Compare commits
2 Commits
redesign/a
...
v0.3.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa60acb164 | ||
|
|
660b6d57d8 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "laude",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.2",
|
||||
"description": "Exercise reminder — Windows desktop app",
|
||||
"main": "out/main/index.js",
|
||||
"author": "AnRil",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<title>Exercise Reminder</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&family=Geist+Mono:wght@400;500;600&family=Instrument+Serif:ital@0;1&display=swap" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Fraunces:opsz,wght@9..144,400;9..144,500;9..144,600;9..144,700&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -142,15 +142,15 @@ function ExerciseReminder({
|
||||
<div className="text-[12px] uppercase tracking-[0.18em] text-text/45 font-medium">
|
||||
Время тренировки
|
||||
</div>
|
||||
<h1 className="font-serif text-[32px] leading-tight tracking-tight mt-2 mb-3">
|
||||
<h1 className="font-serif text-[28px] leading-tight tracking-tight mt-2 mb-3 font-medium">
|
||||
{exercise.name}
|
||||
</h1>
|
||||
|
||||
<div className="inline-flex items-baseline gap-2 font-mono-num">
|
||||
<span className="text-[64px] font-semibold tracking-tight text-text leading-none">
|
||||
<span className="text-[56px] font-semibold tracking-tight text-text leading-none">
|
||||
{exercise.reps}
|
||||
</span>
|
||||
<span className="text-[15px] text-text/55">раз</span>
|
||||
<span className="text-[14px] text-text/55">раз</span>
|
||||
</div>
|
||||
|
||||
<div className="text-[12px] text-text/45 mt-4 inline-flex items-center gap-1.5">
|
||||
@@ -238,7 +238,7 @@ function MatchSummaryView({
|
||||
<Gamepad2 size={26} strokeWidth={2} />
|
||||
)}
|
||||
</motion.div>
|
||||
<h1 className="font-serif text-[22px] tracking-tight">
|
||||
<h1 className="font-serif text-[24px] tracking-tight font-medium">
|
||||
{won ? 'Победа' : lost ? 'Поражение' : 'Матч завершён'}
|
||||
</h1>
|
||||
<p className="text-[12px] text-text/45 mt-1">
|
||||
|
||||
@@ -1,38 +1,37 @@
|
||||
import { NavLink } from 'react-router-dom'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import {
|
||||
LayoutDashboard,
|
||||
ListChecks,
|
||||
Gamepad2,
|
||||
Target,
|
||||
Settings as SettingsIcon,
|
||||
Sun,
|
||||
Dumbbell,
|
||||
Joystick,
|
||||
Flame,
|
||||
Settings2,
|
||||
X
|
||||
} from 'lucide-react'
|
||||
|
||||
type Item = {
|
||||
to: string
|
||||
label: string
|
||||
icon: typeof LayoutDashboard
|
||||
icon: typeof Sun
|
||||
end?: boolean
|
||||
tint?: string
|
||||
}
|
||||
|
||||
// Each item gets a tinted icon-square reminiscent of iOS Settings rows.
|
||||
// Tinted icon plaques á la iOS Settings rows.
|
||||
const items: Item[] = [
|
||||
{ to: '/', label: 'Сегодня', icon: Sun, end: true, tint: 'bg-accent' },
|
||||
{
|
||||
to: '/',
|
||||
label: 'Сегодня',
|
||||
icon: LayoutDashboard,
|
||||
end: true,
|
||||
tint: 'bg-accent'
|
||||
to: '/exercises',
|
||||
label: 'Упражнения',
|
||||
icon: Dumbbell,
|
||||
tint: 'bg-info'
|
||||
},
|
||||
{ to: '/exercises', label: 'Упражнения', icon: ListChecks, tint: 'bg-info' },
|
||||
{ to: '/games', label: 'Игры', icon: Gamepad2, tint: 'bg-accent-2' },
|
||||
{ to: '/challenges', label: 'Челленджи', icon: Target, tint: 'bg-warning' },
|
||||
{ to: '/games', label: 'Игры', icon: Joystick, tint: 'bg-accent-2' },
|
||||
{ to: '/challenges', label: 'Челленджи', icon: Flame, tint: 'bg-warning' },
|
||||
{
|
||||
to: '/settings',
|
||||
label: 'Настройки',
|
||||
icon: SettingsIcon,
|
||||
icon: Settings2,
|
||||
tint: 'bg-text/70'
|
||||
}
|
||||
]
|
||||
@@ -98,16 +97,16 @@ function SidebarContent({ onNav }: { onNav?: () => void }): JSX.Element {
|
||||
<>
|
||||
{/* Brand */}
|
||||
<div className="px-5 pt-7 pb-6">
|
||||
<div className="font-serif text-[28px] leading-none tracking-tight">
|
||||
<div className="font-serif text-[34px] leading-none tracking-tight font-medium">
|
||||
Laude
|
||||
</div>
|
||||
<div className="text-[12px] text-text/45 mt-1.5">
|
||||
Move with intention
|
||||
<div className="text-[12px] text-text/45 mt-2 tracking-tight">
|
||||
Двигайся осознанно
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Nav */}
|
||||
<nav className="px-2.5 flex flex-col gap-0.5">
|
||||
<nav className="px-2.5 flex flex-col gap-1">
|
||||
{items.map(({ to, label, icon: Icon, end, tint }) => (
|
||||
<NavLink
|
||||
key={to}
|
||||
@@ -127,15 +126,15 @@ function SidebarContent({ onNav }: { onNav?: () => void }): JSX.Element {
|
||||
<>
|
||||
<div
|
||||
className={[
|
||||
'w-7 h-7 rounded-lg grid place-items-center text-white shrink-0',
|
||||
'w-8 h-8 rounded-[9px] grid place-items-center text-white shrink-0',
|
||||
tint ?? 'bg-text/70'
|
||||
].join(' ')}
|
||||
>
|
||||
<Icon size={15} strokeWidth={2.4} />
|
||||
<Icon size={17} strokeWidth={2.2} />
|
||||
</div>
|
||||
<span
|
||||
className={[
|
||||
'text-[14px] truncate',
|
||||
'text-[15px] truncate',
|
||||
isActive
|
||||
? 'text-text font-semibold'
|
||||
: 'text-text/85 font-medium'
|
||||
|
||||
@@ -51,7 +51,7 @@ export default function ChallengesPage(): JSX.Element {
|
||||
<div className="text-[13px] text-text/45 font-medium">
|
||||
Правила за матч
|
||||
</div>
|
||||
<h1 className="font-serif text-[40px] sm:text-[44px] leading-[1.05] tracking-tight mt-1">
|
||||
<h1 className="font-serif text-[32px] sm:text-[36px] leading-[1.05] tracking-tight mt-1 font-medium">
|
||||
Челленджи
|
||||
</h1>
|
||||
<p className="text-[14px] text-text/55 mt-2">
|
||||
|
||||
@@ -72,7 +72,7 @@ export default function Dashboard(): JSX.Element {
|
||||
<div className="text-[13px] text-text/45 font-medium capitalize">
|
||||
{today}
|
||||
</div>
|
||||
<h1 className="font-serif text-[40px] sm:text-[44px] leading-[1.05] tracking-tight mt-1">
|
||||
<h1 className="font-serif text-[32px] sm:text-[36px] leading-[1.05] tracking-tight mt-1 font-medium">
|
||||
Сегодня
|
||||
</h1>
|
||||
</div>
|
||||
@@ -233,7 +233,7 @@ function HeroStat({
|
||||
</div>
|
||||
<div className="text-[12px] text-text/55 font-medium">{label}</div>
|
||||
</div>
|
||||
<div className="font-display text-[30px] font-semibold tracking-tight leading-none">
|
||||
<div className="font-display text-[26px] font-semibold tracking-tight leading-none">
|
||||
{value}
|
||||
</div>
|
||||
{subvalue && (
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function Exercises(): JSX.Element {
|
||||
<div className="text-[13px] text-text/45 font-medium">
|
||||
Программа
|
||||
</div>
|
||||
<h1 className="font-serif text-[40px] sm:text-[44px] leading-[1.05] tracking-tight mt-1">
|
||||
<h1 className="font-serif text-[32px] sm:text-[36px] leading-[1.05] tracking-tight mt-1 font-medium">
|
||||
Упражнения
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -64,7 +64,7 @@ export default function GamesPage(): JSX.Element {
|
||||
<div className="text-[13px] text-text/45 font-medium">
|
||||
Трекинг матчей
|
||||
</div>
|
||||
<h1 className="font-serif text-[40px] sm:text-[44px] leading-[1.05] tracking-tight mt-1">
|
||||
<h1 className="font-serif text-[32px] sm:text-[36px] leading-[1.05] tracking-tight mt-1 font-medium">
|
||||
Игры
|
||||
</h1>
|
||||
<p className="text-[14px] text-text/55 mt-2">
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function SettingsPage(): JSX.Element {
|
||||
<div className="text-[13px] text-text/45 font-medium">
|
||||
Конфигурация
|
||||
</div>
|
||||
<h1 className="font-serif text-[40px] sm:text-[44px] leading-[1.05] tracking-tight mt-1">
|
||||
<h1 className="font-serif text-[32px] sm:text-[36px] leading-[1.05] tracking-tight mt-1 font-medium">
|
||||
Настройки
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -2,34 +2,33 @@
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
/* ===== Design tokens — Apple Human Interface Guidelines ===== */
|
||||
/* ===== Design tokens — Apple HIG with Manrope/Fraunces ===== */
|
||||
|
||||
:root {
|
||||
/* Brand & semantic colors (iOS system palette) */
|
||||
--accent: 255 107 53; /* Apple Fitness Move orange */
|
||||
--accent-2: 255 45 85; /* systemPink */
|
||||
--success: 52 199 89; /* systemGreen */
|
||||
--warning: 255 159 10; /* systemOrange-dark */
|
||||
--warning: 255 159 10; /* systemOrange dark */
|
||||
--destructive: 255 59 48; /* systemRed */
|
||||
--info: 0 122 255; /* systemBlue */
|
||||
|
||||
color-scheme: light dark;
|
||||
}
|
||||
|
||||
/* Light — iOS groupedBackground feel */
|
||||
/* Light — polished iOS groupedBackground with warm undertone */
|
||||
:root {
|
||||
--bg: 242 242 247; /* systemGroupedBackground */
|
||||
--surface: 255 255 255; /* secondarySystemGroupedBackground (cards) */
|
||||
--surface-2: 242 242 247; /* tertiarySystemGroupedBackground */
|
||||
--text: 0 0 0;
|
||||
--text-secondary: 60 60 67; /* used with opacity 0.6 */
|
||||
--text-tertiary: 60 60 67; /* used with opacity 0.3 */
|
||||
--hairline: 60 60 67; /* used with opacity 0.18 */
|
||||
--vibrancy: 255 255 255; /* sidebar translucent base */
|
||||
--bg: 245 245 249; /* slightly warmer than 242,242,247 */
|
||||
--surface: 255 255 255;
|
||||
--surface-2: 240 240 245; /* subtle separation for inputs/sections */
|
||||
--text: 17 17 19; /* not pure black — softer */
|
||||
--text-secondary: 60 60 67;
|
||||
--text-tertiary: 60 60 67;
|
||||
--hairline: 60 60 67;
|
||||
--vibrancy: 255 255 255;
|
||||
|
||||
/* Legacy tokens (mapped to keep some old utility classes working) */
|
||||
--accent-soft: 255 107 53;
|
||||
--bg-deep: 230 230 235;
|
||||
--bg-deep: 232 232 238;
|
||||
--surface-elevated: 255 255 255;
|
||||
--border: 60 60 67;
|
||||
--muted: 60 60 67;
|
||||
@@ -38,11 +37,11 @@
|
||||
--xp: 255 159 10;
|
||||
}
|
||||
|
||||
/* Dark — iOS true black for OLED, elevation via grey steps */
|
||||
/* Dark — true black with grey elevation */
|
||||
.dark {
|
||||
--bg: 0 0 0; /* systemBackground */
|
||||
--surface: 28 28 30; /* secondarySystemBackground */
|
||||
--surface-2: 44 44 46; /* tertiarySystemBackground */
|
||||
--bg: 0 0 0;
|
||||
--surface: 28 28 30;
|
||||
--surface-2: 44 44 46;
|
||||
--text: 255 255 255;
|
||||
--text-secondary: 235 235 245;
|
||||
--text-tertiary: 235 235 245;
|
||||
@@ -68,24 +67,26 @@ body,
|
||||
|
||||
body {
|
||||
font-family:
|
||||
'Geist',
|
||||
'Manrope',
|
||||
-apple-system,
|
||||
'SF Pro Text',
|
||||
'Segoe UI Variable Text',
|
||||
'Segoe UI',
|
||||
system-ui,
|
||||
sans-serif;
|
||||
font-feature-settings: 'cv11', 'ss01', 'ss03'; /* Geist stylistic alts */
|
||||
background-color: rgb(var(--bg));
|
||||
color: rgb(var(--text));
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
letter-spacing: -0.01em;
|
||||
font-size: 14px;
|
||||
line-height: 1.45;
|
||||
letter-spacing: -0.005em;
|
||||
}
|
||||
|
||||
/* Display — same Manrope but slightly tighter for headings */
|
||||
.font-display {
|
||||
font-family:
|
||||
'Geist',
|
||||
'Manrope',
|
||||
-apple-system,
|
||||
'SF Pro Display',
|
||||
'Segoe UI Variable Display',
|
||||
@@ -94,17 +95,20 @@ body {
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
/* Serif — Fraunces for hero titles with optical-size axis */
|
||||
.font-serif {
|
||||
font-family: 'Instrument Serif', 'Iowan Old Style', 'Apple Garamond', Georgia,
|
||||
serif;
|
||||
letter-spacing: -0.01em;
|
||||
font-family: 'Fraunces', 'Iowan Old Style', 'New York', Georgia, serif;
|
||||
font-optical-sizing: auto;
|
||||
font-variation-settings: 'opsz' 144;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.font-mono-num {
|
||||
font-family: 'Geist Mono', ui-monospace, 'SF Mono', 'Cascadia Code', Menlo,
|
||||
monospace;
|
||||
font-family: 'JetBrains Mono', ui-monospace, 'SF Mono', 'Cascadia Code',
|
||||
Menlo, monospace;
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-feature-settings: 'ss02';
|
||||
font-feature-settings: 'ss02', 'ss19', 'zero';
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
/* Custom titlebar drag region */
|
||||
@@ -117,7 +121,7 @@ body {
|
||||
app-region: no-drag;
|
||||
}
|
||||
|
||||
/* Thin iOS-style hairline (effectively 0.5px when device DPR allows) */
|
||||
/* iOS 0.5px-style hairlines */
|
||||
.hairline-b {
|
||||
box-shadow: inset 0 -0.5px 0 rgb(var(--hairline) / 0.18);
|
||||
}
|
||||
@@ -129,19 +133,19 @@ body {
|
||||
box-shadow: inset 0 -0.5px 0 rgb(var(--hairline) / 0.4);
|
||||
}
|
||||
|
||||
/* Vibrancy panel (macOS Big Sur+ sidebar feel) */
|
||||
/* macOS vibrancy */
|
||||
.vibrancy {
|
||||
background-color: rgb(var(--vibrancy) / 0.72);
|
||||
backdrop-filter: saturate(180%) blur(30px);
|
||||
-webkit-backdrop-filter: saturate(180%) blur(30px);
|
||||
}
|
||||
|
||||
/* iOS-style soft card shadow */
|
||||
/* Soft iOS card shadow with subtle warmth */
|
||||
.shadow-card {
|
||||
box-shadow:
|
||||
0 0.5px 0 rgb(0 0 0 / 0.03),
|
||||
0 1px 2px rgb(0 0 0 / 0.04),
|
||||
0 4px 12px rgb(0 0 0 / 0.04);
|
||||
0 1px 2px rgb(15 23 42 / 0.04),
|
||||
0 6px 14px -4px rgb(15 23 42 / 0.05);
|
||||
}
|
||||
.dark .shadow-card {
|
||||
box-shadow:
|
||||
@@ -149,7 +153,7 @@ body {
|
||||
0 1px 2px rgb(0 0 0 / 0.4);
|
||||
}
|
||||
|
||||
/* Scrollbar — thin, iOS-style */
|
||||
/* Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
@@ -165,18 +169,15 @@ body {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Selection */
|
||||
::selection {
|
||||
background: rgb(var(--accent) / 0.25);
|
||||
}
|
||||
|
||||
/* iOS focus ring */
|
||||
*:focus-visible {
|
||||
outline: 2px solid rgb(var(--accent) / 0.55);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Reminder window root — iOS sheet */
|
||||
.reminder-shell {
|
||||
position: relative;
|
||||
border: 0.5px solid rgb(var(--hairline) / 0.25);
|
||||
@@ -189,7 +190,6 @@ body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Text helpers (semantic aliases) */
|
||||
.text-secondary {
|
||||
color: rgb(var(--text-secondary) / 0.6);
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ export const DEFAULT_SETTINGS: Settings = {
|
||||
startWithWindows: false,
|
||||
minimizeToTray: true,
|
||||
startMinimized: false,
|
||||
theme: 'system',
|
||||
theme: 'light',
|
||||
snoozeMinutes: 5
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ export default {
|
||||
},
|
||||
fontFamily: {
|
||||
sans: [
|
||||
'Geist',
|
||||
'Manrope',
|
||||
'-apple-system',
|
||||
'SF Pro Text',
|
||||
'Segoe UI Variable Text',
|
||||
@@ -43,7 +43,7 @@ export default {
|
||||
'sans-serif'
|
||||
],
|
||||
display: [
|
||||
'Geist',
|
||||
'Manrope',
|
||||
'-apple-system',
|
||||
'SF Pro Display',
|
||||
'Segoe UI Variable Display',
|
||||
@@ -51,14 +51,14 @@ export default {
|
||||
'sans-serif'
|
||||
],
|
||||
serif: [
|
||||
'Instrument Serif',
|
||||
'Fraunces',
|
||||
'Iowan Old Style',
|
||||
'Apple Garamond',
|
||||
'New York',
|
||||
'Georgia',
|
||||
'serif'
|
||||
],
|
||||
mono: [
|
||||
'Geist Mono',
|
||||
'JetBrains Mono',
|
||||
'ui-monospace',
|
||||
'SF Mono',
|
||||
'Cascadia Code',
|
||||
|
||||
Reference in New Issue
Block a user