Fix the dead create button on a fresh install, and make Design one surface (#89)
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 10s
CI & Build / integration (push) Successful in 30s
CI & Build / TypeScript typecheck (push) Successful in 35s
CI & Build / Python tests (push) Successful in 56s
CI & Build / Build & push image (push) Successful in 22s
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 10s
CI & Build / integration (push) Successful in 30s
CI & Build / TypeScript typecheck (push) Successful in 35s
CI & Build / Python tests (push) Successful in 56s
CI & Build / Build & push image (push) Successful in 22s
This commit was merged in pull request #89.
This commit is contained in:
@@ -64,10 +64,13 @@ router.afterEach(() => {
|
|||||||
<Moon v-else :size="16" />
|
<Moon v-else :size="16" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<!-- Design explorer. An icon rather than a sixth primary nav link: it's a
|
<!-- Design. An icon rather than a sixth primary nav link: it's a
|
||||||
meta-surface like Trash and Settings, but hiding it entirely would
|
meta-surface like Trash and Settings, but hiding it entirely would
|
||||||
defeat the point of having somewhere the design system is visible. -->
|
defeat the point of having somewhere the design system is visible.
|
||||||
<router-link to="/design" class="btn-icon" aria-label="Design" title="Design">
|
Points at the RECORD, not the live-token view — the record is what
|
||||||
|
you work with; the live view is the check on it, and it's a tab
|
||||||
|
away. -->
|
||||||
|
<router-link to="/design-systems" class="btn-icon" aria-label="Design" title="Design">
|
||||||
<Palette :size="16" />
|
<Palette :size="16" />
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|
||||||
@@ -105,8 +108,7 @@ router.afterEach(() => {
|
|||||||
<router-link to="/rules" class="nav-link">Rulebooks</router-link>
|
<router-link to="/rules" class="nav-link">Rulebooks</router-link>
|
||||||
<router-link to="/shared" class="nav-link">Shared</router-link>
|
<router-link to="/shared" class="nav-link">Shared</router-link>
|
||||||
<div class="mobile-divider"></div>
|
<div class="mobile-divider"></div>
|
||||||
<router-link to="/design" class="nav-link">Design</router-link>
|
<router-link to="/design-systems" class="nav-link">Design</router-link>
|
||||||
<router-link to="/design-systems" class="nav-link">Design systems</router-link>
|
|
||||||
<router-link to="/trash" class="nav-link">Trash</router-link>
|
<router-link to="/trash" class="nav-link">Trash</router-link>
|
||||||
<router-link to="/settings" class="nav-link">Settings</router-link>
|
<router-link to="/settings" class="nav-link">Settings</router-link>
|
||||||
<div class="mobile-divider"></div>
|
<div class="mobile-divider"></div>
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
/**
|
||||||
|
* Sub-navigation for the Design surface.
|
||||||
|
*
|
||||||
|
* There are two pages here and they are halves of ONE thing: the record that
|
||||||
|
* decides the styling, and what the browser is actually rendering from it. They
|
||||||
|
* were briefly two top-level nav entries, which put the read-only diagnostic
|
||||||
|
* first and buried the editable record under it — backwards, since the record
|
||||||
|
* is the thing you work with and the live view is the check on it.
|
||||||
|
*
|
||||||
|
* A component rather than the same markup pasted into both views: two copies of
|
||||||
|
* a tab bar diverge the moment a third tab appears, and that is the exact shape
|
||||||
|
* of duplication this whole surface exists to make visible.
|
||||||
|
*/
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<nav class="design-tabs" aria-label="Design views">
|
||||||
|
<router-link to="/design-systems" class="design-tab">Design system</router-link>
|
||||||
|
<router-link to="/design" class="design-tab">Live tokens</router-link>
|
||||||
|
</nav>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.design-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.25rem;
|
||||||
|
margin-bottom: 1.25rem;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.design-tab {
|
||||||
|
padding: 0.5rem 0.9rem;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
text-decoration: none;
|
||||||
|
border-bottom: 2px solid transparent;
|
||||||
|
margin-bottom: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.design-tab:hover {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* `router-link-active` rather than `-exact-active`: both routes are leaves, and
|
||||||
|
exact matching would drop the highlight on any future child route. */
|
||||||
|
.design-tab.router-link-active {
|
||||||
|
color: var(--color-primary);
|
||||||
|
border-bottom-color: var(--color-primary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -42,6 +42,7 @@ import {
|
|||||||
type StylesheetResult,
|
type StylesheetResult,
|
||||||
} from "@/api/designSystems";
|
} from "@/api/designSystems";
|
||||||
import { listRulebooks, type Rulebook } from "@/api/rulebooks";
|
import { listRulebooks, type Rulebook } from "@/api/rulebooks";
|
||||||
|
import DesignTabs from "@/components/DesignTabs.vue";
|
||||||
import { ApiError } from "@/api/client";
|
import { ApiError } from "@/api/client";
|
||||||
import { useToastStore } from "@/stores/toast";
|
import { useToastStore } from "@/stores/toast";
|
||||||
|
|
||||||
@@ -528,14 +529,14 @@ function isColourish(value: string): boolean {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="ds-view">
|
<div class="ds-view">
|
||||||
|
<DesignTabs />
|
||||||
|
|
||||||
<header class="ds-header">
|
<header class="ds-header">
|
||||||
<h1>Design systems</h1>
|
<h1>Design systems</h1>
|
||||||
<p class="lede">
|
<p class="lede">
|
||||||
The design system as the record holds it. A system with a parent stores
|
The design system as the record holds it. A system with a parent stores
|
||||||
only what it changes, so its own list is the answer to "what does this
|
only what it changes, so its own list is the answer to "what does this
|
||||||
one alter?" — nothing to compute.
|
one alter?" — nothing to compute.
|
||||||
<router-link to="/design">The design page</router-link> shows the other
|
|
||||||
side: what the browser is actually rendering right now.
|
|
||||||
</p>
|
</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
@@ -547,7 +548,7 @@ function isColourish(value: string): boolean {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty is the ordinary state for most installs, not a broken one. -->
|
<!-- Empty is the ordinary state for most installs, not a broken one. -->
|
||||||
<div v-else-if="!systems.length" class="notice">
|
<div v-else-if="!systems.length && !showCreate" class="notice">
|
||||||
<strong>No design systems yet.</strong>
|
<strong>No design systems yet.</strong>
|
||||||
<p>
|
<p>
|
||||||
A design system holds your tokens — colours, spacing, radii — as records
|
A design system holds your tokens — colours, spacing, radii — as records
|
||||||
@@ -557,6 +558,39 @@ function isColourish(value: string): boolean {
|
|||||||
<button class="btn-primary" @click="showCreate = true">Create the first one</button>
|
<button class="btn-primary" @click="showCreate = true">Create the first one</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- The FIRST system gets its own form, outside the list layout below.
|
||||||
|
`.ds-body` and the empty state are mutually exclusive branches, so a
|
||||||
|
form nested in the former is unreachable from the latter — which is
|
||||||
|
exactly the dead button this replaces. Once a system exists, the form
|
||||||
|
inside `.ds-body` takes over and this branch never renders. -->
|
||||||
|
<section v-else-if="!systems.length" class="ds-section">
|
||||||
|
<h2>New design system</h2>
|
||||||
|
<p class="section-note">
|
||||||
|
Nothing to inherit from yet, so this one is a family system — the house
|
||||||
|
style everything else departs from.
|
||||||
|
</p>
|
||||||
|
<div class="field">
|
||||||
|
<label class="field-label" for="first-title">Title</label>
|
||||||
|
<input
|
||||||
|
id="first-title" v-model="newTitle" class="input" type="text"
|
||||||
|
placeholder="FabledSword" @keyup.enter="submitCreate"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label class="field-label" for="first-desc">Description</label>
|
||||||
|
<input
|
||||||
|
id="first-desc" v-model="newDescription" class="input" type="text"
|
||||||
|
placeholder="What it covers"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="row-actions">
|
||||||
|
<button class="btn-primary" :disabled="!newTitle.trim() || creating" @click="submitCreate">
|
||||||
|
{{ creating ? "Creating…" : "Create" }}
|
||||||
|
</button>
|
||||||
|
<button class="btn-ghost" @click="showCreate = false">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div v-else class="ds-body">
|
<div v-else class="ds-body">
|
||||||
<!-- Systems list -->
|
<!-- Systems list -->
|
||||||
<aside class="ds-sidebar">
|
<aside class="ds-sidebar">
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
|
|
||||||
import { fetchDesignExpectations } from "@/api/design";
|
import { fetchDesignExpectations } from "@/api/design";
|
||||||
|
import DesignTabs from "@/components/DesignTabs.vue";
|
||||||
import PriorityBadge from "@/components/PriorityBadge.vue";
|
import PriorityBadge from "@/components/PriorityBadge.vue";
|
||||||
import StatusBadge from "@/components/StatusBadge.vue";
|
import StatusBadge from "@/components/StatusBadge.vue";
|
||||||
import TagPill from "@/components/TagPill.vue";
|
import TagPill from "@/components/TagPill.vue";
|
||||||
@@ -101,8 +102,10 @@ const TYPE_SPECIMENS = [
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="design-view">
|
<div class="design-view">
|
||||||
|
<DesignTabs />
|
||||||
|
|
||||||
<header class="design-header">
|
<header class="design-header">
|
||||||
<h1>Design</h1>
|
<h1>Live tokens</h1>
|
||||||
<p class="lede">
|
<p class="lede">
|
||||||
The system as it actually is. Token values are read from the browser at
|
The system as it actually is. Token values are read from the browser at
|
||||||
runtime, so this page reflects the live cascade rather than what the
|
runtime, so this page reflects the live cascade rather than what the
|
||||||
@@ -110,11 +113,6 @@ const TYPE_SPECIMENS = [
|
|||||||
the system has no shared implementation, it is marked missing rather
|
the system has no shared implementation, it is marked missing rather
|
||||||
than mocked up.
|
than mocked up.
|
||||||
</p>
|
</p>
|
||||||
<p class="lede">
|
|
||||||
For the other half — the design system as a record you can edit, with
|
|
||||||
family → app inheritance — see
|
|
||||||
<router-link to="/design-systems">design systems</router-link>.
|
|
||||||
</p>
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- Drift: what the rulebook claims vs what the tokens do. -->
|
<!-- Drift: what the rulebook claims vs what the tokens do. -->
|
||||||
|
|||||||
Reference in New Issue
Block a user