feat: upgrade typography - Plus Jakarta Sans headings, JetBrains Mono data, 14px base

Heading font: Plus Jakarta Sans (500/600/700) for all h1-h3, stat values, dialog titles, timer display, and wordmark.
Body font: Inter (400/500/600/700) unchanged but base bumped from 13px to 14px.
Mono font: JetBrains Mono replaces IBM Plex Mono for code and tabular data.
This commit is contained in:
Your Name
2026-02-17 22:06:48 +02:00
parent 3c8868c899
commit a300d85f6f
10 changed files with 34 additions and 33 deletions

View File

@@ -7,7 +7,7 @@
<title>ZeroClock</title> <title>ZeroClock</title>
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Plus+Jakarta+Sans:wght@500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>

View File

@@ -50,7 +50,7 @@ async function handleDoubleClick() {
<!-- Left: App name --> <!-- Left: App name -->
<div class="flex items-center"> <div class="flex items-center">
<span <span
class="text-accent-text text-[0.6875rem] font-medium tracking-[0.1em] uppercase" class="text-accent-text text-[0.6875rem] font-medium font-[family-name:var(--font-heading)] tracking-[0.1em] uppercase"
> >
ZeroClock ZeroClock
</span> </span>

View File

@@ -30,7 +30,8 @@
/* Fonts */ /* Fonts */
--font-sans: 'Inter', system-ui, sans-serif; --font-sans: 'Inter', system-ui, sans-serif;
--font-mono: 'IBM Plex Mono', monospace; --font-heading: 'Plus Jakarta Sans', 'Inter', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', 'IBM Plex Mono', monospace;
} }
@layer base { @layer base {
@@ -48,7 +49,7 @@
body { body {
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: 0.8125rem; font-size: 0.875rem;
line-height: 1.5; line-height: 1.5;
background-color: var(--color-bg-base); background-color: var(--color-bg-base);
color: var(--color-text-primary); color: var(--color-text-primary);

View File

@@ -14,7 +14,7 @@
<template v-else> <template v-else>
<!-- Greeting header --> <!-- Greeting header -->
<div class="mb-8"> <div class="mb-8">
<p class="text-lg text-text-secondary">{{ greeting }}</p> <p class="text-xl font-[family-name:var(--font-heading)] text-text-secondary">{{ greeting }}</p>
<p class="text-xs text-text-tertiary mt-1">{{ formattedDate }}</p> <p class="text-xs text-text-tertiary mt-1">{{ formattedDate }}</p>
</div> </div>
@@ -22,25 +22,25 @@
<div class="grid grid-cols-4 gap-6 mb-8"> <div class="grid grid-cols-4 gap-6 mb-8">
<div> <div>
<p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">Today</p> <p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">Today</p>
<p class="text-[1.25rem] font-mono text-accent-text font-medium">{{ formatDuration(todayStats.totalSeconds) }}</p> <p class="text-[1.25rem] font-[family-name:var(--font-heading)] text-accent-text font-medium">{{ formatDuration(todayStats.totalSeconds) }}</p>
</div> </div>
<div> <div>
<p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">This Week</p> <p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">This Week</p>
<p class="text-[1.25rem] font-mono text-accent-text font-medium">{{ formatDuration(weekStats.totalSeconds) }}</p> <p class="text-[1.25rem] font-[family-name:var(--font-heading)] text-accent-text font-medium">{{ formatDuration(weekStats.totalSeconds) }}</p>
</div> </div>
<div> <div>
<p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">This Month</p> <p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">This Month</p>
<p class="text-[1.25rem] font-mono text-accent-text font-medium">{{ formatDuration(monthStats.totalSeconds) }}</p> <p class="text-[1.25rem] font-[family-name:var(--font-heading)] text-accent-text font-medium">{{ formatDuration(monthStats.totalSeconds) }}</p>
</div> </div>
<div> <div>
<p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">Active Projects</p> <p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">Active Projects</p>
<p class="text-[1.25rem] font-mono text-accent-text font-medium">{{ activeProjectsCount }}</p> <p class="text-[1.25rem] font-[family-name:var(--font-heading)] text-accent-text font-medium">{{ activeProjectsCount }}</p>
</div> </div>
</div> </div>
<!-- Weekly chart --> <!-- Weekly chart -->
<div class="mb-8"> <div class="mb-8">
<h2 class="text-[1rem] font-medium text-text-primary mb-4">Weekly Hours</h2> <h2 class="text-[1.25rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-4">Weekly Hours</h2>
<div class="h-48"> <div class="h-48">
<Bar v-if="chartData" :data="chartData" :options="chartOptions" /> <Bar v-if="chartData" :data="chartData" :options="chartOptions" />
</div> </div>
@@ -49,7 +49,7 @@
<!-- Recent entries --> <!-- Recent entries -->
<div> <div>
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<h2 class="text-[1rem] font-medium text-text-primary">Recent Entries</h2> <h2 class="text-[1.25rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary">Recent Entries</h2>
<router-link to="/entries" class="text-xs text-text-tertiary hover:text-text-secondary transition-colors">View all</router-link> <router-link to="/entries" class="text-xs text-text-tertiary hover:text-text-secondary transition-colors">View all</router-link>
</div> </div>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="p-6"> <div class="p-6">
<h1 class="text-[1.5rem] font-medium text-text-primary mb-6">Entries</h1> <h1 class="text-[1.75rem] font-bold font-[family-name:var(--font-heading)] tracking-tight text-text-primary mb-6">Entries</h1>
<!-- Filters --> <!-- Filters -->
<div class="bg-bg-surface rounded-lg p-4 mb-6 flex flex-wrap items-end gap-4"> <div class="bg-bg-surface rounded-lg p-4 mb-6 flex flex-wrap items-end gap-4">
@@ -133,7 +133,7 @@
@click.self="closeEditDialog" @click.self="closeEditDialog"
> >
<div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-md mx-4 p-6 animate-modal-enter"> <div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-md mx-4 p-6 animate-modal-enter">
<h2 class="text-[1rem] font-semibold text-text-primary mb-4">Edit Entry</h2> <h2 class="text-[1.125rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-4">Edit Entry</h2>
<form @submit.prevent="handleEdit" class="space-y-4"> <form @submit.prevent="handleEdit" class="space-y-4">
<!-- Project --> <!-- Project -->
@@ -213,7 +213,7 @@
@click.self="cancelDelete" @click.self="cancelDelete"
> >
<div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-sm mx-4 p-6 animate-modal-enter"> <div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-sm mx-4 p-6 animate-modal-enter">
<h2 class="text-[1rem] font-semibold text-text-primary mb-2">Delete Entry</h2> <h2 class="text-[1.125rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-2">Delete Entry</h2>
<p class="text-[0.75rem] text-text-secondary mb-6"> <p class="text-[0.75rem] text-text-secondary mb-6">
Are you sure you want to delete this time entry? This action cannot be undone. Are you sure you want to delete this time entry? This action cannot be undone.
</p> </p>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="p-6"> <div class="p-6">
<h1 class="text-[1.5rem] font-medium text-text-primary mb-6">Invoices</h1> <h1 class="text-[1.75rem] font-bold font-[family-name:var(--font-heading)] tracking-tight text-text-primary mb-6">Invoices</h1>
<!-- View tabs --> <!-- View tabs -->
<div class="flex gap-6 mb-6 border-b border-border-subtle"> <div class="flex gap-6 mb-6 border-b border-border-subtle">
@@ -120,7 +120,7 @@
<!-- Create View --> <!-- Create View -->
<div v-else-if="view === 'create'" class="max-w-lg"> <div v-else-if="view === 'create'" class="max-w-lg">
<h2 class="text-[1rem] font-medium text-text-primary mb-4">Create Invoice</h2> <h2 class="text-[1.25rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-4">Create Invoice</h2>
<form @submit.prevent="handleCreate" class="space-y-4"> <form @submit.prevent="handleCreate" class="space-y-4">
<!-- Client --> <!-- Client -->
@@ -247,7 +247,7 @@
<div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-2xl mx-4 p-6 max-h-[90vh] overflow-y-auto animate-modal-enter"> <div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-2xl mx-4 p-6 max-h-[90vh] overflow-y-auto animate-modal-enter">
<div class="flex items-start justify-between mb-6"> <div class="flex items-start justify-between mb-6">
<div> <div>
<h2 class="text-[1.5rem] font-medium text-text-primary">{{ selectedInvoice?.invoice_number }}</h2> <h2 class="text-[1.75rem] font-bold font-[family-name:var(--font-heading)] tracking-tight text-text-primary">{{ selectedInvoice?.invoice_number }}</h2>
<p class="text-[0.75rem] text-text-secondary">{{ getClientName(selectedInvoice?.client_id || 0) }}</p> <p class="text-[0.75rem] text-text-secondary">{{ getClientName(selectedInvoice?.client_id || 0) }}</p>
</div> </div>
<button <button
@@ -315,7 +315,7 @@
@click.self="showDeleteDialog = false" @click.self="showDeleteDialog = false"
> >
<div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-sm mx-4 p-6 animate-modal-enter"> <div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-sm mx-4 p-6 animate-modal-enter">
<h2 class="text-[1rem] font-semibold text-text-primary mb-2">Delete Invoice</h2> <h2 class="text-[1.125rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-2">Delete Invoice</h2>
<p class="text-[0.75rem] text-text-secondary mb-6"> <p class="text-[0.75rem] text-text-secondary mb-6">
Are you sure you want to delete invoice "{{ invoiceToDelete?.invoice_number }}"? This action cannot be undone. Are you sure you want to delete invoice "{{ invoiceToDelete?.invoice_number }}"? This action cannot be undone.
</p> </p>

View File

@@ -2,7 +2,7 @@
<div class="p-6"> <div class="p-6">
<!-- Header --> <!-- Header -->
<div class="flex items-center justify-between mb-6"> <div class="flex items-center justify-between mb-6">
<h1 class="text-[1.5rem] font-medium text-text-primary">Projects</h1> <h1 class="text-[1.75rem] font-bold font-[family-name:var(--font-heading)] tracking-tight text-text-primary">Projects</h1>
<button <button
@click="openCreateDialog" @click="openCreateDialog"
class="px-3 py-1.5 bg-accent text-bg-base text-xs font-medium rounded-lg hover:bg-accent-hover transition-colors duration-150" class="px-3 py-1.5 bg-accent text-bg-base text-xs font-medium rounded-lg hover:bg-accent-hover transition-colors duration-150"
@@ -72,7 +72,7 @@
@click.self="closeDialog" @click.self="closeDialog"
> >
<div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-md mx-4 p-6 animate-modal-enter"> <div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-md mx-4 p-6 animate-modal-enter">
<h2 class="text-[1rem] font-semibold text-text-primary mb-4"> <h2 class="text-[1.125rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-4">
{{ editingProject ? 'Edit Project' : 'Create Project' }} {{ editingProject ? 'Edit Project' : 'Create Project' }}
</h2> </h2>
@@ -175,7 +175,7 @@
@click.self="cancelDelete" @click.self="cancelDelete"
> >
<div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-sm mx-4 p-6 animate-modal-enter"> <div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-sm mx-4 p-6 animate-modal-enter">
<h2 class="text-[1rem] font-semibold text-text-primary mb-2">Delete Project</h2> <h2 class="text-[1.125rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-2">Delete Project</h2>
<p class="text-[0.75rem] text-text-secondary mb-6"> <p class="text-[0.75rem] text-text-secondary mb-6">
Are you sure you want to delete "{{ projectToDelete?.name }}"? This action cannot be undone. Are you sure you want to delete "{{ projectToDelete?.name }}"? This action cannot be undone.
</p> </p>

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="p-6"> <div class="p-6">
<h1 class="text-[1.5rem] font-medium text-text-primary mb-6">Reports</h1> <h1 class="text-[1.75rem] font-bold font-[family-name:var(--font-heading)] tracking-tight text-text-primary mb-6">Reports</h1>
<!-- Date Range Selector --> <!-- Date Range Selector -->
<div class="bg-bg-surface rounded-lg p-4 mb-6 flex flex-wrap items-end gap-4"> <div class="bg-bg-surface rounded-lg p-4 mb-6 flex flex-wrap items-end gap-4">
@@ -38,21 +38,21 @@
<div class="grid grid-cols-3 gap-6 mb-8"> <div class="grid grid-cols-3 gap-6 mb-8">
<div> <div>
<p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">Total Hours</p> <p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">Total Hours</p>
<p class="text-[1.25rem] font-mono text-accent-text font-medium">{{ formatHours(reportData.totalSeconds) }}</p> <p class="text-[1.25rem] font-[family-name:var(--font-heading)] text-accent-text font-medium">{{ formatHours(reportData.totalSeconds) }}</p>
</div> </div>
<div> <div>
<p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">Earnings</p> <p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">Earnings</p>
<p class="text-[1.25rem] font-mono text-accent-text font-medium">${{ reportData.totalEarnings?.toFixed(2) || '0.00' }}</p> <p class="text-[1.25rem] font-[family-name:var(--font-heading)] text-accent-text font-medium">${{ reportData.totalEarnings?.toFixed(2) || '0.00' }}</p>
</div> </div>
<div> <div>
<p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">Projects</p> <p class="text-[0.6875rem] text-text-tertiary uppercase tracking-[0.08em] mb-1">Projects</p>
<p class="text-[1.25rem] font-mono text-accent-text font-medium">{{ reportData.byProject?.length || 0 }}</p> <p class="text-[1.25rem] font-[family-name:var(--font-heading)] text-accent-text font-medium">{{ reportData.byProject?.length || 0 }}</p>
</div> </div>
</div> </div>
<!-- Chart --> <!-- Chart -->
<div class="mb-8"> <div class="mb-8">
<h2 class="text-[1rem] font-medium text-text-primary mb-4">Hours by Project</h2> <h2 class="text-[1.25rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-4">Hours by Project</h2>
<div class="h-64"> <div class="h-64">
<Bar v-if="chartData" :data="chartData" :options="chartOptions" /> <Bar v-if="chartData" :data="chartData" :options="chartOptions" />
<div v-else class="flex flex-col items-center justify-center h-full"> <div v-else class="flex flex-col items-center justify-center h-full">
@@ -64,7 +64,7 @@
<!-- Project Breakdown --> <!-- Project Breakdown -->
<div> <div>
<h2 class="text-[1rem] font-medium text-text-primary mb-4">Breakdown</h2> <h2 class="text-[1.25rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-4">Breakdown</h2>
<div v-if="reportData.byProject && reportData.byProject.length > 0"> <div v-if="reportData.byProject && reportData.byProject.length > 0">
<div <div

View File

@@ -28,7 +28,7 @@
<div class="flex-1 p-6 overflow-y-auto"> <div class="flex-1 p-6 overflow-y-auto">
<!-- General --> <!-- General -->
<div v-if="activeTab === 'general'"> <div v-if="activeTab === 'general'">
<h2 class="text-[1.125rem] font-medium text-text-primary mb-6">General</h2> <h2 class="text-[1.25rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-6">General</h2>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div>
@@ -57,7 +57,7 @@
<!-- Timer --> <!-- Timer -->
<div v-if="activeTab === 'timer'"> <div v-if="activeTab === 'timer'">
<h2 class="text-[1.125rem] font-medium text-text-primary mb-6">Timer</h2> <h2 class="text-[1.25rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-6">Timer</h2>
<div class="space-y-5"> <div class="space-y-5">
<!-- Idle Detection toggle --> <!-- Idle Detection toggle -->
@@ -105,7 +105,7 @@
<!-- Billing --> <!-- Billing -->
<div v-if="activeTab === 'billing'"> <div v-if="activeTab === 'billing'">
<h2 class="text-[1.125rem] font-medium text-text-primary mb-6">Billing</h2> <h2 class="text-[1.25rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-6">Billing</h2>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div> <div>
@@ -129,7 +129,7 @@
<!-- Data --> <!-- Data -->
<div v-if="activeTab === 'data'"> <div v-if="activeTab === 'data'">
<h2 class="text-[1.125rem] font-medium text-text-primary mb-6">Data</h2> <h2 class="text-[1.25rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-6">Data</h2>
<div class="space-y-6"> <div class="space-y-6">
<!-- Export --> <!-- Export -->
@@ -173,7 +173,7 @@
@click.self="showClearDataDialog = false" @click.self="showClearDataDialog = false"
> >
<div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-sm mx-4 p-6 animate-modal-enter"> <div class="bg-bg-surface border border-border-subtle rounded-lg shadow-[0_1px_3px_rgba(0,0,0,0.3)] w-full max-w-sm mx-4 p-6 animate-modal-enter">
<h2 class="text-[1rem] font-semibold text-text-primary mb-2">Clear All Data</h2> <h2 class="text-[1.125rem] font-semibold font-[family-name:var(--font-heading)] text-text-primary mb-2">Clear All Data</h2>
<p class="text-[0.75rem] text-text-secondary mb-4"> <p class="text-[0.75rem] text-text-secondary mb-4">
Are you sure? This action cannot be undone. Are you sure? This action cannot be undone.
</p> </p>

View File

@@ -2,7 +2,7 @@
<div class="p-6"> <div class="p-6">
<!-- Hero timer display --> <!-- Hero timer display -->
<div class="text-center pt-4 pb-8"> <div class="text-center pt-4 pb-8">
<p class="text-[3rem] font-mono font-medium tracking-wider mb-6"> <p class="text-[3.5rem] font-medium font-[family-name:var(--font-heading)] tracking-tighter mb-6">
<span class="text-text-primary">{{ timerParts.hours }}</span> <span class="text-text-primary">{{ timerParts.hours }}</span>
<span :class="timerStore.isRunning ? 'text-accent-text animate-pulse-colon' : 'text-text-primary'">:</span> <span :class="timerStore.isRunning ? 'text-accent-text animate-pulse-colon' : 'text-text-primary'">:</span>
<span class="text-text-primary">{{ timerParts.minutes }}</span> <span class="text-text-primary">{{ timerParts.minutes }}</span>