Info page: show the app version, two-column layout on wide screens
An About panel shows the installed version (from Tauri at runtime, since release builds stamp it at build time; dev builds are labelled as such). On wide screens the page splits into panels in two columns — card database, library stats and libraries on the left; sync and about on the right — while narrow screens keep the single-column order. The sync panel is now headed "Sync" and the Info page's summary "Library stats". Closes #22
This commit is contained in:
102
src/App.tsx
102
src/App.tsx
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useRef, useState, useCallback, ReactNode } from "react";
|
||||
import { getVersion } from "@tauri-apps/api/app";
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { open } from "@tauri-apps/plugin-dialog";
|
||||
import {
|
||||
@@ -168,10 +169,12 @@ function LibrarySummary({
|
||||
ready,
|
||||
libStats,
|
||||
status,
|
||||
title = "Your library",
|
||||
}: {
|
||||
ready: boolean;
|
||||
libStats: LibraryStats | null;
|
||||
status: Status | null;
|
||||
title?: string;
|
||||
}) {
|
||||
if (!ready) {
|
||||
return (
|
||||
@@ -185,7 +188,7 @@ function LibrarySummary({
|
||||
<div className="lib-stats">
|
||||
<div className="lib-stats-head">
|
||||
<span className="status-dot on" />
|
||||
<span className="lib-stats-title">Your library</span>
|
||||
<span className="lib-stats-title">{title}</span>
|
||||
</div>
|
||||
{!libStats ? (
|
||||
<div className="lib-stats-loading">Loading…</div>
|
||||
@@ -242,6 +245,12 @@ export default function App() {
|
||||
const [status, setStatus] = useState<Status | null>(null);
|
||||
const [libStats, setLibStats] = useState<LibraryStats | null>(null);
|
||||
const [tab, setTab] = usePersistedState<Tab>("active-tab", "add");
|
||||
// The installed build's version, for the Info page. Release builds stamp
|
||||
// it at build time, so it comes from Tauri rather than package.json.
|
||||
const [appVersion, setAppVersion] = useState<string | null>(null);
|
||||
useEffect(() => {
|
||||
getVersion().then(setAppVersion).catch(() => setAppVersion(null));
|
||||
}, []);
|
||||
// A deck a chip elsewhere asked to open; DeckView picks it up and clears it.
|
||||
const [openDeckId, setOpenDeckId] = useState<number | null>(null);
|
||||
// Deck chips only carry the deck's name, which is unique per library.
|
||||
@@ -798,41 +807,64 @@ export default function App() {
|
||||
// rail it normally sits in is replaced by the bottom nav);
|
||||
// on desktop those also appear in the topbar and rail, but sync
|
||||
// lives only here.
|
||||
<div className="panel info-panel">
|
||||
<h2 style={{ margin: 0 }}>Card database</h2>
|
||||
<div className="row" style={{ gap: "var(--space-3)", flexWrap: "wrap" }}>
|
||||
<button className="primary" onClick={updateCardData} disabled={busy}>
|
||||
{ICON_DOWNLOAD}
|
||||
{busy ? "Downloading…" : "Update card data"}
|
||||
</button>
|
||||
<button onClick={importReferenceDb} disabled={busy}>
|
||||
{ICON_OPEN_LIBRARY}
|
||||
Import card data…
|
||||
</button>
|
||||
// Two columns on wide screens — card data, library stats and the
|
||||
// libraries on the left; sync and the version on the right. On
|
||||
// narrow ones the columns dissolve into one list in the order
|
||||
// set by `.info-*` (see styles.css).
|
||||
<div className="info-grid">
|
||||
<div className="info-col">
|
||||
<section className="panel info-section info-db">
|
||||
<h2 style={{ margin: 0 }}>Card database</h2>
|
||||
<div className="row" style={{ gap: "var(--space-3)", flexWrap: "wrap" }}>
|
||||
<button className="primary" onClick={updateCardData} disabled={busy}>
|
||||
{ICON_DOWNLOAD}
|
||||
{busy ? "Downloading…" : "Update card data"}
|
||||
</button>
|
||||
<button onClick={importReferenceDb} disabled={busy}>
|
||||
{ICON_OPEN_LIBRARY}
|
||||
Import card data…
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
<section className="panel info-section info-summary">
|
||||
<LibrarySummary ready={ready} libStats={libStats} status={status} title="Library stats" />
|
||||
</section>
|
||||
<section className="panel info-section info-libraries">
|
||||
<LibrariesPanel
|
||||
libraries={libraries}
|
||||
signedIn={sync?.signed_in ?? false}
|
||||
onChanged={librariesChanged}
|
||||
/>
|
||||
</section>
|
||||
</div>
|
||||
<div className="info-col">
|
||||
<section className="panel info-section info-sync">
|
||||
{sync === null ? (
|
||||
<>
|
||||
<h2 style={{ margin: 0 }}>Sync</h2>
|
||||
<div className="hint">Checking…</div>
|
||||
</>
|
||||
) : (
|
||||
<SyncPanel
|
||||
sync={sync}
|
||||
setSync={setSync}
|
||||
syncing={syncing}
|
||||
runSync={runSync}
|
||||
onLibraryReplaced={refreshEverything}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
<section className="panel info-section info-about">
|
||||
<h2 style={{ margin: 0 }}>About</h2>
|
||||
<div className="info-about-row">
|
||||
<span className="muted">mtgc version</span>
|
||||
<span className="info-version">
|
||||
{appVersion ?? "unknown"}
|
||||
{import.meta.env.DEV && <span className="muted"> · development build</span>}
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<hr className="deck-section-divider" style={{ margin: 0 }} />
|
||||
<LibrariesPanel
|
||||
libraries={libraries}
|
||||
signedIn={sync?.signed_in ?? false}
|
||||
onChanged={librariesChanged}
|
||||
/>
|
||||
<hr className="deck-section-divider" style={{ margin: 0 }} />
|
||||
{sync === null ? (
|
||||
<>
|
||||
<h2 style={{ margin: 0 }}>Your library</h2>
|
||||
<div className="hint">Checking…</div>
|
||||
</>
|
||||
) : (
|
||||
<SyncPanel
|
||||
sync={sync}
|
||||
setSync={setSync}
|
||||
syncing={syncing}
|
||||
runSync={runSync}
|
||||
onLibraryReplaced={refreshEverything}
|
||||
/>
|
||||
)}
|
||||
<hr className="deck-section-divider" style={{ margin: 0 }} />
|
||||
<LibrarySummary ready={ready} libStats={libStats} status={status} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user