Polish brand presentation
|
|
@ -37,7 +37,7 @@ Username: guest · Password: guest123
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
Screenshots below were refreshed from the linked demo server.
|
Screenshots below were refreshed from the current product build.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { ListFilter, RefreshCw, ShieldCheck, Sparkles, type LucideIcon } from 'lucide-react';
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
|
@ -11,6 +12,14 @@ import { RELEASE_NOTES } from '@/lib/version';
|
||||||
import { BrandGlyph } from '@/components/brand/Brand';
|
import { BrandGlyph } from '@/components/brand/Brand';
|
||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { api } from '@/api';
|
import { api } from '@/api';
|
||||||
|
import type { ReleaseHighlightIcon } from '@/lib/version';
|
||||||
|
|
||||||
|
const releaseIcon: Record<ReleaseHighlightIcon, LucideIcon> = {
|
||||||
|
sparkles: Sparkles,
|
||||||
|
filter: ListFilter,
|
||||||
|
sync: RefreshCw,
|
||||||
|
shield: ShieldCheck,
|
||||||
|
};
|
||||||
|
|
||||||
export function ReleaseNotesDialog() {
|
export function ReleaseNotesDialog() {
|
||||||
const { hasNewVersion, setHasNewVersion } = useAuth();
|
const { hasNewVersion, setHasNewVersion } = useAuth();
|
||||||
|
|
@ -55,17 +64,25 @@ export function ReleaseNotesDialog() {
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="mt-2 space-y-3" role="list" aria-label="Release highlights">
|
<div className="mt-2 space-y-3" role="list" aria-label="Release highlights">
|
||||||
{RELEASE_NOTES.highlights.map((item, i) => (
|
{RELEASE_NOTES.highlights.map((item) => {
|
||||||
<div key={i} className="flex gap-3 items-start" role="listitem">
|
const Icon = releaseIcon[item.icon];
|
||||||
<span className="text-lg leading-none mt-0.5" aria-hidden="true">
|
return (
|
||||||
{item.icon}
|
<div key={item.title} className="flex gap-3 items-start" role="listitem">
|
||||||
|
<span
|
||||||
|
className="mt-0.5 grid h-8 w-8 shrink-0 place-items-center rounded-lg border border-primary/20 bg-primary/10 text-primary"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<Icon className="h-4 w-4" />
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-foreground">{item.title}</p>
|
<p className="text-sm font-medium text-foreground">{item.title}</p>
|
||||||
<p className="text-xs text-muted-foreground mt-0.5 leading-relaxed">{item.desc}</p>
|
<p className="text-xs text-muted-foreground mt-0.5 leading-relaxed">
|
||||||
|
{item.desc}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{RELEASE_NOTES.image && (
|
{RELEASE_NOTES.image && (
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ export function MetricCard({
|
||||||
</div>
|
</div>
|
||||||
{action}
|
{action}
|
||||||
</div>
|
</div>
|
||||||
<p className="metric-value mt-4 text-2xl leading-none sm:text-[1.72rem]">{value}</p>
|
<div className="metric-value mt-4 text-2xl leading-none sm:text-[1.72rem]">{value}</div>
|
||||||
{hint && <p className="mt-2 text-xs leading-5 text-muted-foreground">{hint}</p>}
|
{hint && <p className="mt-2 text-xs leading-5 text-muted-foreground">{hint}</p>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,9 @@
|
||||||
--color-sidebar-border: oklch(var(--sidebar-border));
|
--color-sidebar-border: oklch(var(--sidebar-border));
|
||||||
--color-sidebar-ring: oklch(var(--sidebar-ring));
|
--color-sidebar-ring: oklch(var(--sidebar-ring));
|
||||||
|
|
||||||
--font-sans: var(--font-sans), ui-sans-serif, system-ui, sans-serif;
|
--font-sans:
|
||||||
|
Inter, Roboto, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||||||
|
sans-serif;
|
||||||
--font-serif: var(--font-serif), ui-serif, serif;
|
--font-serif: var(--font-serif), ui-serif, serif;
|
||||||
--font-mono: var(--font-mono), ui-monospace, SFMono-Regular, monospace;
|
--font-mono: var(--font-mono), ui-monospace, SFMono-Regular, monospace;
|
||||||
|
|
||||||
|
|
@ -277,7 +279,7 @@
|
||||||
font-family: 'GeorgiaDigits';
|
font-family: 'GeorgiaDigits';
|
||||||
src: local('Georgia');
|
src: local('Georgia');
|
||||||
unicode-range:
|
unicode-range:
|
||||||
U+0030- U+0039,
|
U+0030-0039,
|
||||||
/* 0–9 */ U+002C,
|
/* 0–9 */ U+002C,
|
||||||
/* , thousands separator */ U+002E,
|
/* , thousands separator */ U+002E,
|
||||||
/* . decimal point */ U+002D,
|
/* . decimal point */ U+002D,
|
||||||
|
|
@ -327,11 +329,11 @@
|
||||||
--sidebar-accent-foreground: 0.205 0.02 190;
|
--sidebar-accent-foreground: 0.205 0.02 190;
|
||||||
--sidebar-border: 0.875 0.01 235;
|
--sidebar-border: 0.875 0.01 235;
|
||||||
--sidebar-ring: 0.64 0.15 154;
|
--sidebar-ring: 0.64 0.15 154;
|
||||||
--font-sans: 'GeorgiaDigits', Inter, Roboto, ui-sans-serif, system-ui, sans-serif;
|
--font-sans:
|
||||||
|
Inter, Roboto, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||||||
|
sans-serif;
|
||||||
--font-serif: Merriweather, ui-serif, serif;
|
--font-serif: Merriweather, ui-serif, serif;
|
||||||
--font-mono:
|
--font-mono: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||||||
'GeorgiaDigits', 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
|
|
||||||
monospace;
|
|
||||||
--radius: 1rem;
|
--radius: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@ declare const __APP_VERSION__: string;
|
||||||
|
|
||||||
export const APP_VERSION = __APP_VERSION__;
|
export const APP_VERSION = __APP_VERSION__;
|
||||||
|
|
||||||
|
export type ReleaseHighlightIcon = 'sparkles' | 'filter' | 'sync' | 'shield';
|
||||||
|
|
||||||
export interface ReleaseHighlight {
|
export interface ReleaseHighlight {
|
||||||
icon: string;
|
icon: ReleaseHighlightIcon;
|
||||||
title: string;
|
title: string;
|
||||||
desc: string;
|
desc: string;
|
||||||
}
|
}
|
||||||
|
|
@ -19,42 +21,27 @@ export interface ReleaseNotes {
|
||||||
|
|
||||||
export const RELEASE_NOTES: ReleaseNotes = {
|
export const RELEASE_NOTES: ReleaseNotes = {
|
||||||
version: APP_VERSION,
|
version: APP_VERSION,
|
||||||
date: '2026-05-31',
|
date: '2026-07-10',
|
||||||
highlights: [
|
highlights: [
|
||||||
{
|
{
|
||||||
icon: '🚀',
|
icon: 'sparkles',
|
||||||
title: 'v0.35.0',
|
title: 'Product brand refresh',
|
||||||
desc: 'Version bump and container rebuild.',
|
desc: 'Updated the app identity surfaces, README artwork, favicon family, and preview imagery so Bill Tracker presents like one coherent product.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: '🧠',
|
icon: 'filter',
|
||||||
title: 'Advisory non-bill transaction filters',
|
title: 'Smarter transaction triage',
|
||||||
desc: '5,000+ advisory patterns with 83 bill-like override terms. High-confidence unmatched transactions show "Probably not a bill" instead of "Create Bill". Medium confidence mutes the button. Lazy in-memory cache, seeded on first startup.',
|
desc: 'Unmatched bank activity now gets advisory filtering, with bill-like overrides and gentler calls to action for transactions that probably are not bills.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: '🔄',
|
icon: 'sync',
|
||||||
title: 'SimpleFIN transaction table fix',
|
title: 'Steadier SimpleFIN workflows',
|
||||||
desc: "Transaction table now uses fixed column sizing so long text can't push action buttons off-screen. Action buttons are compact icon-only with accessible labels.",
|
desc: 'Transaction tables hold their shape, action buttons stay reachable, and subscription bills can backfill missing payment history from matched bank activity.',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: '🔄',
|
icon: 'shield',
|
||||||
title: 'SimpleFIN payment backfill',
|
title: 'Safer history and privacy details',
|
||||||
desc: 'Subscription bills with merchant rules now have a Sync Payments button in the edit modal. It scans unmatched SimpleFIN transactions and auto-creates payment records for missing history.',
|
desc: 'Destructive actions use clearer confirmation and undo paths, while profile login details remain visible only to the signed-in user.',
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: '🛡️',
|
|
||||||
title: 'Safer financial history',
|
|
||||||
desc: 'Bill, category, and payment deletes now use confirmations, recovery windows, and undo actions so accidental clicks do not immediately destroy important records.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: '🔐',
|
|
||||||
title: 'Security checks tightened',
|
|
||||||
desc: 'Logout-all now uses the normal CSRF header, password length rules match the backend, and CSRF SPA documentation now matches the actual cookie/header flow.',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: '🔑',
|
|
||||||
title: 'Private login details',
|
|
||||||
desc: 'Your Profile now shows recent login date, IP, browser, OS, device type, and a short device ID. These details are shown only to you in the app UI.',
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
image: {
|
image: {
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 221 KiB |
|
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 235 KiB |
|
Before Width: | Height: | Size: 180 KiB After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 308 KiB After Width: | Height: | Size: 294 KiB |
|
Before Width: | Height: | Size: 237 KiB After Width: | Height: | Size: 259 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 310 KiB |
|
Before Width: | Height: | Size: 238 KiB After Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 256 KiB After Width: | Height: | Size: 221 KiB |
BIN
img/Calendar.png
|
Before Width: | Height: | Size: 202 KiB After Width: | Height: | Size: 235 KiB |
BIN
img/tracker.png
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 262 KiB |