diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..b242572e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "githubPullRequests.ignoredPullRequestBranches": [ + "main" + ] +} \ No newline at end of file diff --git a/linkinbio/.gitignore b/linkinbio/.gitignore new file mode 100644 index 00000000..e0c3f1ef --- /dev/null +++ b/linkinbio/.gitignore @@ -0,0 +1,6 @@ +*.db +*.py[cod] +.env +.web +__pycache__/ +assets/external/ diff --git a/linkinbio/README.md b/linkinbio/README.md new file mode 100644 index 00000000..1d5d52f3 --- /dev/null +++ b/linkinbio/README.md @@ -0,0 +1,90 @@ +# Link in Bio App +This application is built using Reflex.dev, a powerful framework for creating interactive web applications using pure Python. This app allows you to showcase your online presence with a customizable link in bio page. + +## Features + +- **Customizable Links**: Easily add links to your personal website, Twitter, GitHub, LinkedIn, and more. +- **Responsive Design**: The app is designed to look great on both desktop and mobile devices. +- **Stylish UI**: Uses a vibrant gradient background and modern UI components. + +## Installation + +To get started with this project follow these steps: + +### Prerequisites + +- Python 3.7 or higher +- pip (Python package manager) + +### Steps + +1. **Clone the Repository** + + Clone the repository to your local machine using the following command: + + ```bash + git clone https://github.com/reflex-dev/reflex-examples + cd reflex-examples/linkinbio + ``` +2. **Install Dependencies** + + Install the required Python packages using pip: + + ```bash + pip install -r requirements.txt + ``` + + The `requirements.txt` file specifies the necessary Reflex version: + ```plaintext:linkinbio/requirements.txt + startLine: 1 + endLine: 2 + ``` + + + +3. **Run the Application** + + Start the application using the following command: + ```bash + reflex run + ``` + + The app will be accessible at `http://localhost:3000` by default. + +## Project Structure + +- **linkinbio.py**: Contains the main application logic, including the `link_button` and `index` functions. + ```python:linkinbio/linkinbio/linkinbio.py + startLine: 1 + endLine: 57 + ``` + +- **style.py**: Defines the styling for the app components, including buttons, links, and layout. + ```python:linkinbio/linkinbio/style.py + startLine: 1 + endLine: 55 + ``` + +- **rxconfig.py**: Configuration file for the Reflex app. + ```python:linkinbio/rxconfig.py + startLine: 1 + endLine: 5 + ``` + +- **.gitignore**: Specifies files and directories to be ignored by Git. + ```plaintext:linkinbio/.gitignore + startLine: 1 + endLine: 6 + ``` + +## Customization + +You can customize the links and personal information by editing the `index` function in `linkinbio.py`. Update the `name`, `bio`, `avatar_url`, and `links` list to reflect your personal details. + +## Contributing + +Contributions are welcome! Please fork the repository and submit a pull request for any improvements or bug fixes. + +## Contact + +This template was created by @erinmikailstaples (https://github.com/erinmikailstaples). Feel free to reach out for any quesitons, feedback, or collaboration opportunities. \ No newline at end of file diff --git a/linkinbio/assets/favicon.ico b/linkinbio/assets/favicon.ico new file mode 100644 index 00000000..166ae995 Binary files /dev/null and b/linkinbio/assets/favicon.ico differ diff --git a/linkinbio/linkinbio/__init__.py b/linkinbio/linkinbio/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/linkinbio/linkinbio/linkinbio.py b/linkinbio/linkinbio/linkinbio.py new file mode 100644 index 00000000..3bc37bec --- /dev/null +++ b/linkinbio/linkinbio/linkinbio.py @@ -0,0 +1,202 @@ +import reflex as rx +from linkinbio.style import * + +# add launchdarkly imports +import ldclient +from ldclient.config import Config +from ldclient import Context, LDClient +import os + +# Initialize LD client (this should be done once, typically at app startup) +SDK_KEY: str | None = os.getenv("LD_SDK_KEY", None) + +LD_CLIENT: LDClient | None = None +LD_CONTEXT: Context | None = None +if SDK_KEY is not None: + ldclient.set_config(Config(SDK_KEY)) + LD_CLIENT = ldclient.get() + +COUNTER = 0 + +class State(rx.State): + + # Create a LaunchDarkly context (formerly known as "user") + ld_context_set: bool = False + updating: bool = False + + def build_ld_context( + self, + context_key: str = "context-key-abc-123", + context_name: str = "linkinbio-app", + ) -> None: + global LD_CONTEXT + if LD_CLIENT is None: + return + + LD_CONTEXT = ( + Context.builder( + context_key, + ) + .name( + context_name, + ) + .build() + ) + self.ld_context_set = True + + @rx.var + def get_feature_flag_bool( + self, + feature_flag_key: str = "toggle-bio", + ) -> bool: + global COUNTER + if not self.ld_context_set: + return False + + flag_value: bool = LD_CLIENT.variation( + key=feature_flag_key, + context=LD_CONTEXT, + default=False, + ) + COUNTER += 1 + return flag_value + + def on_update(self, date: str,): + print(f"{COUNTER} :: {date}") + + +def link_button( + name: str, + url: str, + icon: str, +) -> rx.Component: + icon_map = { + "globe": "globe", + "twitter": "twitter", + "github": "github", + "linkedin": "linkedin", + } + icon_tag = icon_map.get( + icon.lower(), + "link", + ) + return rx.link( + rx.button( + rx.icon( + tag=icon_tag, + ), + name, + width="100%", + ), + href=url, + is_external=True, + ) + + +def index_content( + name: str, + pronouns: str, + bio: str, + avatar_url: str, + links: list[dict[str, str]], + background: str, +): + return rx.center( + rx.vstack( + rx.avatar( + src=avatar_url, + size="2xl", + ), + rx.heading( + name, + size="lg", + ), + rx.text( + pronouns, + font_size="sm", + ), + rx.text(bio), + rx.vstack( + rx.foreach( + links, + lambda link: link_button(link["name"], link["url"], link["icon"]), + ), + width="100%", + spacing="2", + ), + padding="4", + max_width="400px", + width="100%", + spacing="3", + ), + width="100%", + height="100vh", + background=background, + ) + + +def index() -> rx.Component: + return rx.fragment( + rx.cond( + State.get_feature_flag_bool, + index_content( + name="Bio Page if True", + pronouns="dub.link/pronouns", + bio="insert bio here", + avatar_url="https://avatars.githubusercontent.com/", + links=[ + {"name": "Website", "url": "https://www.google.com"}, + {"name": "Upcoming Events", "url": "lu.ma/launchdarkly"}, + {"name": "Instagram", "url": "https://instagram.com/qtotherescue"}, + { + "name": "Another Link here", + "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", + }, + ], + background="linear-gradient(45deg, #FFD700, #FF8C00, #FF4500)", + ), + index_content( + name="Bio Page if False", + pronouns="dub.link/pronouns", + bio="< insert bio here >", + avatar_url="https://avatars.githubusercontent.com/", + links=[ + { + "name": "Website", + "url": "https://reflex.dev", + "icon": "globe", + }, + { + "name": "Twitter", + "url": "https://twitter.com/getreflex", + "icon": "twitter", + }, + { + "name": "GitHub", + "url": "https://github.com/reflex-dev/reflex-examples", + "icon": "github", + }, + { + "name": "LinkedIn", + "url": "https://www.linkedin.com/company/reflex-dev", + "icon": "linkedin", + }, + ], + background="radial-gradient(circle, var(--chakra-colors-purple-100), var(--chakra-colors-blue-100))", + ), + ), + rx.moment( + interval=3000, + on_change=State.on_update, + format="HH:mm:ss", + ), + ) + + +app = rx.App( + style=style, +) +app.add_page( + index, + on_load=State.build_ld_context, +) diff --git a/linkinbio/linkinbio/style.py b/linkinbio/linkinbio/style.py new file mode 100644 index 00000000..a5870201 --- /dev/null +++ b/linkinbio/linkinbio/style.py @@ -0,0 +1,56 @@ +import reflex as rx + +# Define a vibrant gradient background +background_gradient = "linear-gradient(45deg, #FF6B6B, #4ECDC4, #45B7D1, #7E57C2)" + +style = { + "font_family": "Inter, sans-serif", + "background": background_gradient, + "min_height": "100vh", # Ensure the gradient covers the full height of the viewport + rx.avatar: { + "border": "4px solid white", + "box_shadow": "lg", + "margin_top": "0.25em", + }, + rx.button: { + "width": "100%", + "height": "3em", + "padding": "0.5em 1em", + "border_radius": "full", + "color": "white", + "background_color": "rgba(0, 0, 0, 0.5)", # Semi-transparent black + "backdrop_filter": "blur(10px)", + "white_space": "nowrap", + "box_shadow": "0 4px 6px rgba(0, 0, 0, 0.1)", + "transition": "all 0.3s ease", + "_hover": { + "transform": "translateY(-2px)", + "box_shadow": "0 6px 8px rgba(0, 0, 0, 0.15)", + "background_color": "rgba(0, 0, 0, 0.7)", # Darker on hover + }, + }, + rx.link: { + "text_decoration": "none", + "_hover": { + "text_decoration": "none", + }, + }, + rx.vstack: { + "background": "rgba(255, 255, 255, 0.9)", + "backdrop_filter": "blur(20px)", + "border_radius": "20px", + "padding": "1em", + "box_shadow": "0 4px 16px rgba(0, 0, 0, 0.1)", + "color": "black", + "align_items": "center", + "text_align": "center", + }, + rx.heading: { + "color": "black", + "margin_bottom": "0.25em", + }, + rx.text: { + "color": "black", + "margin_bottom": "0.5em", + }, +} diff --git a/linkinbio/requirements.txt b/linkinbio/requirements.txt new file mode 100644 index 00000000..c0e28231 --- /dev/null +++ b/linkinbio/requirements.txt @@ -0,0 +1,2 @@ +reflex==0.6.2.post1 +launchdarkly-server-sdk==9.8.0 diff --git a/linkinbio/rxconfig.py b/linkinbio/rxconfig.py new file mode 100644 index 00000000..c6446910 --- /dev/null +++ b/linkinbio/rxconfig.py @@ -0,0 +1,5 @@ +import reflex as rx + +config = rx.Config( + app_name="linkinbio", +) \ No newline at end of file