From 8b42688bd471dd1ed4a24fd1296105bf0588d180 Mon Sep 17 00:00:00 2001 From: Wanjohi <71614375+wanjohiryan@users.noreply.github.com> Date: Sun, 1 Sep 2024 00:34:50 +0300 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20Game=20card?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/nexus/src/image/banner.ts | 4 +- apps/www/src/routes/home/index.tsx | 55 +++++++++++- packages/ui/globals.css | 4 +- packages/ui/src/card.tsx | 107 ++++++++++++++++++++++++ packages/ui/src/home-nav-bar.tsx | 28 +------ packages/ui/src/index.ts | 3 +- packages/ui/src/react/title-section.tsx | 6 +- 7 files changed, 174 insertions(+), 33 deletions(-) create mode 100644 packages/ui/src/card.tsx diff --git a/apps/nexus/src/image/banner.ts b/apps/nexus/src/image/banner.ts index 73fa0bfe..45391ca0 100644 --- a/apps/nexus/src/image/banner.ts +++ b/apps/nexus/src/image/banner.ts @@ -42,9 +42,9 @@ app.notFound((c) => c.json({ message: 'Not Found', ok: false }, 404)) app.get('/:id', middleware, async (c) => { const [gameId, imageType] = c.req.param("id").split('.'); - const width = parseInt(c.req.query("width") || "600"); + const width = parseInt(c.req.query("width") || "460"); //We don't even use this, but let us keep it for future use - const height = parseInt(c.req.query("height") || "900"); + const height = parseInt(c.req.query("height") || "215"); if (!gameId || !imageType) { return c.text("Invalid image parameters", 400) } diff --git a/apps/www/src/routes/home/index.tsx b/apps/www/src/routes/home/index.tsx index 7e5b6722..46a0ae1d 100644 --- a/apps/www/src/routes/home/index.tsx +++ b/apps/www/src/routes/home/index.tsx @@ -1,10 +1,63 @@ import { component$ } from "@builder.io/qwik"; -import { HomeNavBar } from "@nestri/ui"; +import { GameCard, HomeNavBar, Card } from "@nestri/ui"; + +function getGreeting(): string { + const hour = new Date().getHours(); + if (hour < 12) return "Good Morning"; + if (hour < 18) return "Good Afternoon"; + return "Good Evening"; +} export default component$(() => { return ( <> +
+
+

{getGreeting()}, Wanjohi

+

What will you play today?

+
+
+
+
+ {/* */} +
+
+ +
+
) }) \ No newline at end of file diff --git a/packages/ui/globals.css b/packages/ui/globals.css index b844f5ed..fa108bc9 100644 --- a/packages/ui/globals.css +++ b/packages/ui/globals.css @@ -22,12 +22,12 @@ } html.dark *::selection { - background-color: theme("colors.primary.900"); + background-color: theme("colors.primary.800"); color: theme("colors.primary.500"); } html.dark *::-moz-selection { - background-color: theme("colors.primary.900"); + background-color: theme("colors.primary.800"); color: theme("colors.primary.500"); } diff --git a/packages/ui/src/card.tsx b/packages/ui/src/card.tsx new file mode 100644 index 00000000..f2e67a39 --- /dev/null +++ b/packages/ui/src/card.tsx @@ -0,0 +1,107 @@ +import { component$, useSignal, useVisibleTask$, $ } from "@builder.io/qwik"; + +type Props = { + game: { + name: string; + id: number; + } +} + +export const Card = component$(({ game }: Props) => { + const imageUrl = `http://localhost:8787/image/cover/${game.id}.avif` + const backgroundColor = useSignal(undefined); + const ringColor = useSignal(undefined); + const imgRef = useSignal(); + + // Function to extract dominant color + const extractColor = $((img: HTMLImageElement) => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + canvas.width = img.naturalWidth; + canvas.height = img.naturalHeight; + ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight); + + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const data = imageData.data; + + let r = 0, g = 0, b = 0; + + for (let i = 0; i < data.length; i += 4) { + r += data[i]; + g += data[i + 1]; + b += data[i + 2]; + } + + r = Math.floor(r / (data.length / 4)); + g = Math.floor(g / (data.length / 4)); + b = Math.floor(b / (data.length / 4)); + + return `rgb(${r},${g},${b})`; + }); + + // Function to darken a color + const darkenColor = $((color: string | undefined, amount: number) => { + if (!color) return color; + + const rgb = color.match(/\d+/g); + if (!rgb || rgb.length !== 3) return color; + + const darkenChannel = (channel: number) => Math.max(0, channel - amount); + const r = darkenChannel(parseInt(rgb[0])); + const g = darkenChannel(parseInt(rgb[1])); + const b = darkenChannel(parseInt(rgb[2])); + + return `rgb(${r},${g},${b})`; + }); + + useVisibleTask$(async ({ track }) => { + track(() => imgRef.value); + + const img = imgRef.value; + if (img) { + if (img.complete) { + const extractedColor = await extractColor(img); + backgroundColor.value = extractedColor; + ringColor.value = await darkenColor(extractedColor, 30); + } else { + await new Promise((resolve) => { + img.onload = async () => { + const extractedColor = await extractColor(img); + backgroundColor.value = extractedColor; + ringColor.value = await darkenColor(extractedColor, 30); + resolve(); + }; + }); + } + } + }); + + return ( +
+
+
+

{game.name}

+
+
+
+ {game.name} +
+
+ ) +}); \ No newline at end of file diff --git a/packages/ui/src/home-nav-bar.tsx b/packages/ui/src/home-nav-bar.tsx index b2554600..11578ba6 100644 --- a/packages/ui/src/home-nav-bar.tsx +++ b/packages/ui/src/home-nav-bar.tsx @@ -1,24 +1,7 @@ import { $, component$, useOnDocument, useSignal } from "@builder.io/qwik"; -import { Link, useLocation } from "@builder.io/qwik-city"; -import { buttonVariants, cn } from "@/design"; - -const navLinks = [ - { - name: "Changelog", - href: "/changelog" - }, - { - name: "Pricing", - href: "/pricing" - }, - { - name: "Login", - href: "/login" - } -] +import { cn } from "@/design"; export const HomeNavBar = component$(() => { - const location = useLocation() const hasScrolled = useSignal(false); useOnDocument( @@ -29,7 +12,7 @@ export const HomeNavBar = component$(() => { ); return ( -