Files
FabledScribe/frontend/src/components/rules/RulebookListPane.vue
T
bvandeusenandClaude Opus 5 bd60d679d9
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 16s
CI & Build / integration (push) Successful in 23s
CI & Build / TypeScript typecheck (push) Successful in 25s
CI & Build / Python tests (push) Successful in 57s
CI & Build / Build & push image (push) Successful in 43s
refactor(theme): remove 184 var() fallbacks — every one was unreachable
#2277 counted ~150 "raw colour literals bypassing the tokens". Measuring them
told a different story: 184 sat in `var(--token, #fallback)` position, and a
check against theme.css shows every one of those tokens IS declared. So the
fallbacks could not render. Not drift — vestigial.

They were also not this palette. The most common were Tailwind and Flat-UI
defaults — #6366f1 indigo, #22c55e green, #f59e0b amber, #3b82f6 blue,
#e74c3c and #27ae60 — a second, unsanctioned colour scheme sitting in the
codebase looking like the app's colours to anyone reading it.

Removing them is not tidying. #2319's lesson is that a fallback is WORSE than a
missing token: a missing token renders as nothing and someone eventually
notices, while a fallback renders something plausible forever. These 184 were
one token rename away from silently repainting the app in Tailwind. The design
token check would catch the rename — but the fallback is precisely the thing
that would make it invisible if the check were ever bypassed.

Literal count 152 -> 45, which matters beyond the number: a report that is
mostly unreachable noise is one people stop reading, and then it stops working
while still passing. What remains should be genuinely worth looking at.

Done with a paren-aware transform, not a regex — `var(--x, rgba(0,0,0,.5))`
nests parens and `[^)]+` would cut at the first one and leave `))` behind.
Verified after: every changed line is a fallback strip and nothing else, and
every var() reference still resolves.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs
2026-08-03 11:52:04 -04:00

77 lines
2.4 KiB
Vue

<script setup lang="ts">
import { ref } from "vue";
import { useRulebooksStore } from "@/stores/rulebooks";
import type { Rulebook } from "@/api/rulebooks";
defineProps<{ rulebooks: Rulebook[]; selectedId: number | null }>();
const emit = defineEmits<{ select: [id: number] }>();
const store = useRulebooksStore();
const isCreating = ref(false);
const newTitle = ref("");
async function submitNew() {
const title = newTitle.value.trim();
if (!title) return;
const rb = await store.createRulebook({ title });
newTitle.value = "";
isCreating.value = false;
emit("select", rb.id);
}
</script>
<template>
<aside class="pane">
<header><h2>Rulebooks</h2></header>
<ul>
<li
v-for="rb in rulebooks"
:key="rb.id"
:class="{ active: rb.id === selectedId }"
@click="emit('select', rb.id)"
>
<span class="title">{{ rb.title }}</span>
<span v-if="rb.always_on" class="always-on-badge" title="Loaded at session start">always on</span>
</li>
</ul>
<div class="new-rulebook">
<button v-if="!isCreating" @click="isCreating = true">+ New rulebook</button>
<form v-else @submit.prevent="submitNew">
<input v-model="newTitle" autofocus placeholder="Rulebook title" />
<div class="form-buttons">
<button type="submit">Create</button>
<button type="button" @click="isCreating = false">Cancel</button>
</div>
</form>
</div>
</aside>
</template>
<style scoped>
.pane { background: var(--color-surface); padding: 1rem; overflow-y: auto; }
header h2 { font-family: Fraunces, serif; font-style: italic; margin: 0 0 0.5rem 0; }
ul { list-style: none; padding: 0; margin: 1rem 0; }
li { padding: 0.5rem; cursor: pointer; border-radius: 6px; display: flex; align-items: center; gap: 0.5rem; }
li.active { background: var(--color-primary-bg); }
li:hover { background: var(--color-hover); }
.always-on-badge {
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.05em;
padding: 0.1rem 0.4rem;
border-radius: 3px;
background: var(--color-accent);
color: var(--color-accent-fg);
margin-left: auto;
}
.new-rulebook { margin-top: 1rem; }
.new-rulebook input {
width: 100%; margin-bottom: 0.5rem;
background: var(--color-bg); color: inherit;
border: 1px solid var(--color-border); border-radius: 6px;
padding: 0.5rem;
}
.form-buttons { display: flex; gap: 0.5rem; }
button { cursor: pointer; }
</style>