diff --git a/frontend/README.md b/frontend/README.md index e6cd94f..a45e2a0 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -42,6 +42,6 @@ If you have state that's important to retain within a component, consider creati ```ts // store.ts // An extremely simple external store -import { writable } from 'svelte/store' -export default writable(0) +import { writable } from "svelte/store"; +export default writable(0); ``` diff --git a/frontend/index.html b/frontend/index.html index 18611f1..eda6b2d 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,10 +4,15 @@ - + RythonDev — Media Kit - +
diff --git a/frontend/public/images/logos/instagram.svg b/frontend/public/images/logos/instagram.svg new file mode 100644 index 0000000..8f7c8c7 --- /dev/null +++ b/frontend/public/images/logos/instagram.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/public/images/logos/tiktok.svg b/frontend/public/images/logos/tiktok.svg new file mode 100644 index 0000000..6e142b5 --- /dev/null +++ b/frontend/public/images/logos/tiktok.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/public/images/logos/tiktok.webp b/frontend/public/images/logos/tiktok.webp new file mode 100644 index 0000000..b63df84 Binary files /dev/null and b/frontend/public/images/logos/tiktok.webp differ diff --git a/frontend/public/images/logos/twitch.svg b/frontend/public/images/logos/twitch.svg new file mode 100644 index 0000000..a2b6304 --- /dev/null +++ b/frontend/public/images/logos/twitch.svg @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/frontend/public/images/logos/youtube.svg b/frontend/public/images/logos/youtube.svg new file mode 100644 index 0000000..c7e566f --- /dev/null +++ b/frontend/public/images/logos/youtube.svg @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/frontend/src/app.css b/frontend/src/app.css index b188655..20bb472 100644 --- a/frontend/src/app.css +++ b/frontend/src/app.css @@ -1,38 +1,39 @@ @import "tailwindcss"; @font-face { - font-family: "Fredoka"; - src: url("/fonts/Fredoka-Regular.ttf") format("truetype"); - font-weight: normal; - font-style: normal; - font-display: swap; + font-family: "Fredoka"; + src: url("/fonts/Fredoka-Regular.ttf") format("truetype"); + font-weight: normal; + font-style: normal; + font-display: swap; } @font-face { - font-family: "Antonio"; - src: url("/fonts/Antonio-Bold.ttf") format("truetype"); - font-weight: bold; - font-style: normal; - font-display: swap; + font-family: "Antonio"; + src: url("/fonts/Antonio-Bold.ttf") format("truetype"); + font-weight: bold; + font-style: normal; + font-display: swap; } /* Montserrat Fonts */ @font-face { - font-family: "Montserrat"; - src: url("/fonts/Montserrat-Bold.ttf") format("truetype"); - font-weight: bold; - font-style: normal; - font-display: swap; + font-family: "Montserrat"; + src: url("/fonts/Montserrat-Bold.ttf") format("truetype"); + font-weight: bold; + font-style: normal; + font-display: swap; } @font-face { - font-family: "Montserrat"; - src: url("/fonts/Montserrat-Regular.ttf") format("truetype"); - font-weight: normal; - font-style: normal; - font-display: swap; + font-family: "Montserrat"; + src: url("/fonts/Montserrat-Regular.ttf") format("truetype"); + font-weight: normal; + font-style: normal; + font-display: swap; } -html, body { - font-family: Montserrat; +html, +body { + font-family: Montserrat; } diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 317e8da..474207c 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -1,78 +1,85 @@ -import type { AdminState, MediaKit, Platform } from './types' +import type { AdminState, MediaKit, Platform } from "./types"; -const TOKEN_KEY = 'rythondev_admin_token' +const TOKEN_KEY = "rythondev_admin_token"; function authHeaders(): Record { - const token = localStorage.getItem(TOKEN_KEY) - return token ? { Authorization: `Basic ${token}` } : {} + const token = localStorage.getItem(TOKEN_KEY); + return token ? { Authorization: `Basic ${token}` } : {}; } export function getStoredToken(): string | null { - return localStorage.getItem(TOKEN_KEY) + return localStorage.getItem(TOKEN_KEY); } export function clearStoredToken(): void { - localStorage.removeItem(TOKEN_KEY) + localStorage.removeItem(TOKEN_KEY); } export async function fetchMediaKit(): Promise { - const res = await fetch('/api/media-kit') - if (!res.ok) throw new Error('Failed to load media kit') - return res.json() + const res = await fetch("/api/media-kit"); + if (!res.ok) throw new Error("Failed to load media kit"); + return res.json(); } -export async function verifyAdmin(username: string, password: string): Promise { - const token = btoa(`${username}:${password}`) - const res = await fetch('/api/admin/verify', { +export async function verifyAdmin( + username: string, + password: string, +): Promise { + const token = btoa(`${username}:${password}`); + const res = await fetch("/api/admin/verify", { headers: { Authorization: `Basic ${token}` }, - }) + }); - if (!res.ok) return false + if (!res.ok) return false; - localStorage.setItem(TOKEN_KEY, token) - return true + localStorage.setItem(TOKEN_KEY, token); + return true; } export async function fetchAdminState(): Promise { - const res = await fetch('/api/admin/state', { headers: authHeaders() }) + const res = await fetch("/api/admin/state", { headers: authHeaders() }); if (res.status === 401) { - clearStoredToken() - throw new Error('unauthorized') + clearStoredToken(); + throw new Error("unauthorized"); } - if (!res.ok) throw new Error('Failed to load admin state') - return res.json() + if (!res.ok) throw new Error("Failed to load admin state"); + return res.json(); } -export async function updateContent(content: Record): Promise> { - const res = await fetch('/api/admin/content', { - method: 'PUT', - headers: { 'Content-Type': 'application/json', ...authHeaders() }, +export async function updateContent( + content: Record, +): Promise> { + const res = await fetch("/api/admin/content", { + method: "PUT", + headers: { "Content-Type": "application/json", ...authHeaders() }, body: JSON.stringify(content), - }) + }); if (res.status === 401) { - clearStoredToken() - throw new Error('unauthorized') + clearStoredToken(); + throw new Error("unauthorized"); } - if (!res.ok) throw new Error('Failed to save content') + if (!res.ok) throw new Error("Failed to save content"); - const data = await res.json() - return data.content + const data = await res.json(); + return data.content; } -export async function updatePlatforms(platforms: Platform[]): Promise { - const res = await fetch('/api/admin/platforms', { - method: 'PUT', - headers: { 'Content-Type': 'application/json', ...authHeaders() }, +export async function updatePlatforms( + platforms: Platform[], +): Promise { + const res = await fetch("/api/admin/platforms", { + method: "PUT", + headers: { "Content-Type": "application/json", ...authHeaders() }, body: JSON.stringify(platforms), - }) + }); if (res.status === 401) { - clearStoredToken() - throw new Error('unauthorized') + clearStoredToken(); + throw new Error("unauthorized"); } - if (!res.ok) throw new Error('Failed to save platforms') + if (!res.ok) throw new Error("Failed to save platforms"); - const data = await res.json() - return data.platforms + const data = await res.json(); + return data.platforms; } diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts index 4a451e8..8137711 100644 --- a/frontend/src/lib/types.ts +++ b/frontend/src/lib/types.ts @@ -1,32 +1,32 @@ export interface Platform { - name: string - handle: string - url: string - followers: number + name: string; + handle: string; + url: string; + followers: number; } export interface TwitchData { - configured?: boolean - found?: boolean - login?: string - display_name?: string - profile_image_url?: string - followers?: number - live?: boolean - title?: string - game_name?: string - viewer_count?: number - updated_at?: number - message?: string + configured?: boolean; + found?: boolean; + login?: string; + display_name?: string; + profile_image_url?: string; + followers?: number; + live?: boolean; + title?: string; + game_name?: string; + viewer_count?: number; + updated_at?: number; + message?: string; } export interface MediaKit { - content: Record - platforms: Platform[] - twitch: TwitchData | null + content: Record; + platforms: Platform[]; + twitch: TwitchData | null; } export interface AdminState { - content: Record - platforms: Platform[] + content: Record; + platforms: Platform[]; } diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 664a057..d47b930 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -1,9 +1,9 @@ -import { mount } from 'svelte' -import './app.css' -import App from './App.svelte' +import { mount } from "svelte"; +import "./app.css"; +import App from "./App.svelte"; const app = mount(App, { - target: document.getElementById('app')!, -}) + target: document.getElementById("app")!, +}); -export default app +export default app; diff --git a/frontend/src/routes/MediaKit.svelte b/frontend/src/routes/MediaKit.svelte index 76f40c3..3e7dc83 100644 --- a/frontend/src/routes/MediaKit.svelte +++ b/frontend/src/routes/MediaKit.svelte @@ -1,117 +1,159 @@ {#if error} -
-
- {error} -
-
-{:else if !data} -
-
Loading…
-
-{:else} -
-
- {#if content.profile_image_url} - {content.brand_name - {/if} -
-

- {content.brand_name ?? 'RythonDev'} -

- {#if content.tagline} -

{content.tagline}

- {/if} -
-
- -
-

About

-

- {content.about ?? ''} -

- {#if content.email} - {content.email} +
- {/if} -
- -
-

Twitch

- {#if twitch?.configured && twitch?.found} -
-
- Followers - {formatCount(twitch?.followers)} -
+ {error}
- {:else} -

{twitch?.message ?? 'Twitch stats are unavailable.'}

- {/if} -
- -
-

Platforms

- -
-
+ +{:else if !data} +
+
Loading…
+
+{:else} +
+ +
+
+
+ Hi there, I'm
+ RythonDev +
+
+
+
{/if} + + diff --git a/frontend/src/routes/MediaKit_copy.svelte b/frontend/src/routes/MediaKit_copy.svelte new file mode 100644 index 0000000..488e77c --- /dev/null +++ b/frontend/src/routes/MediaKit_copy.svelte @@ -0,0 +1,117 @@ + + +{#if error} +
+
+ {error} +
+
+{:else if !data} +
+
Loading…
+
+{:else} +
+
+ {#if content.profile_image_url} + {content.brand_name + {/if} +
+

+ {content.brand_name ?? 'RythonDev'} +

+ {#if content.tagline} +

{content.tagline}

+ {/if} +
+
+ +
+

About

+

+ {content.about ?? ''} +

+ {#if content.email} + {content.email} + {/if} +
+ +
+

Twitch

+ {#if twitch?.configured && twitch?.found} +
+
+ Followers + {formatCount(twitch?.followers)} +
+
+ {:else} +

{twitch?.message ?? 'Twitch stats are unavailable.'}

+ {/if} +
+ +
+

Platforms

+ +
+
+{/if} diff --git a/frontend/svelte.config.js b/frontend/svelte.config.js index 0cf7db3..ed45953 100644 --- a/frontend/svelte.config.js +++ b/frontend/svelte.config.js @@ -1,2 +1,2 @@ /** @type {import("@sveltejs/vite-plugin-svelte").SvelteConfig} */ -export default {} +export default {}; diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 73a4303..f4a35bb 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,16 +1,16 @@ -import { svelte } from '@sveltejs/vite-plugin-svelte' -import tailwindcss from '@tailwindcss/vite' -import { defineConfig } from 'vite' +import { svelte } from "@sveltejs/vite-plugin-svelte"; +import tailwindcss from "@tailwindcss/vite"; +import { defineConfig } from "vite"; // https://vite.dev/config/ export default defineConfig({ plugins: [tailwindcss(), svelte()], server: { proxy: { - '/api': { - target: 'http://localhost:3000', + "/api": { + target: "http://localhost:3000", changeOrigin: true, }, }, }, -}) +});