Files
FabledScribe/frontend/src/components/rules/PlanRulesPanel.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

68 lines
1.9 KiB
Vue

<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
import { getProjectApplicableRules } from "@/api/rulebooks";
import type { ApplicableRules } from "@/api/rulebooks";
const props = defineProps<{ projectId: number }>();
const data = ref<ApplicableRules | null>(null);
function grouped(rules: ApplicableRules["rules"]) {
const g: Record<string, Record<string, ApplicableRules["rules"]>> = {};
for (const r of rules) {
(g[r.rulebook_title] ??= {});
(g[r.rulebook_title][r.topic_title] ??= []).push(r);
}
return g;
}
async function load() {
data.value = await getProjectApplicableRules(props.projectId);
}
onMounted(load);
watch(() => props.projectId, load);
</script>
<template>
<section class="plan-rules" v-if="data && data.rules.length">
<h3>Applicable rules</h3>
<div v-for="(topics, rb) in grouped(data.rules)" :key="rb" class="rb">
<h4>{{ rb }}</h4>
<div v-for="(rules, topic) in topics" :key="topic">
<h5>{{ topic }}</h5>
<ul>
<li v-for="r in rules" :key="r.id">
<strong>{{ r.title }}</strong> {{ r.statement }}
</li>
</ul>
</div>
</div>
<p v-if="data.truncated" class="truncated">
Truncated at 50 rules more apply.
</p>
</section>
</template>
<style scoped>
.plan-rules {
margin-top: 1.5rem;
border-top: 1px solid var(--color-border);
padding-top: 1rem;
}
.plan-rules h3 {
font-size: 0.9em; opacity: 0.7;
text-transform: uppercase; letter-spacing: 0.05em;
}
.rb h4 { font-family: Fraunces, serif; font-style: italic; margin-bottom: 0.25rem; }
.rb h5 {
font-size: 0.8em; opacity: 0.7;
text-transform: uppercase; margin-top: 0.5rem;
}
.plan-rules ul {
list-style: none; padding-left: 0.75rem; margin: 0.25rem 0;
border-left: 2px solid var(--color-primary);
}
.plan-rules li { margin: 0.35rem 0; font-size: 0.92em; }
.truncated { opacity: 0.7; font-style: italic; font-size: 0.85em; }
</style>