From 27747baca360284b8650d6149155b003e66a37d5 Mon Sep 17 00:00:00 2001 From: Brais Moure Date: Thu, 8 Feb 2024 21:56:14 +0100 Subject: [PATCH] Supabase API --- README.md | 2 +- link_bio/README.md | 2 +- link_bio/assets/css/styles.css | 7 +++++ link_bio/link_bio/api/SupabaseAPI.py | 25 ++++++++++++++++++ link_bio/link_bio/api/TwitchAPI.py | 7 +++-- link_bio/link_bio/api/api.py | 8 +++++- link_bio/link_bio/components/link_button.py | 6 ++--- link_bio/link_bio/pages/index.py | 7 ++--- link_bio/link_bio/state/PageState.py | 11 ++++++-- link_bio/link_bio/styles/styles.py | 3 ++- link_bio/link_bio/views/courses_links.py | 6 ++--- link_bio/link_bio/views/header.py | 28 ++++++++++++++++---- link_bio/link_bio/views/index_links.py | 29 ++++++++++++++++++--- link_bio/requirements.txt | 5 ++-- 14 files changed, 117 insertions(+), 29 deletions(-) create mode 100644 link_bio/assets/css/styles.css create mode 100644 link_bio/link_bio/api/SupabaseAPI.py diff --git a/README.md b/README.md index f14f0139..0d8ff1ad 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Python Web [![Python](https://img.shields.io/badge/Python-3.11+-yellow?style=for-the-badge&logo=python&logoColor=white&labelColor=101010)](https://python.org) -[![Reflex](https://img.shields.io/badge/Reflex-0.3.9+-5646ED?style=for-the-badge&logo=reflex&logoColor=white&labelColor=101010)](https://reflex.dev) +[![Reflex](https://img.shields.io/badge/Reflex-0.3.10+-5646ED?style=for-the-badge&logo=reflex&logoColor=white&labelColor=101010)](https://reflex.dev) ## Curso de 6 horas en vídeo para aprender desarrollo web frontend con Python puro y Reflex desde cero. diff --git a/link_bio/README.md b/link_bio/README.md index 4383dc72..db3c5c07 100644 --- a/link_bio/README.md +++ b/link_bio/README.md @@ -1,7 +1,7 @@ # Web de links de MoureDev [![Python](https://img.shields.io/badge/Python-3.11+-yellow?style=for-the-badge&logo=python&logoColor=white&labelColor=101010)](https://python.org) -[![FastAPI](https://img.shields.io/badge/Reflex-0.3.9+-5646ED?style=for-the-badge&logo=reflex&logoColor=white&labelColor=101010)](https://fastapi.tiangolo.com) +[![FastAPI](https://img.shields.io/badge/Reflex-0.3.10+-5646ED?style=for-the-badge&logo=reflex&logoColor=white&labelColor=101010)](https://fastapi.tiangolo.com) ## Proyecto desarrollado con [Python](https://www.python.org/) y [Reflex](https://reflex.dev/) que representa un sitio web personal estilo "[link in bio](https://moure.dev/)" diff --git a/link_bio/assets/css/styles.css b/link_bio/assets/css/styles.css new file mode 100644 index 00000000..182b6368 --- /dev/null +++ b/link_bio/assets/css/styles.css @@ -0,0 +1,7 @@ +@keyframes blinker { + 50% { opacity: 0; } +} + +.blink { + animation: blinker 1.5s linear infinite; +} \ No newline at end of file diff --git a/link_bio/link_bio/api/SupabaseAPI.py b/link_bio/link_bio/api/SupabaseAPI.py new file mode 100644 index 00000000..030b2433 --- /dev/null +++ b/link_bio/link_bio/api/SupabaseAPI.py @@ -0,0 +1,25 @@ +import os +import dotenv +from supabase import create_client, Client + + +class SupabaseAPI: + + dotenv.load_dotenv() + + SUPABASE_URL = os.environ.get("SUPABASE_URL") + SUPABASE_KEY = os.environ.get("SUPABASE_KEY") + + supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY) + + def featured(self) -> list: + + response = self.supabase.table("featured").select("*").execute() + + featured_data = [] + + if len(response.data) > 0: + for featured_item in response.data: + featured_data.append(featured_item) + + return featured_data diff --git a/link_bio/link_bio/api/TwitchAPI.py b/link_bio/link_bio/api/TwitchAPI.py index 0f4852c3..34722d28 100644 --- a/link_bio/link_bio/api/TwitchAPI.py +++ b/link_bio/link_bio/api/TwitchAPI.py @@ -37,7 +37,7 @@ def generate_token(self): def token_valid(self) -> bool: return time.time() < self.token_exp - def live(self, user: str) -> bool: + def live(self, user: str) -> dict: if not self.token_valid(): self.generate_token() @@ -52,7 +52,6 @@ def live(self, user: str) -> bool: if response.status_code == 200 and response.json()["data"]: data = response.json()["data"] - print(data) - return True + return {"live": True, "title": data[0]["title"]} - return False + return {"live": False, "title": ""} diff --git a/link_bio/link_bio/api/api.py b/link_bio/link_bio/api/api.py index dcef41aa..4dc8dda6 100644 --- a/link_bio/link_bio/api/api.py +++ b/link_bio/link_bio/api/api.py @@ -1,12 +1,18 @@ import link_bio.constants as const from .TwitchAPI import TwitchAPI +from .SupabaseAPI import SupabaseAPI TWITCH_API = TwitchAPI() +SUPABASE_API = SupabaseAPI() async def repo() -> str: return const.REPO_URL -async def live(user: str) -> bool: +async def live(user: str) -> dict: return TWITCH_API.live(user) + + +async def featured() -> list: + return SUPABASE_API.featured() diff --git a/link_bio/link_bio/components/link_button.py b/link_bio/link_bio/components/link_button.py index a2af6f28..e82470d2 100644 --- a/link_bio/link_bio/components/link_button.py +++ b/link_bio/link_bio/components/link_button.py @@ -3,7 +3,7 @@ from link_bio.styles.styles import Size, Color -def link_button(title: str, body: str, image: str, url: str, is_external=True, highlight=False) -> rx.Component: +def link_button(title: str, body: str, image: str, url: str, is_external=True, highlight_color=None) -> rx.Component: return rx.link( rx.button( rx.hstack( @@ -24,8 +24,8 @@ def link_button(title: str, body: str, image: str, url: str, is_external=True, h ), width="100%" ), - border_color=Color.SECONDARY.value if highlight else None, - border_width="2px" if highlight else None + border_color=highlight_color, + border_width="2px" if highlight_color != None else None ), href=url, is_external=is_external, diff --git a/link_bio/link_bio/pages/index.py b/link_bio/link_bio/pages/index.py index 02e73649..81e63bd9 100644 --- a/link_bio/link_bio/pages/index.py +++ b/link_bio/link_bio/pages/index.py @@ -15,7 +15,7 @@ description=utils.index_description, image=utils.preview, meta=utils.index_meta, - on_load=PageState.check_live + on_load=[PageState.check_live, PageState.featured_links] ) def index() -> rx.Component: return rx.box( @@ -24,9 +24,10 @@ def index() -> rx.Component: rx.center( rx.vstack( header( - live=PageState.is_live + live=PageState.is_live, + live_title=PageState.live_title ), - index_links(), + index_links(PageState.featured_info), sponsors(), max_width=styles.MAX_WIDTH, width="100%", diff --git a/link_bio/link_bio/state/PageState.py b/link_bio/link_bio/state/PageState.py index b6381f92..09a808c6 100644 --- a/link_bio/link_bio/state/PageState.py +++ b/link_bio/link_bio/state/PageState.py @@ -1,5 +1,5 @@ import reflex as rx -from link_bio.api.api import live +from link_bio.api.api import live, featured USER = "mouredev" @@ -7,6 +7,13 @@ class PageState(rx.State): is_live: bool + live_title: str + featured_info: list[dict] async def check_live(self): - self.is_live = await live(USER) + live_data = await live(USER) + self.is_live = live_data["live"] + self.live_title = live_data["title"] + + async def featured_links(self): + self.featured_info = await featured() diff --git a/link_bio/link_bio/styles/styles.py b/link_bio/link_bio/styles/styles.py index dc2ae8d3..8c9c0808 100644 --- a/link_bio/link_bio/styles/styles.py +++ b/link_bio/link_bio/styles/styles.py @@ -10,7 +10,8 @@ STYLESHEETS = [ "https://fonts.googleapis.com/css2?family=Poppins:wght@300;500&display=swap", - "https://fonts.googleapis.com/css2?family=Comfortaa:wght@500&display=swap" + "https://fonts.googleapis.com/css2?family=Comfortaa:wght@500&display=swap", + "/css/styles.css" ] diff --git a/link_bio/link_bio/views/courses_links.py b/link_bio/link_bio/views/courses_links.py index 76bec9ac..47822388 100644 --- a/link_bio/link_bio/views/courses_links.py +++ b/link_bio/link_bio/views/courses_links.py @@ -2,7 +2,7 @@ import link_bio.constants as const from link_bio.components.link_button import link_button from link_bio.components.title import title -from link_bio.styles.styles import Size +from link_bio.styles.styles import Size, Color def courses_links() -> rx.Component: @@ -10,10 +10,10 @@ def courses_links() -> rx.Component: title("Cursos gratis"), link_button( "Retos de programación", - "Ruta de estudio semanal para practicar lógica de programación", + "Ruta de estudio semanal para practicar lógica", "/icons/challenges.png", const.CODE_CHALLENGES_URL, - highlight=True + highlight_color=Color.SECONDARY.value ), link_button( "Python desde cero", diff --git a/link_bio/link_bio/views/header.py b/link_bio/link_bio/views/header.py index a6d4454a..a53ce49e 100644 --- a/link_bio/link_bio/views/header.py +++ b/link_bio/link_bio/views/header.py @@ -5,18 +5,26 @@ from link_bio.styles.colors import Color, TextColor from link_bio.components.link_icon import link_icon from link_bio.components.info_text import info_text +from link_bio.components.link_button import link_button -def header(details=True, live=False) -> rx.Component: +def header(details=True, live=False, live_title="") -> rx.Component: return rx.vstack( rx.hstack( rx.avatar( rx.cond( live, - rx.avatar_badge( - box_size=Size.MEDIUM.value, - bg=Color.PURPLE.value, - border_color=Color.PURPLE.value + rx.link( + rx.avatar_badge( + rx.image( + src="/icons/twitch.svg" + ), + bg=Color.PURPLE.value, + border_color=Color.PURPLE.value, + class_name="blink" + ), + href=const.TWITCH_URL, + is_external=True ) ), name="Brais Moure", @@ -93,6 +101,16 @@ def header(details=True, live=False) -> rx.Component: ), width="100%" ), + rx.cond( + live, + link_button( + "En directo", + live_title, + "/icons/twitch.svg", + const.TWITCH_URL, + highlight_color=Color.PURPLE.value + ) + ), rx.text( f""" Soy ingeniero de software y actualmente trabajo como freelance diff --git a/link_bio/link_bio/views/index_links.py b/link_bio/link_bio/views/index_links.py index 0fc8af79..e5758ed7 100644 --- a/link_bio/link_bio/views/index_links.py +++ b/link_bio/link_bio/views/index_links.py @@ -3,10 +3,10 @@ from link_bio.routes import Route from link_bio.components.link_button import link_button from link_bio.components.title import title -from link_bio.styles.styles import Size +from link_bio.styles.styles import Size, Color -def index_links() -> rx.Component: +def index_links(featured=[]) -> rx.Component: return rx.vstack( title("Comunidad"), link_button( @@ -15,7 +15,7 @@ def index_links() -> rx.Component: "/icons/code.svg", Route.COURSES.value, False, - True + Color.SECONDARY.value ), link_button( "Twitch", @@ -42,6 +42,29 @@ def index_links() -> rx.Component: const.YOUTUBE_SECONDARY_URL ), + # rx.cond( + # len(featured) > 0, + # rx.vstack( + # title("Destacado"), + # rx.foreach( + # featured, + # lambda item: rx.responsive_grid( + # rx.text(item) + # rx.link( + # rx.image( + # src=item["image"] + # ), + # rx.text( + # item["title"] + # ), + # href=item["url"], + # is_external=True + # ) + # ) + # ) + # ) + # ), + title("Recursos y más"), link_button( "Git y GitHub desde cero", diff --git a/link_bio/requirements.txt b/link_bio/requirements.txt index 4999da9e..d82923af 100644 --- a/link_bio/requirements.txt +++ b/link_bio/requirements.txt @@ -1,2 +1,3 @@ -reflex==0.3.9 -python-dotenv \ No newline at end of file +reflex==0.3.10 +python-dotenv +supabase \ No newline at end of file