diff --git a/blocks/project_ledger.ninjatpl b/blocks/project_ledger.ninjatpl index 3ec9641..0804c39 100644 --- a/blocks/project_ledger.ninjatpl +++ b/blocks/project_ledger.ninjatpl @@ -1,3 +1,6 @@ -
+
+
+ {% if heading %}

{{ heading }}

{% endif %} {% if not rows %}

No projects listed.

{% else %}
    {% for row in rows %}
  1. {{ row.no }}{{ row.year }}{% if row.link %}{{ row.client }}{% else %}{{ row.client }}{% endif %}{{ row.role }}{% if row.link %}{% endif %}
  2. {% endfor %}
{% endif %} +
diff --git a/blocks/project_ledger.schema.json b/blocks/project_ledger.schema.json index 8114f10..14b9359 100644 --- a/blocks/project_ledger.schema.json +++ b/blocks/project_ledger.schema.json @@ -4,6 +4,12 @@ "description": "Ordered project list on a 12-col grid: number, year, client, role, link", "type": "object", "properties": { + "heading": { + "type": "string", + "title": "Heading", + "description": "Optional section heading shown above the ledger", + "x-editor": "text" + }, "rows": { "type": "array", "title": "Rows", diff --git a/manifest.yaml b/manifest.yaml index fcfce4a..04aa175 100644 --- a/manifest.yaml +++ b/manifest.yaml @@ -475,8 +475,8 @@ css: via hsl(var(--token)); all type via var(--font-*). ============================================================ */ - .bru-section { padding: 4rem 0; } - @media (min-width: 768px) { .bru-section { padding: 6rem 0; } } + .bru-section { padding: 2.75rem 0; } + @media (min-width: 768px) { .bru-section { padding: 4rem 0; } } .bru-wrap { width: 100%; max-width: 80rem; margin: 0 auto; padding: 0 1.5rem; } .bru-wrap-mid { width: 100%; max-width: 64rem; margin: 0 auto; padding: 0 1.5rem; } .bru-wrap-narrow { width: 100%; max-width: 44rem; margin: 0 auto; padding: 0 1.5rem; } @@ -647,3 +647,120 @@ css: .bru-spec-row dt { text-transform: uppercase; color: hsl(var(--muted-foreground)); } .bru-spec-row dd { margin: 0; text-align: right; color: hsl(var(--foreground)); } + /* ============================================================ + LAYOUT GUARANTEE LAYER — the host's public CSS is a render-driven + JIT built with `@import "tailwindcss" source(none)`. A codeless + theme installs to data/plugins, which is NOT in any @source glob, + so its .ninjatpl utility classes only reach the compiled CSS if a + built-in template emits the exact string or the class is in the + host safelist. These families are NOT safelisted and were silently + dropping on a fresh provision (collapsed grids, zero padding, + touching items): grid-cols-{1,2,4,5}, every responsive grid + variant, col-span-*, the p-* shorthand, gap-{3..12}/gap-x/gap-y, + space-y-*, columns-*, aspect-*, object-*, w/h-full. Define them + here (input_css_append is compiled UNCONDITIONALLY) so every block + lays out deterministically on desktop AND collapses on mobile. + Scoped to .brutalist-page; structural only — no colours. Values + mirror Tailwind's defaults so any host-compiled copy is identical. + ============================================================ */ + + .brutalist-page .grid { display: grid; } + .brutalist-page .grid-cols-1 { grid-template-columns: repeat(1, minmax(0, 1fr)); } + .brutalist-page .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .brutalist-page .grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .brutalist-page .grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } + .brutalist-page .grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } + .brutalist-page .col-span-2 { grid-column: span 2 / span 2; } + .brutalist-page .col-span-3 { grid-column: span 3 / span 3; } + .brutalist-page .columns-2 { columns: 2; } + + /* Padding shorthand (px-*/py-* are safelisted; p-* is not). */ + .brutalist-page .p-0 { padding: 0; } + .brutalist-page .p-1 { padding: 0.25rem; } + .brutalist-page .p-2 { padding: 0.5rem; } + .brutalist-page .p-3 { padding: 0.75rem; } + .brutalist-page .p-4 { padding: 1rem; } + .brutalist-page .p-5 { padding: 1.25rem; } + .brutalist-page .p-6 { padding: 1.5rem; } + .brutalist-page .p-8 { padding: 2rem; } + .brutalist-page .p-16 { padding: 4rem; } + + /* Gaps (only gap-1/1.5/2 are safelisted). */ + .brutalist-page .gap-0 { gap: 0; } + .brutalist-page .gap-3 { gap: 0.75rem; } + .brutalist-page .gap-4 { gap: 1rem; } + .brutalist-page .gap-5 { gap: 1.25rem; } + .brutalist-page .gap-6 { gap: 1.5rem; } + .brutalist-page .gap-8 { gap: 2rem; } + .brutalist-page .gap-10 { gap: 2.5rem; } + .brutalist-page .gap-12 { gap: 3rem; } + .brutalist-page .gap-x-2 { column-gap: 0.5rem; } + .brutalist-page .gap-x-3 { column-gap: 0.75rem; } + .brutalist-page .gap-x-4 { column-gap: 1rem; } + .brutalist-page .gap-x-10 { column-gap: 2.5rem; } + .brutalist-page .gap-y-1 { row-gap: 0.25rem; } + .brutalist-page .gap-y-2 { row-gap: 0.5rem; } + .brutalist-page .gap-y-6 { row-gap: 1.5rem; } + + /* Vertical rhythm (space-y-*). */ + .brutalist-page .space-y-0 > * + * { margin-top: 0; } + .brutalist-page .space-y-1 > * + * { margin-top: 0.25rem; } + .brutalist-page .space-y-2 > * + * { margin-top: 0.5rem; } + .brutalist-page .space-y-3 > * + * { margin-top: 0.75rem; } + .brutalist-page .space-y-4 > * + * { margin-top: 1rem; } + .brutalist-page .space-y-5 > * + * { margin-top: 1.25rem; } + .brutalist-page .space-y-6 > * + * { margin-top: 1.5rem; } + .brutalist-page .space-y-8 > * + * { margin-top: 2rem; } + .brutalist-page .space-y-10 > * + * { margin-top: 2.5rem; } + .brutalist-page .space-y-12 > * + * { margin-top: 3rem; } + + /* Sizing used for media fill + logos. */ + .brutalist-page .w-full { width: 100%; } + .brutalist-page .h-full { height: 100%; } + .brutalist-page .w-auto { width: auto; } + .brutalist-page .h-auto { height: auto; } + + /* Media boxes: a fixed aspect ratio so ABSENT/empty media can never + balloon into a tall empty box — it stays a compact bordered tile. */ + .brutalist-page .aspect-video { aspect-ratio: 16 / 9; } + .brutalist-page .aspect-square { aspect-ratio: 1 / 1; } + .brutalist-page .aspect-\[3\/4\] { aspect-ratio: 3 / 4; } + .brutalist-page .aspect-\[4\/3\] { aspect-ratio: 4 / 3; } + .brutalist-page .aspect-\[21\/9\] { aspect-ratio: 21 / 9; } + .brutalist-page .object-cover { object-fit: cover; } + .brutalist-page .object-contain { object-fit: contain; } + .brutalist-page .object-fill { object-fit: fill; } + .brutalist-page img { max-width: 100%; } + + @media (min-width: 640px) { + .brutalist-page .sm\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .brutalist-page .sm\:col-span-1 { grid-column: span 1 / span 1; } + .brutalist-page .sm\:col-span-2 { grid-column: span 2 / span 2; } + .brutalist-page .sm\:gap-6 { gap: 1.5rem; } + } + @media (min-width: 768px) { + .brutalist-page .md\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .brutalist-page .md\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .brutalist-page .md\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } + .brutalist-page .md\:col-span-3 { grid-column: span 3 / span 3; } + .brutalist-page .md\:columns-2 { columns: 2; } + .brutalist-page .md\:columns-3 { columns: 3; } + .brutalist-page .md\:columns-4 { columns: 4; } + .brutalist-page .md\:gap-16 { gap: 4rem; } + .brutalist-page .md\:p-6 { padding: 1.5rem; } + .brutalist-page .md\:p-8 { padding: 2rem; } + .brutalist-page .md\:p-14 { padding: 3.5rem; } + .brutalist-page .md\:px-10 { padding-left: 2.5rem; padding-right: 2.5rem; } + .brutalist-page .md\:py-14 { padding-top: 3.5rem; padding-bottom: 3.5rem; } + .brutalist-page .md\:py-16 { padding-top: 4rem; padding-bottom: 4rem; } + } + @media (min-width: 1024px) { + .brutalist-page .lg\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .brutalist-page .lg\:grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } + .brutalist-page .lg\:grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); } + .brutalist-page .lg\:grid-cols-5 { grid-template-columns: repeat(5, minmax(0, 1fr)); } + .brutalist-page .lg\:col-span-1 { grid-column: span 1 / span 1; } + .brutalist-page .lg\:col-span-2 { grid-column: span 2 / span 2; } + .brutalist-page .lg\:col-span-3 { grid-column: span 3 / span 3; } + } + diff --git a/templates/overrides/brutalist/image.ninjatpl b/templates/overrides/brutalist/image.ninjatpl index 6e75b61..dcf712f 100644 --- a/templates/overrides/brutalist/image.ninjatpl +++ b/templates/overrides/brutalist/image.ninjatpl @@ -1,2 +1,2 @@ {# brutalist image override — hard-bordered figure, mono caption. Fields: src, alt, size, align, aspectRatio, objectFit, caption. Rounding is killed page-wide. #} -{% with size=size|default:"full" align=align|default:"center" aspectRatio=aspectRatio|default:"auto" objectFit=objectFit|default:"cover" %}
{% if objectFit == "contain" %}{% img src alt=alt class="w-full h-full object-contain" layout=size %}{% elif objectFit == "fill" %}{% img src alt=alt class="w-full h-full object-fill" layout=size %}{% else %}{% img src alt=alt class="w-full h-full object-cover" layout=size %}{% endif %}
{% if caption %}
{{ caption }}
{% endif %}
{% endwith %} +{% with size=size|default:"full" align=align|default:"center" aspectRatio=aspectRatio|default:"auto" objectFit=objectFit|default:"cover" %}{% if src %}
{% if objectFit == "contain" %}{% img src alt=alt class="w-full h-full object-contain" layout=size %}{% elif objectFit == "fill" %}{% img src alt=alt class="w-full h-full object-fill" layout=size %}{% else %}{% img src alt=alt class="w-full h-full object-cover" layout=size %}{% endif %}
{% if caption %}
{{ caption }}
{% endif %}
{% endif %}{% endwith %} diff --git a/templates/overrides/brutalist/navbar.ninjatpl b/templates/overrides/brutalist/navbar.ninjatpl index 6902819..2024809 100644 --- a/templates/overrides/brutalist/navbar.ninjatpl +++ b/templates/overrides/brutalist/navbar.ninjatpl @@ -23,8 +23,13 @@