diff --git a/public/cbox/tokens/components.css b/public/cbox/tokens/components.css index 62348d5..57c3289 100644 --- a/public/cbox/tokens/components.css +++ b/public/cbox/tokens/components.css @@ -94,6 +94,12 @@ .cbx-kv { display: grid; grid-template-columns: 140px 1fr; align-items: baseline; column-gap: 24px; padding: 12px 0; border-bottom: 1px solid var(--border); } .cbx-kv:last-child { border-bottom: 0; } .cbx-kv dt { text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.6875rem; font-weight: 600; color: var(--muted-foreground); } + +/* A small section label above a grouped control (the invoice action panels use it). It was + referenced in Blade with no rule behind it, so those headings rendered as plain body text — + indistinguishable from the content beneath them. Matches the `.cbx-kv dt` treatment so the + two read as one system. */ +.cbx-label { text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.6875rem; font-weight: 600; color: var(--muted-foreground); } .cbx-kv dd { margin: 0; font-family: var(--font-mono); font-size: 13px; word-break: break-all; color: var(--foreground); } .cbx-kv dd.prose { font-family: var(--font-sans); font-size: 14px; } diff --git a/resources/views/billing/import/index.blade.php b/resources/views/billing/import/index.blade.php index 73d771a..4cc08fd 100644 --- a/resources/views/billing/import/index.blade.php +++ b/resources/views/billing/import/index.blade.php @@ -96,7 +96,7 @@ @elseif ($run->status === 'running') running @elseif ($run->status === 'failed') - failed + failed @else planned (dry-run) @endif diff --git a/resources/views/billing/import/plan.blade.php b/resources/views/billing/import/plan.blade.php index e5f5836..af02460 100644 --- a/resources/views/billing/import/plan.blade.php +++ b/resources/views/billing/import/plan.blade.php @@ -7,7 +7,7 @@ 'updated' => 'cbx-pill--info', 'skipped' => 'cbx-pill--muted', 'conflict' => 'cbx-pill--warning', - 'failed' => 'cbx-pill--danger', + 'failed' => 'cbx-pill--destructive', default => 'cbx-pill--muted', }; @endphp diff --git a/resources/views/billing/import/run.blade.php b/resources/views/billing/import/run.blade.php index d229f37..6ea0132 100644 --- a/resources/views/billing/import/run.blade.php +++ b/resources/views/billing/import/run.blade.php @@ -6,7 +6,7 @@ 'updated' => 'cbx-pill--info', 'skipped' => 'cbx-pill--muted', 'conflict' => 'cbx-pill--warning', - 'failed' => 'cbx-pill--danger', + 'failed' => 'cbx-pill--destructive', default => 'cbx-pill--muted', }; @endphp diff --git a/resources/views/billing/nexus.blade.php b/resources/views/billing/nexus.blade.php index 0f9d0de..4bed17a 100644 --- a/resources/views/billing/nexus.blade.php +++ b/resources/views/billing/nexus.blade.php @@ -33,7 +33,7 @@

Where your default selling entity has — or is approaching — a US sales-tax registration obligation. Thresholds come from the us-tax-data dataset; sales from your invoices (every currency, valued in USD) plus any external-channel sales you record below. Triggered = register now; Approaching = watch.

- {{ $triggeredCount }} triggered + {{ $triggeredCount }} triggered {{ $approachingCount }} approaching {{ $registeredCount }} registered @if ($unknownCount > 0){{ $unknownCount }} unknown@endif @@ -76,7 +76,7 @@ {{ $e->threshold?->describe() ?? '—' }} {{ $e->progress !== null ? number_format($e->progress * 100, 1).'%' : '—' }} - @if ($e->physicalPresence)presence@endif + @if ($e->physicalPresence)presence@endif @if (in_array($e->state->value, $registeredStates, true))registered@endif diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 9b789dd..69f6aac 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -164,7 +164,7 @@ class="cbx-btn cbx-btn--sm cbx-btn--ghost @if(! empty($testMode)) cbx-pill--warn @if (! empty($environments))
@include('partials.icon', ['name' => 'copy', 'size' => 13, 'sw' => 1.7])Clone -
@csrf
Clone environment config
diff --git a/tests/Feature/DesignSystemClassesTest.php b/tests/Feature/DesignSystemClassesTest.php new file mode 100644 index 0000000..a69db41 --- /dev/null +++ b/tests/Feature/DesignSystemClassesTest.php @@ -0,0 +1,143 @@ +definedClasses(); + $this->assertNotSame([], $defined, 'No cbx-* rules found — the stylesheet paths are wrong.'); + + $undefined = []; + + foreach ($this->bladeFiles() as $file) { + $contents = (string) file_get_contents($file); + + // Only `class="..."` attributes, so prose and comments mentioning a class name + // cannot trip the check. + preg_match_all('/class\s*=\s*"([^"]*)"/', $contents, $attributes); + + foreach ($attributes[1] as $attribute) { + foreach (preg_split('/\s+/', $attribute) ?: [] as $class) { + if (! str_starts_with($class, 'cbx-') || str_contains($class, '{')) { + continue; // interpolated (`{{ }}`) classes are resolved at runtime + } + + if (! in_array($class, $defined, true) && ! in_array($class, self::EXEMPT, true)) { + $undefined[$class][] = basename((string) $file); + } + } + } + } + + $this->assertSame([], $undefined, $this->describe($undefined)); + } + + /** @return list */ + private function definedClasses(): array + { + $classes = []; + + foreach (glob(public_path('cbox/**/*.css')) ?: [] as $sheet) { + preg_match_all('/\.(cbx-[A-Za-z0-9_-]+)/', (string) file_get_contents($sheet), $matches); + $classes = [...$classes, ...$matches[1]]; + } + + foreach (glob(public_path('cbox/*.css')) ?: [] as $sheet) { + preg_match_all('/\.(cbx-[A-Za-z0-9_-]+)/', (string) file_get_contents($sheet), $matches); + $classes = [...$classes, ...$matches[1]]; + } + + // Blade `