Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/geolibre-desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
"@dvt3d/maplibre-three-plugin": "^1.7.1",
"@electric-sql/pglite": "^0.5.4",
"@electric-sql/pglite-postgis": "^0.2.4",
"@fontsource-variable/ibm-plex-sans": "^5.3.0",
"@fontsource/ibm-plex-mono": "^5.3.0",
Comment thread
coderabbitai[bot] marked this conversation as resolved.
"@geolibre/core": "*",
"@geolibre/embed": "*",
"@geolibre/map": "*",
Expand Down
23 changes: 23 additions & 0 deletions apps/geolibre-desktop/src/index.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,32 @@
@import "@geolibre/ui/globals.css";

/* Supplies the custom-color/border-radius theme that @geolibre/ui's globals.css
relies on via @apply (background, border, etc.). globals.css is intentionally
config-agnostic; the consuming app provides the Tailwind config here. */
@config "../tailwind.config.js";

/* App typeface: IBM Plex Sans for UI, IBM Plex Mono for the numeric/coordinate
readouts (StatusBar, code, feature IDs). One matched superfamily, so the mono
readouts and the surrounding UI share a voice. The @font-face rules are
loaded from main.tsx — see the note there for why they cannot be @imported
here. Self-hosted rather than CDN-loaded: the desktop build must render
offline, and the Tauri CSP is `default-src 'self'`.

This block drives both the `font-sans`/`font-mono` utilities and Tailwind's
preflight default, so no `font-family` on <body> is needed.

Plex covers latin, latin-ext, cyrillic, greek and vietnamese only. The
locales it does NOT cover (ar, fa, hi, ja, ka, ko, th, zh) rely on per-glyph
fallback to the system stack below — which is why that stack must stay a
full, ordered list rather than a bare `sans-serif`. */
@theme {
--font-sans:
"IBM Plex Sans Variable", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
"Noto Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
--font-mono:
"IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
}

html,
body,
#root {
Expand Down
10 changes: 10 additions & 0 deletions apps/geolibre-desktop/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import "./lib/symbol-dispose-polyfill";
import React from "react";
import ReactDOM from "react-dom/client";
/* App typeface — see the --font-sans/--font-mono note in index.css.
These must be imported from JS, not via `@import` in index.css: Tailwind v4
resolves CSS @imports itself and inlines them before Vite sees them, so the
relative `url(./files/*.woff2)` in fontsource's CSS is never rewritten into
an asset reference and no font file is emitted into dist/. The result builds
clean and 404s at runtime, silently falling back to system fonts. Importing
from JS routes the CSS through Vite's asset pipeline instead. */
import "@fontsource-variable/ibm-plex-sans/wght.css";
import "@fontsource/ibm-plex-mono/400.css";
import "@fontsource/ibm-plex-mono/700.css";
import "@geoman-io/maplibre-geoman-free/dist/maplibre-geoman.css";
import "@maplibre/maplibre-gl-directions/dist/style.css";
import "maplibre-gl-3d-tiles/style.css";
Expand Down
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions packages/ui/src/components/dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@ export const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 flex max-h-[calc(100dvh-1rem)] w-[calc(100vw-1rem)] max-w-lg translate-x-[-50%] translate-y-[-50%] flex-col overflow-hidden border bg-background shadow-lg duration-200 supports-[not_(max-height:1dvh)]:max-h-[calc(100vh-1rem)] sm:rounded-lg",
"fixed left-[50%] top-[50%] z-50 flex max-h-[calc(100dvh-1rem)] w-[calc(100vw-1rem)] max-w-lg translate-x-[-50%] translate-y-[-50%] flex-col overflow-hidden border bg-popover text-popover-foreground shadow-lg duration-200 supports-[not_(max-height:1dvh)]:max-h-[calc(100vh-1rem)] sm:rounded-lg",
className,
)}
{...props}
>
<div className={cn("grid min-h-0 flex-1 gap-4 overflow-auto", bodyClassName ?? "p-4 sm:p-6")}>
{children}
</div>
<DialogPrimitive.Close className="absolute end-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring">
{/* ring-offset matches the popover surface this sits on, not --background.
Inert today (no ring-offset width utility is applied, so the offset
colour never paints) but wrong the moment one is added. */}
<DialogPrimitive.Close className="absolute end-4 top-4 rounded-sm opacity-70 ring-offset-popover transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
Expand Down
65 changes: 50 additions & 15 deletions packages/ui/src/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,42 +11,70 @@
--popover-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
/* Neutrals sit at ~16% saturation rather than the stock 40%, so the chrome
reads as grey next to the map instead of tinting blue. --accent is one
step darker than --muted so hover fills register on white surfaces. */
--secondary: 220 16% 96%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted: 220 16% 96%;
/* Darkened from 46.9% L so secondary text meets WCAG AA (4.5:1) even on the
muted/secondary backgrounds it is paired with (e.g. kbd badges). */
--muted-foreground: 215.4 16.3% 40%;
--accent: 210 40% 96.1%;
--accent: 220 16% 94%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
/* --border is decorative (dividers, panel edges); --input is a control
boundary, so it is deliberately darker. See the note in .dark below. */
--border: 220 15% 88%;
--input: 220 13% 76%;
Comment thread
giswqs marked this conversation as resolved.
--ring: 221.2 83.2% 53.3%;
--radius: 0.5rem;
}

