fix(workspace): single scroll area, drag cleanup, thin note titles with bundled Inter
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m18s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m18s
- the workspace fills the window; only the note scrolls (also on phones, where the sideways scroll area used to scroll on its own) - clear drag state on dragend, calmer sidebar toggle when collapsed - ship Inter as variable font, light and larger note titles; header shows the title only after the big title scrolled away and stays one row on phones - main builds show the package version without -dev Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ad4829796c
commit
6c154af251
11 files changed
+88
-19
No files matched your search
@@ -51,10 +51,12 @@ jobs:
|
|||||||
echo "tag=${TAGS%% *}" >> "$GITHUB_OUTPUT"
|
echo "tag=${TAGS%% *}" >> "$GITHUB_OUTPUT"
|
||||||
echo "tags=${TAGS}" >> "$GITHUB_OUTPUT"
|
echo "tags=${TAGS}" >> "$GITHUB_OUTPUT"
|
||||||
echo "actor=${ACTOR_NAME}" >> "$GITHUB_OUTPUT"
|
echo "actor=${ACTOR_NAME}" >> "$GITHUB_OUTPUT"
|
||||||
# Releases (tags) show the tag as version in the app header
|
# Version in the app header: tags show the tag, main the package version, everything else
|
||||||
|
# (dev, feature branches) keeps the "-dev" suffix from vite.config.ts
|
||||||
APP_VERSION=""
|
APP_VERSION=""
|
||||||
case "${GITHUB_REF:-}" in
|
case "${GITHUB_REF:-}" in
|
||||||
refs/tags/*) APP_VERSION="${REF_NAME}" ;;
|
refs/tags/*) APP_VERSION="${REF_NAME}" ;;
|
||||||
|
refs/heads/main) APP_VERSION="v$(sed -nE 's/^ "version": "([^"]+)".*/\1/p' frontend/package.json | head -n1)" ;;
|
||||||
esac
|
esac
|
||||||
echo "app_version=${APP_VERSION}" >> "$GITHUB_OUTPUT"
|
echo "app_version=${APP_VERSION}" >> "$GITHUB_OUTPUT"
|
||||||
echo "Target Docker image: ${IMAGE_NAME} tags: ${TAGS} (Registry: ${REGISTRY_HOST}, Actor: ${ACTOR_NAME})"
|
echo "Target Docker image: ${IMAGE_NAME} tags: ${TAGS} (Registry: ${REGISTRY_HOST}, Actor: ${ACTOR_NAME})"
|
||||||
|
|||||||
@@ -6,7 +6,15 @@ Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), die V
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Schrift: MindSift liefert die Schrift Inter jetzt selbst aus (ohne externen Dienst), damit die Oberfläche auf allen Geräten gleich aussieht. Notiztitel stehen in einer feinen, dünnen Schrift und etwas größer.
|
||||||
|
- Notizen: Der Titel in der Kopfleiste erscheint erst, wenn der große Titel aus dem Bild gescrollt ist; am Handy passt die Kopfleiste in eine Zeile.
|
||||||
|
- Das Bild für `main` (`latest`) zeigt die Versionsnummer ohne `-dev`; nur `dev` und andere Zweige behalten den Zusatz.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- Workspace: kein doppelter Scrollbalken mehr – die Seite selbst scrollt nicht, nur die Notiz; am Handy scrollt die Notiz nicht mehr getrennt von der Seite.
|
||||||
|
- Workspace: Ein abgebrochenes Ziehen in der Seitenleiste lässt „Auf Hauptebene verschieben“ nicht mehr stehen.
|
||||||
|
- Workspace: Der Knopf zum Ein-/Ausklappen der Ordnerleiste ist im eingeklappten Zustand dezent (nur das Symbol in Akzentfarbe).
|
||||||
- Kontoeinstellungen: Der Bereich „Profil & Anmeldedaten“ nutzt die volle Breite wie die übrigen Bereiche.
|
- Kontoeinstellungen: Der Bereich „Profil & Anmeldedaten“ nutzt die volle Breite wie die übrigen Bereiche.
|
||||||
- Light-Theme: Notizen stehen auf einem weißen Blatt, die Ordnerleiste ist dezent grau abgesetzt (bisher umgekehrt). Themes können das über die neuen Variablen `--bg-editor` und `--bg-sidebar` selbst festlegen.
|
- Light-Theme: Notizen stehen auf einem weißen Blatt, die Ordnerleiste ist dezent grau abgesetzt (bisher umgekehrt). Themes können das über die neuen Variablen `--bg-editor` und `--bg-sidebar` selbst festlegen.
|
||||||
|
|
||||||
|
|||||||
Generated
+10
@@ -9,6 +9,7 @@
|
|||||||
"version": "0.9.0",
|
"version": "0.9.0",
|
||||||
"license": "Unlicense",
|
"license": "Unlicense",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource-variable/inter": "5.3.0",
|
||||||
"@types/prismjs": "^1.26.6",
|
"@types/prismjs": "^1.26.6",
|
||||||
"emoji-picker-react": "4.12.0",
|
"emoji-picker-react": "4.12.0",
|
||||||
"framer-motion": "^11.15.0",
|
"framer-motion": "^11.15.0",
|
||||||
@@ -1024,6 +1025,15 @@
|
|||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@fontsource-variable/inter": {
|
||||||
|
"version": "5.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fontsource-variable/inter/-/inter-5.3.0.tgz",
|
||||||
|
"integrity": "sha512-OupL48va4JNofb97w6NYeF9S7W/kHNKM0Er8Dem5nqi4jeOLrVJDoE8tZEpnMJmtkvNbB1EIPPwHcdkF6b1oUA==",
|
||||||
|
"license": "OFL-1.1",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ayuhito"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanfs/core": {
|
"node_modules/@humanfs/core": {
|
||||||
"version": "0.19.2",
|
"version": "0.19.2",
|
||||||
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
|
"resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz",
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"test:run": "vitest run"
|
"test:run": "vitest run"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource-variable/inter": "5.3.0",
|
||||||
"@types/prismjs": "^1.26.6",
|
"@types/prismjs": "^1.26.6",
|
||||||
"emoji-picker-react": "4.12.0",
|
"emoji-picker-react": "4.12.0",
|
||||||
"framer-motion": "^11.15.0",
|
"framer-motion": "^11.15.0",
|
||||||
|
|||||||
+12
-3
@@ -750,7 +750,11 @@ export const App: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-canvas text-main flex flex-col font-sans selection:bg-accent/30">
|
<div
|
||||||
|
className={`bg-canvas text-main flex flex-col font-sans selection:bg-accent/30 ${
|
||||||
|
activeTab === 'workspace' ? 'h-[100dvh] overflow-hidden' : 'min-h-screen'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
{/* Top Header Bar: Floating on mobile, solid panel on desktop */}
|
{/* Top Header Bar: Floating on mobile, solid panel on desktop */}
|
||||||
<header className="sticky top-0 z-30 bg-canvas/85 backdrop-blur-md sm:bg-panel sm:border-b sm:border-border sm:shadow-sm">
|
<header className="sticky top-0 z-30 bg-canvas/85 backdrop-blur-md sm:bg-panel sm:border-b sm:border-border sm:shadow-sm">
|
||||||
{/* Mobile Header: Floating Bar with Logo Action Dropdown Left & Profile Avatar Right */}
|
{/* Mobile Header: Floating Bar with Logo Action Dropdown Left & Profile Avatar Right */}
|
||||||
@@ -1113,9 +1117,14 @@ export const App: React.FC = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Main Container */}
|
{/* Main Container */}
|
||||||
<main className="flex-1 max-w-6xl w-full mx-auto px-3 sm:px-4 pt-3 pb-24 sm:pb-6">
|
{/* The workspace fills the window exactly and scrolls only inside the note, never the page */}
|
||||||
|
<main
|
||||||
|
className={`flex-1 max-w-6xl w-full mx-auto px-3 sm:px-4 pt-3 pb-24 sm:pb-6 ${
|
||||||
|
activeTab === 'workspace' ? 'min-h-0 flex flex-col' : ''
|
||||||
|
}`}
|
||||||
|
>
|
||||||
<ViewErrorBoundary onReset={() => setActiveTab('triage')}>
|
<ViewErrorBoundary onReset={() => setActiveTab('triage')}>
|
||||||
<section key={dataEpoch}>
|
<section key={dataEpoch} className={activeTab === 'workspace' ? 'flex-1 min-h-0 flex flex-col' : undefined}>
|
||||||
{activeTab === 'triage' && (
|
{activeTab === 'triage' && (
|
||||||
<TriageDeck
|
<TriageDeck
|
||||||
deck={deck}
|
deck={deck}
|
||||||
|
|||||||
@@ -230,6 +230,9 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
|
|||||||
|
|
||||||
|
|
||||||
const titleInputRef = useRef<HTMLTextAreaElement | HTMLInputElement | null>(null);
|
const titleInputRef = useRef<HTMLTextAreaElement | HTMLInputElement | null>(null);
|
||||||
|
const scrollRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
// The header repeats the title only once the big title has scrolled out of view
|
||||||
|
const [titleScrolledAway, setTitleScrolledAway] = useState(false);
|
||||||
const outlinerTreeRef = useRef<OutlinerTreeHandle | null>(null);
|
const outlinerTreeRef = useRef<OutlinerTreeHandle | null>(null);
|
||||||
const docRef = useRef<Document | null>(doc);
|
const docRef = useRef<Document | null>(doc);
|
||||||
docRef.current = doc;
|
docRef.current = doc;
|
||||||
@@ -239,6 +242,22 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
|
|||||||
const currentBlocksRef = useRef<DocumentBlock[]>(blocks);
|
const currentBlocksRef = useRef<DocumentBlock[]>(blocks);
|
||||||
currentBlocksRef.current = blocks;
|
currentBlocksRef.current = blocks;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const root = scrollRef.current;
|
||||||
|
const el = titleInputRef.current;
|
||||||
|
if (!root || !el || typeof IntersectionObserver === 'undefined') {
|
||||||
|
setTitleScrolledAway(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
([entry]) => setTitleScrolledAway(!entry.isIntersecting),
|
||||||
|
// the sticky header covers the top of the scroll area
|
||||||
|
{ root, rootMargin: '-56px 0px 0px 0px' }
|
||||||
|
);
|
||||||
|
observer.observe(el);
|
||||||
|
return () => observer.disconnect();
|
||||||
|
}, [zoomedBlockId, doc?.id]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loading && (autoFocusTitle || (doc?.title === 'Neue Notiz' && (!doc?.blocks || doc?.blocks.length <= 1)))) {
|
if (!loading && (autoFocusTitle || (doc?.title === 'Neue Notiz' && (!doc?.blocks || doc?.blocks.length <= 1)))) {
|
||||||
const focusTitle = () => {
|
const focusTitle = () => {
|
||||||
@@ -763,15 +782,15 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-1 flex flex-col h-full min-h-0 bg-editor overflow-y-auto" data-sync-channel={engineState?.channel}>
|
<div ref={scrollRef} className="flex-1 flex flex-col h-full min-h-0 bg-editor overflow-y-auto" data-sync-channel={engineState?.channel}>
|
||||||
{/* Top Document Action Bar */}
|
{/* Top Document Action Bar */}
|
||||||
<div className="sticky top-0 z-20 flex flex-wrap items-center justify-between gap-2 px-4 sm:px-6 py-2 bg-editor border-b border-border">
|
<div className="sticky top-0 z-20 flex items-center justify-between gap-2 px-4 sm:px-6 py-2 bg-editor border-b border-border">
|
||||||
<div className="flex items-center gap-2 min-w-0">
|
<div className="flex flex-1 items-center gap-2 min-w-0">
|
||||||
{onBackMobile && (
|
{onBackMobile && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onBackMobile}
|
onClick={onBackMobile}
|
||||||
className="lg:hidden btn-icon h-11 w-11 sm:h-7 sm:w-7"
|
className="lg:hidden btn-icon shrink-0 h-11 w-11 sm:h-7 sm:w-7"
|
||||||
title="Zurück zur Seitenleiste"
|
title="Zurück zur Seitenleiste"
|
||||||
>
|
>
|
||||||
<ArrowLeft className="w-3.5 h-3.5" />
|
<ArrowLeft className="w-3.5 h-3.5" />
|
||||||
@@ -823,7 +842,12 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
|
|||||||
})}
|
})}
|
||||||
</nav>
|
</nav>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex items-center gap-1.5 text-xs text-muted">
|
<div
|
||||||
|
className={`flex min-w-0 items-center gap-1.5 text-xs text-muted transition-opacity duration-200 ${
|
||||||
|
titleScrolledAway ? 'opacity-100' : 'opacity-0 pointer-events-none'
|
||||||
|
}`}
|
||||||
|
aria-hidden={!titleScrolledAway}
|
||||||
|
>
|
||||||
<FileText className="w-3.5 h-3.5 text-accent shrink-0" />
|
<FileText className="w-3.5 h-3.5 text-accent shrink-0" />
|
||||||
<span className="truncate max-w-[180px] font-medium text-main">
|
<span className="truncate max-w-[180px] font-medium text-main">
|
||||||
{title || doc?.title || 'Dokument'}
|
{title || doc?.title || 'Dokument'}
|
||||||
@@ -868,7 +892,7 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right Action Buttons */}
|
{/* Right Action Buttons */}
|
||||||
<div className="flex items-center gap-1.5">
|
<div className="flex shrink-0 items-center gap-1.5">
|
||||||
{!inTrash && (
|
{!inTrash && (
|
||||||
<>
|
<>
|
||||||
<button
|
<button
|
||||||
@@ -1022,7 +1046,8 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
|
|||||||
|
|
||||||
{/* Main Content Area */}
|
{/* Main Content Area */}
|
||||||
{/* Phones: almost no side margin; very deep outlines scroll sideways (rows keep a minimum width) */}
|
{/* Phones: almost no side margin; very deep outlines scroll sideways (rows keep a minimum width) */}
|
||||||
<div className="w-full pl-2 pr-1 sm:px-8 py-5 flex-1 overflow-x-auto sm:overflow-x-visible [-webkit-overflow-scrolling:touch]">
|
{/* shrink-0: the sideways scroll area must keep its full height, so only the editor scrolls vertically */}
|
||||||
|
<div className="w-full pl-2 pr-1 sm:px-8 py-5 flex-auto shrink-0 overflow-x-auto sm:overflow-x-visible [-webkit-overflow-scrolling:touch]">
|
||||||
{zoomedBlock ? (
|
{zoomedBlock ? (
|
||||||
/* =========================================================================
|
/* =========================================================================
|
||||||
FOKUS-MODUS & ZOOM-IN (HOISTED SUBTREE VIEW)
|
FOKUS-MODUS & ZOOM-IN (HOISTED SUBTREE VIEW)
|
||||||
@@ -1061,7 +1086,7 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
|
|||||||
}}
|
}}
|
||||||
placeholder="Ast-Titel…"
|
placeholder="Ast-Titel…"
|
||||||
readOnly={!canEdit}
|
readOnly={!canEdit}
|
||||||
className="w-full text-2xl sm:text-3xl font-extrabold text-main bg-transparent border-0 focus:outline-none focus:ring-0 tracking-tight leading-tight"
|
className="w-full text-2xl sm:text-3xl font-light text-main bg-transparent border-0 focus:outline-none focus:ring-0 tracking-tight leading-tight"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -1183,7 +1208,7 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = ({
|
|||||||
}}
|
}}
|
||||||
onBlur={handleTitleBlur}
|
onBlur={handleTitleBlur}
|
||||||
placeholder="Titel der Notiz…"
|
placeholder="Titel der Notiz…"
|
||||||
className="flex-1 min-w-0 text-xl sm:text-2xl font-bold text-main bg-transparent border-0 focus:outline-none focus:ring-0 tracking-tight resize-none leading-snug whitespace-pre-wrap break-words [overflow-wrap:anywhere]"
|
className="flex-1 min-w-0 text-2xl sm:text-3xl font-light text-main bg-transparent border-0 focus:outline-none focus:ring-0 tracking-tight resize-none leading-snug whitespace-pre-wrap break-words [overflow-wrap:anywhere]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -408,6 +408,17 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
}, []);
|
}, []);
|
||||||
const [draggingFolderPath, setDraggingFolderPath] = useState<string | null>(null);
|
const [draggingFolderPath, setDraggingFolderPath] = useState<string | null>(null);
|
||||||
const [dragOverFolder, setDragOverFolder] = useState<string | null>(null);
|
const [dragOverFolder, setDragOverFolder] = useState<string | null>(null);
|
||||||
|
// A drag that ends without a drop (released elsewhere, Escape) fires only dragend: clear every drag state
|
||||||
|
useEffect(() => {
|
||||||
|
const clear = () => {
|
||||||
|
setDraggingDocId(null);
|
||||||
|
setDraggingFolderPath(null);
|
||||||
|
setDragOverFolder(null);
|
||||||
|
setMergeHoverId(null);
|
||||||
|
};
|
||||||
|
document.addEventListener('dragend', clear);
|
||||||
|
return () => document.removeEventListener('dragend', clear);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Rollup drilldown & View Mode
|
// Rollup drilldown & View Mode
|
||||||
const [todoFolderDrilldown, setTodoFolderDrilldown] = useState<string | null>(null);
|
const [todoFolderDrilldown, setTodoFolderDrilldown] = useState<string | null>(null);
|
||||||
@@ -1218,7 +1229,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
}, [tagsSummary, tagSearchQuery, tagSortBy]);
|
}, [tagsSummary, tagSearchQuery, tagSortBy]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full space-y-3">
|
<div className="w-full h-full min-h-0 flex flex-col gap-3">
|
||||||
{/* Top Header: Workspace Tabs & Actions */}
|
{/* Top Header: Workspace Tabs & Actions */}
|
||||||
<div className="flex flex-wrap items-center justify-between gap-2 border-b border-border pb-2">
|
<div className="flex flex-wrap items-center justify-between gap-2 border-b border-border pb-2">
|
||||||
{/* Workspace selector tabs & left sidebar toggle; on phones the three tabs share the full width */}
|
{/* Workspace selector tabs & left sidebar toggle; on phones the three tabs share the full width */}
|
||||||
@@ -1231,8 +1242,8 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
subView !== 'editor'
|
subView !== 'editor'
|
||||||
? 'opacity-35 bg-canvas border-border text-faint cursor-not-allowed pointer-events-none'
|
? 'opacity-35 bg-canvas border-border text-faint cursor-not-allowed pointer-events-none'
|
||||||
: isSidebarCollapsed
|
: isSidebarCollapsed
|
||||||
? 'bg-panel border-accent text-accent cursor-pointer'
|
? 'bg-canvas border-border text-accent hover:bg-panel cursor-pointer'
|
||||||
: 'bg-canvas border-border text-muted hover:text-main cursor-pointer'
|
: 'bg-canvas border-border text-muted hover:text-main hover:bg-panel cursor-pointer'
|
||||||
}`}
|
}`}
|
||||||
title={
|
title={
|
||||||
subView !== 'editor'
|
subView !== 'editor'
|
||||||
@@ -1436,7 +1447,7 @@ export const WorkspaceView: React.FC<WorkspaceViewProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Main Workspace Split Pane */}
|
{/* Main Workspace Split Pane */}
|
||||||
<div className="flex h-[calc(100vh-7.5rem)] bg-editor rounded-card border border-border overflow-hidden">
|
<div className="flex flex-1 min-h-0 bg-editor rounded-card border border-border overflow-hidden">
|
||||||
{/* LEFT MASTER SIDEBAR */}
|
{/* LEFT MASTER SIDEBAR */}
|
||||||
<aside
|
<aside
|
||||||
className={`${
|
className={`${
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
body {
|
body {
|
||||||
background-color: var(--bg-app);
|
background-color: var(--bg-app);
|
||||||
color: var(--text-main);
|
color: var(--text-main);
|
||||||
font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
font-family: 'Inter Variable', 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
transition: background-color 140ms ease, color 140ms ease;
|
transition: background-color 140ms ease, color 140ms ease;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import React from 'react';
|
|||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import { MobileActionProvider } from './context/MobileActionContext';
|
import { MobileActionProvider } from './context/MobileActionContext';
|
||||||
|
// Inter ships with the app (no external font service); the variable font covers all weights
|
||||||
|
import '@fontsource-variable/inter';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ export default {
|
|||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
sans: [
|
sans: [
|
||||||
|
'Inter Variable',
|
||||||
'Inter',
|
'Inter',
|
||||||
'system-ui',
|
'system-ui',
|
||||||
'-apple-system',
|
'-apple-system',
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { defineConfig } from 'vite';
|
|||||||
import react from '@vitejs/plugin-react';
|
import react from '@vitejs/plugin-react';
|
||||||
import { readFileSync } from 'node:fs';
|
import { readFileSync } from 'node:fs';
|
||||||
|
|
||||||
// Shown in the header. Release builds get the git tag (APP_VERSION build argument, e.g. "v0.6.0");
|
// Shown in the header. Tag and main builds get APP_VERSION as build argument (e.g. "v0.6.0");
|
||||||
// other builds show the package version with a "-dev" suffix (Semantic Versioning, see CHANGELOG.md).
|
// other builds show the package version with a "-dev" suffix (Semantic Versioning, see CHANGELOG.md).
|
||||||
const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8'));
|
const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8'));
|
||||||
const appVersion = process.env.APP_VERSION || `v${pkg.version}-dev`;
|
const appVersion = process.env.APP_VERSION || `v${pkg.version}-dev`;
|
||||||
|
|||||||
Reference in new issue
Block a user