-
Notifications
You must be signed in to change notification settings - Fork 18
feat: add new font options (mono, elegant, minimal, retro) - closes #4 #35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
809596e
bbdd1c0
5997bc8
3e3c4df
73a3a52
1290eeb
8829a35
4cf3f96
9568f58
bc2260b
bd07c1a
ff1a43f
52d1ad5
ba8e384
6e4f6c0
caa3aee
f0277ad
064ee94
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,3 +39,6 @@ yarn-error.log* | |
| # typescript | ||
| *.tsbuildinfo | ||
| next-env.d.ts | ||
|
|
||
|
|
||
| -Raw) -replace | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,13 @@ | ||
| 'use client'; | ||
| ο»Ώ'use client'; | ||
|
|
||
| import { useState, useCallback } from 'react'; | ||
| import Link from 'next/link'; | ||
| import { motion } from 'framer-motion'; | ||
| import { themes } from '../../lib/svg/themes'; | ||
| import { FONT_OPTIONS } from '../../lib/svg/generator'; | ||
| const FONT_KEYS = Object.keys(FONT_OPTIONS); | ||
|
|
||
| // βββ Types ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | ||
| // Γ’ββ¬Γ’ββ¬Γ’ββ¬ Types Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬ | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what do you mean by this line ? |
||
|
|
||
| type Scale = 'linear' | 'log'; | ||
|
|
||
|
|
@@ -19,13 +21,13 @@ const SPEEDS = [ | |
| { value: '20s', label: 'Ultra-slow (20s)' }, | ||
| ] as const; | ||
|
|
||
| // βββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | ||
| // Γ’ββ¬Γ’ββ¬Γ’ββ¬ Helpers Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬ | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what do you mean by this line ? |
||
|
|
||
| function stripHash(val: string) { | ||
| return val.replace(/^#/, ''); | ||
| } | ||
|
|
||
| // βββ Sub-components βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | ||
| // Γ’ββ¬Γ’ββ¬Γ’ββ¬ Sub-components Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬ | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what do you mean by this line ? |
||
|
|
||
| function SectionLabel({ children }: { children: React.ReactNode }) { | ||
| return ( | ||
|
|
@@ -89,7 +91,7 @@ function HexInput({ | |
| <div className="flex flex-col gap-1.5"> | ||
| <SectionLabel>{label}</SectionLabel> | ||
| <div className="relative flex items-center gap-2"> | ||
| {/* ββ Color picker trigger ββ */} | ||
| {/* Γ’ββ¬Γ’ββ¬ Color picker trigger Γ’ββ¬Γ’ββ¬ */} | ||
| <label | ||
| htmlFor={`${id}-picker`} | ||
| title="Open color picker" | ||
|
|
@@ -116,7 +118,7 @@ function HexInput({ | |
| /> | ||
| </label> | ||
|
|
||
| {/* ββ Text input ββ */} | ||
| {/* Γ’ββ¬Γ’ββ¬ Text input Γ’ββ¬Γ’ββ¬ */} | ||
| <div className="relative flex-1 flex items-center"> | ||
| <span className="absolute left-3 text-white/30 text-sm select-none pointer-events-none"> | ||
| # | ||
|
|
@@ -136,7 +138,7 @@ function HexInput({ | |
| ); | ||
| } | ||
|
|
||
| // βββ Main Page ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | ||
| // Γ’ββ¬Γ’ββ¬Γ’ββ¬ Main Page Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬ | ||
|
|
||
| export default function CustomizePage() { | ||
| const [username, setUsername] = useState('jhasourav07'); | ||
|
|
@@ -146,9 +148,10 @@ export default function CustomizePage() { | |
| const [textHex, setTextHex] = useState(''); | ||
| const [scale, setScale] = useState<Scale>('linear'); | ||
| const [speed, setSpeed] = useState('8s'); | ||
| const [font, setFont] = useState('default'); | ||
| const [copied, setCopied] = useState(false); | ||
|
|
||
| // ββ buildQueryParams ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | ||
| // Γ’ββ¬Γ’ββ¬ buildQueryParams Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬ | ||
|
|
||
| const buildQueryParams = useCallback(() => { | ||
| const params = new URLSearchParams(); | ||
|
|
@@ -167,9 +170,10 @@ export default function CustomizePage() { | |
|
|
||
| if (scale !== 'linear') params.set('scale', scale); | ||
| if (speed !== '8s') params.set('speed', speed); | ||
| if (font !== 'default') params.set('font', font); | ||
|
|
||
| return params.toString(); | ||
| }, [username, theme, bgHex, accentHex, textHex, scale, speed]); | ||
| }, [username, theme, bgHex, accentHex, textHex, scale, speed, font]); | ||
|
|
||
| const queryString = buildQueryParams(); | ||
| const previewSrc = `/api/streak?${queryString}`; | ||
|
|
@@ -191,7 +195,7 @@ export default function CustomizePage() { | |
| </div> | ||
|
|
||
| <div className="relative z-10 max-w-[1400px] mx-auto px-6 py-8"> | ||
| {/* ββ Top Bar βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */} | ||
| {/* Γ’ββ¬Γ’ββ¬ Top Bar Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬ */} | ||
| <motion.div | ||
| initial={{ opacity: 0, y: -10 }} | ||
| animate={{ opacity: 1, y: 0 }} | ||
|
|
@@ -228,7 +232,7 @@ export default function CustomizePage() { | |
| </div> | ||
| </motion.div> | ||
|
|
||
| {/* ββ Page heading βββββββββββββββββββββββββββββββββββββββββββββββββββ */} | ||
| {/* Γ’ββ¬Γ’ββ¬ Page heading Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬ */} | ||
| <motion.div | ||
| initial={{ opacity: 0, y: 16 }} | ||
| animate={{ opacity: 1, y: 0 }} | ||
|
|
@@ -240,13 +244,13 @@ export default function CustomizePage() { | |
| </h1> | ||
| <p className="text-gray-500 text-sm max-w-xl"> | ||
| Every change below updates the preview in real-time. Copy the Markdown snippet when | ||
| you're done β no extra steps required. | ||
| you're done Γ’β¬β no extra steps required. | ||
| </p> | ||
| </motion.div> | ||
|
|
||
| {/* ββ Split layout βββββββββββββββββββββββββββββββββββββββββββββββββββ */} | ||
| {/* Γ’ββ¬Γ’ββ¬ Split layout Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬Γ’ββ¬ */} | ||
| <div className="grid lg:grid-cols-[380px_1fr] gap-6 items-start"> | ||
| {/* ββββ LEFT: Control Panel ββββββββββββββββββββββββββββββββββββββββ */} | ||
| {/* Γ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’Β LEFT: Control Panel Γ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’Β */} | ||
| <motion.aside | ||
| initial={{ opacity: 0, x: -20 }} | ||
| animate={{ opacity: 1, x: 0 }} | ||
|
|
@@ -284,7 +288,7 @@ export default function CustomizePage() { | |
| </option> | ||
| ))} | ||
| </StyledSelect> | ||
| {/* Theme color swatches β driven from the imported themes object */} | ||
| {/* Theme color swatches Γ’β¬β driven from the imported themes object */} | ||
| <div className="mt-2 flex gap-1.5"> | ||
| {(['bg', 'accent', 'text'] as const).map((prop) => { | ||
| const color = themes[theme]?.[prop]; | ||
|
|
@@ -298,7 +302,7 @@ export default function CustomizePage() { | |
| ) : null; | ||
| })} | ||
| <span className="text-[11px] text-white/25 ml-1 self-center"> | ||
| bg Β· accent Β· text | ||
| bg ΓΒ· accent ΓΒ· text | ||
| </span> | ||
| </div> | ||
| </div> | ||
|
|
@@ -347,7 +351,7 @@ export default function CustomizePage() { | |
| }} | ||
| className="mt-3 text-[11px] text-red-400/60 hover:text-red-400 transition-colors" | ||
| > | ||
| β Clear overrides | ||
| Γ’Εβ’ Clear overrides | ||
| </button> | ||
| )} | ||
| </div> | ||
|
|
@@ -375,10 +379,25 @@ export default function CustomizePage() { | |
| </div> | ||
| <p className="text-[11px] text-white/25 mt-1.5 leading-relaxed"> | ||
| {scale === 'log' | ||
| ? 'Log mode compresses extreme outliers β great for power committers.' | ||
| ? 'Log mode compresses extreme outliers Γ’β¬β great for power committers.' | ||
| : 'Linear mode shows raw commit counts as tower heights.'} | ||
| </p> | ||
| </ControlRow> | ||
| {/* Font Style */} | ||
| <ControlRow label="Font Style"> | ||
| <div className="relative"> | ||
| <StyledSelect id="font-select" value={font} onChange={setFont}> | ||
| {FONT_KEYS.map((k) => ( | ||
| <option key={k} value={k}> | ||
| {FONT_OPTIONS[k].title} | ||
| </option> | ||
| ))} | ||
| </StyledSelect> | ||
| </div> | ||
| </ControlRow> | ||
|
|
||
| {/* Divider */} | ||
| <div className="h-px bg-white/5" /> | ||
|
|
||
| {/* Scan speed */} | ||
| <ControlRow label="Radar Scan Speed"> | ||
|
|
@@ -396,7 +415,7 @@ export default function CustomizePage() { | |
| </div> | ||
| </motion.aside> | ||
|
|
||
| {/* ββββ RIGHT: Preview + Export ββββββββββββββββββββββββββββββββββββ */} | ||
| {/* Γ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’Β RIGHT: Preview + Export Γ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’ΒΓ’β’Β */} | ||
| <motion.div | ||
| initial={{ opacity: 0, x: 20 }} | ||
| animate={{ opacity: 1, x: 0 }} | ||
|
|
@@ -430,7 +449,7 @@ export default function CustomizePage() { | |
| </div> | ||
|
|
||
| <p className="mt-3 text-[11px] text-white/20 text-center"> | ||
| Preview updates on every change Β· Hosted badge is cached at UTC midnight | ||
| Preview updates on every change ΓΒ· Hosted badge is cached at UTC midnight | ||
| </p> | ||
| </div> | ||
|
|
||
|
|
@@ -496,8 +515,8 @@ export default function CustomizePage() { | |
|
|
||
| <p className="mt-4 text-[11px] text-white/20 leading-relaxed"> | ||
| Paste this into your GitHub profile's{' '} | ||
| <code className="text-white/35">README.md</code> β the badge renders server-side, no | ||
| script required. | ||
| <code className="text-white/35">README.md</code> Γ’β¬β the badge renders server-side, | ||
| no script required. | ||
| </p> | ||
| </div> | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the point to edit this file ?