/* Dark mode is built as an explicit elevation ladder. Previously --background,
--card and --popover were all 222.2 84% 4.9%, and --border, --input,
--muted, --secondary and --accent were all 217.2 32.6% 17.5% — five tokens,
one colour — so panels, dialogs and menus were indistinguishable from the
app canvas and only a 1px border separated them. Each step below is a
distinct surface:

background 9% app canvas / base chrome
card 12% toolbar, docked panels
popover 15% menus, tooltips, dialogs
muted 20% inset fills (status bar, wells)
accent 22% hover fill — must read above popover, since menu items
sit on it

Saturation also drops from 84% to ~22%: the old value was a strongly
blue-tinted near-black that clashed with satellite imagery in the map view.
Every foreground/surface pair here clears WCAG AA 4.5:1 (lowest is
muted-foreground on accent at 4.82:1). */
.dark {
--background: 222.2 84% 4.9%;
--background: 222 24% 9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card: 222 22% 12%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover: 222 21% 15%;
--popover-foreground: 210 40% 98%;
--primary: 217.2 91.2% 59.8%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary: 220 18% 20%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted: 220 18% 20%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent: 220 18% 22%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 224.3 76.3% 48%;
--border: 220 14% 26%;
--input: 220 12% 38%;
/* Matches --primary, so the focus ring stays visible against the lifted
surfaces (4.98:1 on --background, 4.64:1 on --card). The violet, rose and
amber schemes below already pair ring with primary this way; emerald was
the one exception and is brought into line there, since the lifted
surfaces left its darker ring almost no headroom. */
--ring: 217.2 91.2% 59.8%;
}

/* Accent color schemes. Each scheme overrides only the accent-bearing tokens
Expand All @@ -70,10 +98,17 @@
--primary-foreground: 355.7 100% 97.3%;
--ring: 142.1 76.2% 36.3%;
}
/* Unlike violet/rose/amber, emerald's dark ring used to sit well below its
primary (142.4 71.8% 29.2%). Against the old near-black canvas that still
cleared the 3:1 focus-indicator floor at 3.98:1, but the lifted surfaces in
.dark drop it to 3.65:1 on --background and 3.13:1 on --popover — passing
by ~4%, so any later surface tweak would break it. Pairing ring with
primary restores the headroom (8.04:1 on --background) and makes the
ring == primary invariant hold across every scheme. */
[data-theme="emerald"].dark {
--primary: 142.1 70.6% 45.3%;
--primary-foreground: 144.9 80.4% 10%;
--ring: 142.4 71.8% 29.2%;
--ring: 142.1 70.6% 45.3%;
}

[data-theme="rose"] {
Expand Down
Loading