diff --git a/app/src/components/AppMeta/AppMeta.css b/app/src/components/AppMeta/AppMeta.css new file mode 100644 index 00000000..22331ecd --- /dev/null +++ b/app/src/components/AppMeta/AppMeta.css @@ -0,0 +1,32 @@ +/* Shared shape for the version / about / credit atoms. Each surface sets its + own colours, since the same link reads differently among header icons than it + does against footer prose. */ + +.meta-line { + display: inline-flex; + align-items: center; + gap: var(--cc-space-3); + flex-wrap: wrap; + min-width: 0; +} + +.meta-version, +.meta-credit { + white-space: nowrap; +} + +.meta-link { + text-decoration: none; +} +.meta-link:hover, +.meta-link:focus-visible { + color: var(--cc-text-strong); + text-decoration: underline; +} + +/* Pointer-events off so a stray click between items can't land on the dot. */ +.meta-sep { + flex: 0 0 auto; + color: var(--cc-text-faint); + pointer-events: none; +} diff --git a/app/src/components/AppMeta/AppMeta.tsx b/app/src/components/AppMeta/AppMeta.tsx new file mode 100644 index 00000000..b03b209f --- /dev/null +++ b/app/src/components/AppMeta/AppMeta.tsx @@ -0,0 +1,73 @@ +// components/AppMeta/AppMeta.tsx โ What codecity says about itself: which build +// is running, where the source is, and who made it. +// +// Three surfaces show these, in different arrangements: the app header carries +// about, the app footer splits version and credit across its two ends, and the +// project switcher runs all three under the wordmark. One definition each, so +// the wording, the URLs and the link targets cannot drift apart. +// +// Link treatment is the surface's call, via `linkClass`: the app chrome keeps +// its links at icon/prose weight so a status bar doesn't turn into a row of +// accents, while the landing uses the house `.link` (accent + always underlined, +// see styles/text.css) because nothing around it signals a link. + +import './AppMeta.css'; +import { SERVER_CONFIG } from '@/state/stores/serverConfig'; +import { REPO_URL, CREATOR_URL } from '@/constants/ui'; + +/** The running build's version, as reported by the server. */ +export function MetaVersion() { + return ; +} + +export interface MetaLinkProps { + /** House link class from styles/text.css: `link` or `link--chrome`. Omit to + * let the surface's own CSS colour it. */ + linkClass?: string; +} + +/** Outward link to the repo. */ +export function MetaAbout({ linkClass }: MetaLinkProps = {}) { + return ( + + about + + ); +} + +/** Authorship, linked to the author's site. */ +export function MetaCredit({ linkClass }: MetaLinkProps = {}) { + return ( + + ); +} + +/** All three on one line, separated. Used where there's room for the full set. */ +export function MetaLine({ linkClass }: MetaLinkProps = {}) { + return ( + + ); +} diff --git a/app/src/layout/AppFooter/AppFooter.css b/app/src/layout/AppFooter/AppFooter.css index 11adb21a..911b6df0 100644 --- a/app/src/layout/AppFooter/AppFooter.css +++ b/app/src/layout/AppFooter/AppFooter.css @@ -119,35 +119,21 @@ /* โโ Version + credit โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ /* Version sits with the status dot on the left; the credit holds the right. - Both stay a step below the status text so the live state reads first, and - the link brightens like any other. */ -.app-footer-version, -.app-footer-credit { + Both stay a step below the status text so the live state reads first. The + name inside the credit takes the house .link--chrome, since nothing around + it in a status bar signals that a word is a link. */ +#app-footer .meta-version, +#app-footer .meta-credit { color: var(--cc-text-muted); - white-space: nowrap; -} -.app-footer-link { - color: var(--cc-text-primary); - text-decoration: none; -} -.app-footer-link:hover, -.app-footer-link:focus-visible { - color: var(--cc-text-strong); - text-decoration: underline; } /* โโ Footer responsive narrowing โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */ -/* At narrow widths the status timestamp and the credit are both secondary to - knowing the build state at all, so the dot and version keep the bar. */ +/* Tighter insets, nothing dropped. The bar holds two short items per side, and + each section already clips with an ellipsis, so hiding anything traded real + information for space that wasn't needed. */ @media (max-width: 580px) { #app-footer { gap: var(--cc-space-3); padding: 0 var(--cc-space-4); } - .app-footer-status-detail { - display: none; - } - .app-footer-credit { - display: none; - } } diff --git a/app/src/layout/AppFooter/AppFooter.tsx b/app/src/layout/AppFooter/AppFooter.tsx index e0644320..77e5fddc 100644 --- a/app/src/layout/AppFooter/AppFooter.tsx +++ b/app/src/layout/AppFooter/AppFooter.tsx @@ -31,7 +31,7 @@ import { import { openDebug } from '@/state/stores/ui'; import { isDebugMode } from '@/utils/debugMode'; import { FooterSep } from './FooterSep'; -import { FooterVersion, FooterCredit } from './FooterMeta'; +import { MetaVersion, MetaCredit } from '@/components/AppMeta/AppMeta'; export interface FooterStatus { /** True when live-poll is active; renders as `live`. False renders as `paused`. */ @@ -156,7 +156,7 @@ export function AppFooter() {