Commit093650daRecorded29 Mar 2026Repositorysigil-web-styles

Initial implementation of sigil-web-styles design system

Message

Palette, typography, components, layout modules with default black+gold theme. Includes card, table, badge, status, button, nav, form, code block, log viewer, and ANSI color components. All styles use CSS custom properties for palette swapping.

Changed
 demo/preview.sgl                    | 123 ++++++++++++++++++++++++++++++++++++++++++++++++
 dev-redirects.sgl                   |   6 +++
 package.sgl                         |  29 ++++++++++++
 src/sigil/web/styles.sgl            |  88 +++++++++++++++++++++++++++++++++++
 src/sigil/web/styles/components.sgl | 399 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/sigil/web/styles/layout.sgl     | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/sigil/web/styles/palette.sgl    |  94 +++++++++++++++++++++++++++++++++++++
 src/sigil/web/styles/typography.sgl |  70 ++++++++++++++++++++++++++++
 test/test-styles.sgl                | 133 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 1085 insertions(+)
Diff
demo/preview.sgladded
@@ -0,0 +1,123 @@
+1
;;; Demo/preview page showing all sigil-web-styles components.
+2
;;;
+3
;;; Run with: sigil -L build/dev/lib eval -f demo/preview.sgl
+4
+5
(import (sigil core)
+6
(sigil io)
+7
(sigil web styles))
+8
+9
(define css (theme-stylesheet))
+10
+11
(define html-1 (string-append
+12
"<!DOCTYPE html><html><head>"
+13
"<meta charset='utf-8'>"
+14
"<meta name='viewport' content='width=device-width, initial-scale=1'>"
+15
"<title>sigil-web-styles Preview</title>"
+16
"<style>" css "</style>"
+17
"</head><body>"
+18
"<header class='header'>"
+19
"<a href='/' class='header-logo'>sigil-web-styles</a>"
+20
"<nav class='header-nav'><a href='#'>Dashboard</a></nav>"
+21
"</header>"
+22
"<main class='main'>"
+23
"<h1 class='page-title'>Component Preview</h1>"))
+24
+25
(define html-2 (string-append
+26
"<section style='margin-bottom:2rem'><h2>Typography</h2>"
+27
"<h1>Heading 1</h1><h2>Heading 2</h2><h3>Heading 3</h3>"
+28
"<p>Body text with <a href='#'>a link</a> and <code>inline code</code>.</p>"
+29
"<small>Small text</small>"
+30
"<p class='text-caption'>Caption text</p>"
+31
"<p class='mono'>Monospace text</p></section>"
+32
"<section style='margin-bottom:2rem'><h2>Buttons</h2>"
+33
"<a class='btn btn-primary' href='#'>Primary</a> "
+34
"<a class='btn btn-secondary' href='#'>Secondary</a></section>"
+35
"<section style='margin-bottom:2rem'><h2>Badges &amp; Status</h2>"
+36
"<p><span class='status status-up'>up</span> "
+37
"<span class='status status-down'>down</span> "
+38
"<span class='status status-degraded'>degraded</span> "
+39
"<span class='status status-passed'>passed</span> "
+40
"<span class='status status-failed'>failed</span> "
+41
"<span class='status status-running'>running</span> "
+42
"<span class='status status-pending'>pending</span></p>"
+43
"<p style='margin-top:1rem'>Dots: "
+44
"<span class='status-dot dot-up'></span> "
+45
"<span class='status-dot dot-down'></span> "
+46
"<span class='status-dot dot-degraded'></span> "
+47
"<span class='status-dot'></span></p>"
+48
"<p style='margin-top:1rem'>"
+49
"<span class='status-badge status-up'>UP</span> "
+50
"<span class='status-badge status-down'>DOWN</span> "
+51
"<span class='status-badge status-degraded'>DEGRADED</span></p>"
+52
"</section>"))
+53
+54
(define html-3 (string-append
+55
"<section style='margin-bottom:2rem'><h2>Cards</h2>"
+56
"<div class='grid'>"
+57
"<div class='card card-accent accent-success'>"
+58
"<div style='font-weight:600'>Service A</div>"
+59
"<div style='color:var(--color-text-muted)'><span class='status-dot dot-up'></span> up</div>"
+60
"</div>"
+61
"<div class='card card-accent accent-error'>"
+62
"<div style='font-weight:600'>Service B</div>"
+63
"<div style='color:var(--color-text-muted)'><span class='status-dot dot-down'></span> down</div>"
+64
"</div>"
+65
"<div class='card card-accent accent-warning'>"
+66
"<div style='font-weight:600'>Service C</div>"
+67
"<div style='color:var(--color-text-muted)'><span class='status-dot dot-degraded'></span> degraded</div>"
+68
"</div></div></section>"
+69
"<section style='margin-bottom:2rem'><h2>Status Panel</h2>"
+70
"<div class='status-panel'>"
+71
"<span class='status-badge status-up'>UP</span>"
+72
"<div class='status-details'>"
+73
"<div>Uptime: 99.9%</div><div>Latency: 12ms</div>"
+74
"</div></div></section>"))
+75
+76
(define html-4 (string-append
+77
"<section style='margin-bottom:2rem'><h2>Table</h2>"
+78
"<table class='table'><thead>"
+79
"<tr><th>Job</th><th>Branch</th><th>Status</th><th>Duration</th></tr>"
+80
"</thead><tbody>"
+81
"<tr><td>build-sigil</td><td>master</td>"
+82
"<td><span class='status status-passed'>passed</span></td><td>2m 15s</td></tr>"
+83
"<tr><td>test-web</td><td>master</td>"
+84
"<td><span class='status status-failed'>failed</span></td><td>1m 42s</td></tr>"
+85
"<tr><td>deploy</td><td>master</td>"
+86
"<td><span class='status status-running'>running</span></td><td>running...</td></tr>"
+87
"</tbody></table></section>"
+88
"<section style='margin-bottom:2rem'><h2>Form Inputs</h2>"
+89
"<div style='max-width:400px'>"
+90
"<label>Text Input</label>"
+91
"<input type='text' placeholder='Enter value...' style='width:100%;margin-bottom:1rem'>"
+92
"<label>Textarea</label>"
+93
"<textarea rows='3' style='width:100%' placeholder='Enter text...'></textarea>"
+94
"</div></section>"))
+95
+96
(define html-5 (string-append
+97
"<section style='margin-bottom:2rem'><h2>Log Viewer</h2>"
+98
"<div class='log-viewer'>"
+99
"<div class='log-line'><span class='log-seq'>1</span>"
+100
"<span class='a-green'>==></span> Building...</div>"
+101
"<div class='log-line'><span class='log-seq'>2</span>"
+102
" <span class='a-cyan'>COMPILE</span> palette.sgl</div>"
+103
"<div class='log-line'><span class='log-seq'>3</span>"
+104
" <span class='a-cyan'>COMPILE</span> components.sgl</div>"
+105
"<div class='log-line log-line-stderr'><span class='log-seq'>4</span>"
+106
"<span class='a-red'>ERROR:</span> something went wrong</div>"
+107
"<div class='log-line'><span class='log-seq'>5</span>"
+108
"<span class='a-green'>Build complete!</span></div>"
+109
"</div></section>"
+110
"</main>"
+111
"<footer class='footer'>"
+112
"Crafted with <a href='https://usesigil.org'>Sigil</a>"
+113
"</footer></body></html>"))
+114
+115
(let ((port (open-output-file "demo/preview.html")))
+116
(display html-1 port)
+117
(display html-2 port)
+118
(display html-3 port)
+119
(display html-4 port)
+120
(display html-5 port)
+121
(close-port port))
+122
+123
(display "Preview written to demo/preview.html\n")
dev-redirects.sgladded
@@ -0,0 +1,6 @@
+1
;; Local development redirects
+2
(redirects
+3
repos: (list
+4
(for-repo
+5
url: "codeberg:sigil/sigil"
+6
use: (from-path dir: "../sigil"))))
package.sgladded
@@ -0,0 +1,29 @@
+1
;;; sigil-web-styles - Design system and theme library for Sigil web apps
+2
;;;
+3
;;; Provides palettes, typography, component styles, and layouts that give
+4
;;; Sigil web apps a consistent look with customizable color themes.
+5
+6
(define sigil-repo "codeberg:sigil/sigil#56f620e6")
+7
+8
(package
+9
name: "sigil-web-styles"
+10
version: "0.1.0"
+11
description: "Design system and theme library for Sigil web apps"
+12
url: "https://codeberg.org/sigil/sigil-web-styles"
+13
license: "BSD-3-Clause"
+14
authors: (list "David Wilson <[email protected]>")
+15
+16
dependencies: (list
+17
(from-git url: sigil-repo package: "sigil-stdlib")
+18
(from-git url: sigil-repo package: "sigil-css"))
+19
+20
dev-dependencies: (list
+21
(from-git url: sigil-repo package: "sigil-test"))
+22
+23
tasks: (list
+24
(task
+25
name: 'build
+26
description: "Compile sigil-web-styles modules"
+27
steps: (list
+28
(compile-sigil-modules sources: "src/**/*.sgl"
+29
output-dir: (config-output-subdir "lib"))))))
src/sigil/web/styles.sgladded
@@ -0,0 +1,88 @@
+1
;;; (sigil web styles) - Design system for Sigil web apps.
+2
;;;
+3
;;; Main entry point. Re-exports palette, typography, components, and layout.
+4
;;; Use `theme-stylesheet` to generate a complete CSS string for an app.
+5
;;;
+6
;;; ## Basic Usage
+7
;;;
+8
;;; ```scheme
+9
;;; (import (sigil web styles))
+10
;;; (theme-stylesheet) ;; default black+gold
+11
;;; (theme-stylesheet palette: my-custom-palette) ;; custom colors
+12
;;; ```
+13
+14
(define-library (sigil web styles)
+15
(import (sigil core)
+16
(sigil css)
+17
(sigil web styles palette)
+18
(sigil web styles typography)
+19
(sigil web styles components)
+20
(sigil web styles layout))
+21
+22
(export
+23
;; Main API
+24
theme-stylesheet
+25
+26
;; Palette
+27
make-palette
+28
default-palette
+29
palette-background
+30
palette-surface
+31
palette-surface-hover
+32
palette-primary
+33
palette-primary-hover
+34
palette-text
+35
palette-text-muted
+36
palette-border
+37
palette-success
+38
palette-warning
+39
palette-error
+40
palette->css-vars
+41
+42
;; Typography
+43
font-family-sans
+44
font-family-mono
+45
typography-styles
+46
+47
;; Components
+48
card-styles
+49
table-styles
+50
badge-styles
+51
status-styles
+52
button-styles
+53
nav-styles
+54
form-styles
+55
code-styles
+56
log-viewer-styles
+57
empty-state-styles
+58
ansi-color-styles
+59
+60
;; Layout
+61
reset-styles
+62
layout-styles
+63
footer-styles
+64
grid-styles)
+65
+66
(begin
+67
+68
(define (theme-stylesheet (keys: (palette default-palette)))
+69
(css->string
+70
(palette->css-vars palette)
+71
(reset-styles)
+72
(typography-styles)
+73
(nav-styles)
+74
(layout-styles)
+75
(footer-styles)
+76
(grid-styles)
+77
(card-styles)
+78
(table-styles)
+79
(badge-styles)
+80
(status-styles)
+81
(button-styles)
+82
(form-styles)
+83
(code-styles)
+84
(log-viewer-styles)
+85
(empty-state-styles)
+86
(ansi-color-styles)))
+87
+88
))
src/sigil/web/styles/components.sgladded
@@ -0,0 +1,399 @@
+1
;;; (sigil web styles components) - Styled UI components.
+2
;;;
+3
;;; Each function returns sigil-css rules using CSS custom properties
+4
;;; from the palette. Components include cards, tables, badges, buttons,
+5
;;; nav bar, form inputs, code blocks, status indicators, and log viewer.
+6
+7
(define-library (sigil web styles components)
+8
(import (sigil core)
+9
(sigil string)
+10
(sigil css)
+11
(sigil web styles typography))
+12
+13
(export card-styles
+14
table-styles
+15
badge-styles
+16
status-styles
+17
button-styles
+18
nav-styles
+19
form-styles
+20
code-styles
+21
log-viewer-styles
+22
empty-state-styles
+23
ansi-color-styles)
+24
+25
(begin
+26
+27
;; ============================================================
+28
;; Cards
+29
;; ============================================================
+30
+31
(define (card-styles)
+32
(css-combine
+33
(css ".card"
+34
(background "linear-gradient(180deg, var(--color-surface) 0%, #141414 100%)")
+35
(border "1px solid var(--color-border)")
+36
(border-radius "0.5rem")
+37
(padding "1.25rem")
+38
(box-shadow "inset 0 1px 0 rgba(255,255,255,0.03)")
+39
(transition "transform 0.15s, box-shadow 0.15s")
+40
(color "var(--color-text)")
+41
(text-decoration "none")
+42
(display "block")
+43
(& ":hover"
+44
(transform "translateY(-2px)")
+45
(box-shadow "0 4px 12px rgba(0,0,0,0.4)")))
+46
+47
;; Card with left accent border (for status cards)
+48
(css ".card-accent"
+49
(border-left "4px solid var(--color-text-muted)"))
+50
+51
(css ".card-accent.accent-success"
+52
(border-left-color "var(--color-success)"))
+53
(css ".card-accent.accent-error"
+54
(border-left-color "var(--color-error)"))
+55
(css ".card-accent.accent-warning"
+56
(border-left-color "var(--color-warning)"))
+57
(css ".card-accent.accent-primary"
+58
(border-left-color "var(--color-primary)"))))
+59
+60
;; ============================================================
+61
;; Tables
+62
;; ============================================================
+63
+64
(define (table-styles)
+65
(css-combine
+66
(css ".table"
+67
(width "100%")
+68
(border-collapse "collapse"))
+69
+70
(css ".table th"
+71
(text-align "left")
+72
(padding "0.5rem 0.75rem")
+73
(border-bottom "1px solid var(--color-border)")
+74
(color "var(--color-text-muted)")
+75
(font-size "0.8rem")
+76
(text-transform "uppercase")
+77
(letter-spacing "0.05em")
+78
(font-weight "500"))
+79
+80
(css ".table td"
+81
(padding "0.5rem 0.75rem")
+82
(border-bottom "1px solid var(--color-border)"))
+83
+84
(css ".table tr"
+85
(cursor "pointer")
+86
(& ":hover td"
+87
(background "var(--color-surface-hover)")))
+88
+89
(css ".table tr td a"
+90
(color "inherit"))
+91
+92
(css ".table tr td a.row-link"
+93
(display "block")
+94
(text-decoration "none"))))
+95
+96
;; ============================================================
+97
;; Badges / Status indicators
+98
;; ============================================================
+99
+100
(define (badge-styles)
+101
(css-combine
+102
(css ".badge"
+103
(display "inline-block")
+104
(padding "0.125rem 0.5rem")
+105
(border-radius "4px")
+106
(font-size "0.8rem")
+107
(font-weight "500"))
+108
+109
(css ".badge-success"
+110
(background "#052e16")
+111
(color "var(--color-success)"))
+112
(css ".badge-error"
+113
(background "#2d0a0a")
+114
(color "var(--color-error)"))
+115
(css ".badge-warning"
+116
(background "#1a1500")
+117
(color "var(--color-warning)"))
+118
(css ".badge-primary"
+119
(background "#1a1200")
+120
(color "var(--color-primary)"))
+121
(css ".badge-muted"
+122
(background "var(--color-surface)")
+123
(color "var(--color-text-muted)"))))
+124
+125
;; Status-specific badges (for Vigil/Kiln status states)
+126
(define (status-styles)
+127
(css-combine
+128
(css ".status"
+129
(display "inline-block")
+130
(padding "0.125rem 0.5rem")
+131
(border-radius "4px")
+132
(font-size "0.8rem")
+133
(font-weight "500"))
+134
+135
;; Vigil statuses
+136
(css ".status-up"
+137
(background "#052e16")
+138
(color "var(--color-success)"))
+139
(css ".status-down"
+140
(background "#2d0a0a")
+141
(color "var(--color-error)"))
+142
(css ".status-degraded"
+143
(background "#1a1500")
+144
(color "var(--color-warning)"))
+145
(css ".status-unknown"
+146
(background "var(--color-surface)")
+147
(color "var(--color-text-muted)"))
+148
+149
;; Kiln statuses
+150
(css ".status-passed"
+151
(background "#052e16")
+152
(color "var(--color-success)"))
+153
(css ".status-failed"
+154
(background "#2d0a0a")
+155
(color "var(--color-error)"))
+156
(css ".status-errored"
+157
(background "#1a0d00")
+158
(color "var(--color-warning)"))
+159
(css ".status-running"
+160
(background "#1a1200")
+161
(color "var(--color-primary)")
+162
(animation "pulse 2s infinite"))
+163
(css ".status-starting"
+164
(background "#0d1a1a")
+165
(color "#5eead4")
+166
(animation "pulse 2s infinite"))
+167
(css (css-sel ".status-pending" ".status-waiting")
+168
(background "var(--color-surface)")
+169
(color "var(--color-text-muted)"))
+170
(css (css-sel ".status-skipped" ".status-cancelled")
+171
(background "var(--color-surface)")
+172
(color "var(--color-text-muted)"))
+173
+174
(css-keyframes "pulse"
+175
(from (opacity "1"))
+176
(|50%| (opacity "0.6"))
+177
(to (opacity "1")))
+178
+179
;; Status dot (small circular indicator)
+180
(css ".status-dot"
+181
(display "inline-block")
+182
(width "8px")
+183
(height "8px")
+184
(border-radius "50%")
+185
(background "var(--color-text-muted)"))
+186
+187
(css ".dot-up, .status-up .status-dot"
+188
(background "var(--color-success)"))
+189
(css ".dot-down, .status-down .status-dot"
+190
(background "var(--color-error)"))
+191
(css ".dot-degraded, .status-degraded .status-dot"
+192
(background "var(--color-warning)"))
+193
+194
;; Status badge (larger, for detail pages)
+195
(css ".status-badge"
+196
(display "inline-block")
+197
(padding "0.5rem 1.25rem")
+198
(border-radius "0.25rem")
+199
(font-weight "600")
+200
(text-transform "uppercase")
+201
(font-size "0.875rem"))
+202
+203
(css ".status-badge.status-up"
+204
(background "var(--color-success)")
+205
(color "#000"))
+206
(css ".status-badge.status-down"
+207
(background "var(--color-error)")
+208
(color "#fff"))
+209
(css ".status-badge.status-degraded"
+210
(background "var(--color-warning)")
+211
(color "#000"))
+212
(css ".status-badge.status-unknown"
+213
(background "var(--color-text-muted)")
+214
(color "#fff"))))
+215
+216
;; ============================================================
+217
;; Buttons
+218
;; ============================================================
+219
+220
(define (button-styles)
+221
(css-combine
+222
(css ".btn"
+223
(display "inline-block")
+224
(padding "0.5rem 1.25rem")
+225
(border "none")
+226
(border-radius "0.375rem")
+227
(font-size "0.875rem")
+228
(font-weight "600")
+229
(cursor "pointer")
+230
(text-decoration "none")
+231
(transition "background 0.15s, transform 0.1s"))
+232
+233
(css ".btn-primary"
+234
(background "linear-gradient(180deg, var(--color-primary) 0%, var(--color-primary-hover) 100%)")
+235
(color "#000")
+236
(box-shadow "inset 0 1px 0 rgba(255,255,255,0.15)")
+237
(& ":hover"
+238
(background "var(--color-primary-hover)"))
+239
(& ":active"
+240
(transform "translateY(1px)")))
+241
+242
(css ".btn-secondary"
+243
(background "var(--color-surface)")
+244
(color "var(--color-text)")
+245
(border "1px solid var(--color-border)")
+246
(& ":hover"
+247
(background "var(--color-surface-hover)")))))
+248
+249
;; ============================================================
+250
;; Navigation
+251
;; ============================================================
+252
+253
(define (nav-styles)
+254
(css-combine
+255
(css ".header"
+256
(background "var(--color-surface)")
+257
(border-bottom "1px solid var(--color-border)")
+258
(padding "0.75rem 1.5rem")
+259
(display "flex")
+260
(align-items "center")
+261
(gap "1.5rem"))
+262
+263
(css ".header-logo"
+264
(font-size "1.25rem")
+265
(font-weight "700")
+266
(letter-spacing "-0.02em")
+267
(color "var(--color-primary)")
+268
(text-decoration "none"))
+269
+270
(css ".header-nav a"
+271
(color "var(--color-text-muted)")
+272
(text-decoration "none")
+273
(& ":hover"
+274
(color "var(--color-text)")))))
+275
+276
;; ============================================================
+277
;; Form Inputs
+278
;; ============================================================
+279
+280
(define (form-styles)
+281
(css-combine
+282
(css "input, textarea, select"
+283
(background "var(--color-bg)")
+284
(color "var(--color-text)")
+285
(border "1px solid var(--color-border)")
+286
(border-radius "0.375rem")
+287
(padding "0.5rem 0.75rem")
+288
(font-size "0.875rem")
+289
(font-family "inherit")
+290
(box-shadow "inset 0 1px 2px rgba(0,0,0,0.3)")
+291
(transition "border-color 0.15s, box-shadow 0.15s")
+292
(& ":focus"
+293
(outline "none")
+294
(border-color "var(--color-primary)")
+295
(box-shadow "0 0 0 2px rgba(212,160,23,0.25)")))
+296
+297
(css "label"
+298
(display "block")
+299
(font-size "0.875rem")
+300
(font-weight "500")
+301
(margin-bottom "0.25rem")
+302
(color "var(--color-text-muted)"))))
+303
+304
;; ============================================================
+305
;; Code Blocks
+306
;; ============================================================
+307
+308
(define (code-styles)
+309
(css-combine
+310
(css "pre"
+311
(background "#000")
+312
(border "1px solid var(--color-border)")
+313
(border-radius "6px")
+314
(padding "1rem")
+315
(overflow-x "auto")
+316
(font-family font-family-mono)
+317
(font-size "0.8rem")
+318
(line-height "1.7"))
+319
+320
(css "code"
+321
(font-family font-family-mono)
+322
(font-size "0.875rem"))
+323
+324
(css ":not(pre) > code"
+325
(background "var(--color-surface)")
+326
(padding "0.125rem 0.375rem")
+327
(border-radius "3px"))))
+328
+329
;; ============================================================
+330
;; Log Viewer (for Kiln-style build logs)
+331
;; ============================================================
+332
+333
(define (log-viewer-styles)
+334
(css-combine
+335
(css ".log-viewer"
+336
(background "#000")
+337
(border "1px solid var(--color-border)")
+338
(border-radius "6px")
+339
(padding "1rem")
+340
(overflow-x "auto")
+341
(font-family font-family-mono)
+342
(font-size "0.8rem")
+343
(line-height "1.7")
+344
(max-height "70vh")
+345
(overflow-y "auto"))
+346
+347
(css ".log-line"
+348
(white-space "pre")
+349
(color "var(--color-text-muted)"))
+350
+351
(css ".log-line-stderr"
+352
(color "var(--color-error)"))
+353
+354
(css ".log-seq"
+355
(color "var(--color-text-muted)")
+356
(user-select "none")
+357
(margin-right "1rem")
+358
(min-width "3ch")
+359
(display "inline-block")
+360
(text-align "right"))))
+361
+362
;; ============================================================
+363
;; Empty State
+364
;; ============================================================
+365
+366
(define (empty-state-styles)
+367
(css ".empty"
+368
(text-align "center")
+369
(padding "3rem")
+370
(color "var(--color-text-muted)")))
+371
+372
;; ============================================================
+373
;; ANSI Terminal Colors
+374
;; ============================================================
+375
+376
(define (ansi-color-styles)
+377
(css-combine
+378
(css ".a-bold" (font-weight "bold"))
+379
(css ".a-dim" (opacity "0.6"))
+380
(css ".a-italic" (font-style "italic"))
+381
(css ".a-underline" (text-decoration "underline"))
+382
(css ".a-black" (color "#555"))
+383
(css ".a-red" (color "var(--color-error)"))
+384
(css ".a-green" (color "var(--color-success)"))
+385
(css ".a-yellow" (color "var(--color-primary)"))
+386
(css ".a-blue" (color "#60a5fa"))
+387
(css ".a-magenta" (color "#c084fc"))
+388
(css ".a-cyan" (color "#22d3ee"))
+389
(css ".a-white" (color "var(--color-text)"))
+390
(css ".a-bright-black" (color "var(--color-text-muted)"))
+391
(css ".a-bright-red" (color "#f87171"))
+392
(css ".a-bright-green" (color "#4ade80"))
+393
(css ".a-bright-yellow" (color "#fde047"))
+394
(css ".a-bright-blue" (color "#93c5fd"))
+395
(css ".a-bright-magenta" (color "#d8b4fe"))
+396
(css ".a-bright-cyan" (color "#67e8f9"))
+397
(css ".a-bright-white" (color "#fff"))))
+398
+399
))
src/sigil/web/styles/layout.sgladded
@@ -0,0 +1,143 @@
+1
;;; (sigil web styles layout) - Page structure and responsive layout.
+2
;;;
+3
;;; Page shell (header, main, footer), grid system for card layouts,
+4
;;; responsive breakpoints, and container widths.
+5
+6
(define-library (sigil web styles layout)
+7
(import (sigil core)
+8
(sigil css))
+9
+10
(export reset-styles
+11
layout-styles
+12
footer-styles
+13
grid-styles)
+14
+15
(begin
+16
+17
;; ============================================================
+18
;; Reset
+19
;; ============================================================
+20
+21
(define (reset-styles)
+22
(css "*"
+23
(margin "0")
+24
(padding "0")
+25
(box-sizing "border-box")))
+26
+27
;; ============================================================
+28
;; Page Layout
+29
;; ============================================================
+30
+31
(define (layout-styles)
+32
(css-combine
+33
(css ".main"
+34
(max-width "1200px")
+35
(margin "0 auto")
+36
(padding "1.5rem"))
+37
+38
(css ".main-narrow"
+39
(max-width "960px")
+40
(margin "0 auto")
+41
(padding "1.5rem"))
+42
+43
(css ".page-title"
+44
(font-size "1.5rem")
+45
(margin-bottom "1rem")
+46
(color "var(--color-text)"))
+47
+48
;; Status panel (detail pages)
+49
(css ".status-panel"
+50
(display "flex")
+51
(align-items "center")
+52
(gap "2rem")
+53
(margin-bottom "2rem")
+54
(padding "1.5rem")
+55
(background "linear-gradient(180deg, var(--color-surface) 0%, #141414 100%)")
+56
(border-radius "0.5rem")
+57
(box-shadow "inset 0 1px 0 rgba(255,255,255,0.03)"))
+58
+59
(css ".status-details"
+60
(color "var(--color-text-muted)")
+61
(font-size "0.9rem")
+62
(& " div"
+63
(margin-bottom "0.25rem")))
+64
+65
;; Run/status info line
+66
(css ".run-status-line"
+67
(margin-bottom "1rem")
+68
(font-size "0.9rem")
+69
(color "var(--color-text-muted)")
+70
(display "flex")
+71
(align-items "center")
+72
(flex-wrap "wrap")
+73
(gap "0.25rem"))
+74
+75
(css ".run-status-line .mono"
+76
(font-family "'JetBrains Mono', 'Fira Code', monospace")
+77
(font-size "0.85rem"))
+78
+79
(css ".dim"
+80
(color "var(--color-text-muted)"))
+81
+82
;; Check history section
+83
(css ".check-history"
+84
(margin-top "1rem"))
+85
(css ".check-history h2"
+86
(margin-bottom "1rem")
+87
(font-size "1.25rem"))
+88
+89
;; Responsive
+90
(css-media "(max-width: 640px)"
+91
(css ".main, .main-narrow"
+92
(padding "1rem"))
+93
(css ".status-panel"
+94
(flex-direction "column")
+95
(align-items "flex-start")
+96
(gap "1rem")))))
+97
+98
;; ============================================================
+99
;; Footer
+100
;; ============================================================
+101
+102
(define (footer-styles)
+103
(css ".footer"
+104
(text-align "center")
+105
(padding "2rem 1rem")
+106
(color "var(--color-text-muted)")
+107
(font-size "0.8rem")
+108
(& " a"
+109
(color "var(--color-text-muted)"))))
+110
+111
;; ============================================================
+112
;; Grid System
+113
;; ============================================================
+114
+115
(define (grid-styles)
+116
(css-combine
+117
(css ".grid"
+118
(display "grid")
+119
(grid-template-columns "repeat(auto-fill, minmax(280px, 1fr))")
+120
(gap "1rem"))
+121
+122
;; Service card grid (alias)
+123
(css ".service-grid"
+124
(display "grid")
+125
(grid-template-columns "repeat(auto-fill, minmax(280px, 1fr))")
+126
(gap "1rem"))
+127
+128
;; Repo group (Kiln)
+129
(css ".repo-group"
+130
(margin-bottom "2rem"))
+131
(css ".repo-heading"
+132
(font-size "1rem")
+133
(color "var(--color-text-muted)")
+134
(font-family "'JetBrains Mono', 'Fira Code', monospace")
+135
(margin-bottom "0.5rem")
+136
(font-weight "normal"))
+137
+138
;; Responsive
+139
(css-media "(max-width: 640px)"
+140
(css ".grid, .service-grid"
+141
(grid-template-columns "1fr")))))
+142
+143
))
src/sigil/web/styles/palette.sgladded
@@ -0,0 +1,94 @@
+1
;;; (sigil web styles palette) - Color palettes for Sigil web apps.
+2
;;;
+3
;;; A palette is a record of named colors used by all component styles.
+4
;;; The default palette is black and gold. Apps can create custom palettes
+5
;;; with `make-palette` and pass them to component style functions.
+6
+7
(define-library (sigil web styles palette)
+8
(import (sigil core)
+9
(sigil string)
+10
(sigil css))
+11
+12
(export make-palette
+13
default-palette
+14
palette-background
+15
palette-surface
+16
palette-surface-hover
+17
palette-primary
+18
palette-primary-hover
+19
palette-text
+20
palette-text-muted
+21
palette-border
+22
palette-success
+23
palette-warning
+24
palette-error
+25
palette->css-vars)
+26
+27
(begin
+28
+29
;; A palette is a simple alist of named colors.
+30
;; Using an alist allows easy extension and customization.
+31
+32
(define (make-palette (keys: background surface surface-hover
+33
primary primary-hover
+34
text text-muted border
+35
success warning error))
+36
(list (cons 'background background)
+37
(cons 'surface surface)
+38
(cons 'surface-hover surface-hover)
+39
(cons 'primary primary)
+40
(cons 'primary-hover primary-hover)
+41
(cons 'text text)
+42
(cons 'text-muted text-muted)
+43
(cons 'border border)
+44
(cons 'success success)
+45
(cons 'warning warning)
+46
(cons 'error error)))
+47
+48
(define default-palette
+49
(make-palette
+50
background: "#0d0d0d"
+51
surface: "#1a1a1a"
+52
surface-hover: "#222222"
+53
primary: "#d4a017"
+54
primary-hover: "#b8860b"
+55
text: "#e8e8e8"
+56
text-muted: "#888888"
+57
border: "#2a2a2a"
+58
success: "#22c55e"
+59
warning: "#f59e0b"
+60
error: "#ef4444"))
+61
+62
;; Accessors
+63
(define (palette-ref p key)
+64
(let ((pair (assoc key p)))
+65
(if pair (cdr pair) #f)))
+66
+67
(define (palette-background p) (palette-ref p 'background))
+68
(define (palette-surface p) (palette-ref p 'surface))
+69
(define (palette-surface-hover p) (palette-ref p 'surface-hover))
+70
(define (palette-primary p) (palette-ref p 'primary))
+71
(define (palette-primary-hover p) (palette-ref p 'primary-hover))
+72
(define (palette-text p) (palette-ref p 'text))
+73
(define (palette-text-muted p) (palette-ref p 'text-muted))
+74
(define (palette-border p) (palette-ref p 'border))
+75
(define (palette-success p) (palette-ref p 'success))
+76
(define (palette-warning p) (palette-ref p 'warning))
+77
(define (palette-error p) (palette-ref p 'error))
+78
+79
;; Convert palette to CSS custom properties (:root block)
+80
(define (palette->css-vars p)
+81
(css-vars
+82
(--color-bg (palette-background p))
+83
(--color-surface (palette-surface p))
+84
(--color-surface-hover (palette-surface-hover p))
+85
(--color-primary (palette-primary p))
+86
(--color-primary-hover (palette-primary-hover p))
+87
(--color-text (palette-text p))
+88
(--color-text-muted (palette-text-muted p))
+89
(--color-border (palette-border p))
+90
(--color-success (palette-success p))
+91
(--color-warning (palette-warning p))
+92
(--color-error (palette-error p))))
+93
+94
))
src/sigil/web/styles/typography.sgladded
@@ -0,0 +1,70 @@
+1
;;; (sigil web styles typography) - Font stack, type scale, and text styles.
+2
;;;
+3
;;; System font stack with modular type scale for headings, body, and
+4
;;; small text. Includes monospace stack for code elements.
+5
+6
(define-library (sigil web styles typography)
+7
(import (sigil core)
+8
(sigil css))
+9
+10
(export font-family-sans
+11
font-family-mono
+12
typography-styles)
+13
+14
(begin
+15
+16
(define font-family-sans
+17
"system-ui, -apple-system, 'Segoe UI', sans-serif")
+18
+19
(define font-family-mono
+20
"'JetBrains Mono', 'Fira Code', 'Cascadia Code', ui-monospace, monospace")
+21
+22
(define (typography-styles)
+23
(css-combine
+24
(css "body"
+25
(font-family font-family-sans)
+26
(font-size "16px")
+27
(line-height "1.6")
+28
(color "var(--color-text)")
+29
(background "var(--color-bg)"))
+30
+31
(css "h1"
+32
(font-size "1.75rem")
+33
(font-weight "700")
+34
(line-height "1.2")
+35
(margin-bottom "1rem"))
+36
+37
(css "h2"
+38
(font-size "1.375rem")
+39
(font-weight "600")
+40
(line-height "1.3")
+41
(margin-bottom "0.75rem"))
+42
+43
(css "h3"
+44
(font-size "1.125rem")
+45
(font-weight "600")
+46
(line-height "1.4")
+47
(margin-bottom "0.5rem"))
+48
+49
(css "small, .text-small"
+50
(font-size "0.875rem"))
+51
+52
(css ".text-caption"
+53
(font-size "0.8rem")
+54
(color "var(--color-text-muted)"))
+55
+56
(css ".mono"
+57
(font-family font-family-mono)
+58
(font-size "0.85rem"))
+59
+60
(css "code, pre"
+61
(font-family font-family-mono)
+62
(font-size "0.875rem"))
+63
+64
(css "a"
+65
(color "var(--color-primary)")
+66
(text-decoration "none")
+67
(& ":hover"
+68
(text-decoration "underline")))))
+69
+70
))
test/test-styles.sgladded
@@ -0,0 +1,133 @@
+1
;;; Test suite for sigil-web-styles
+2
+3
(import (sigil test)
+4
(sigil string)
+5
(sigil web styles)
+6
(sigil web styles palette)
+7
(sigil web styles typography)
+8
(sigil web styles components)
+9
(sigil web styles layout)
+10
(sigil css))
+11
+12
(define (string-contains? haystack needle)
+13
(let ((hlen (string-length haystack))
+14
(nlen (string-length needle)))
+15
(let loop ((i 0))
+16
(cond
+17
((> (+ i nlen) hlen) #f)
+18
((string=? (substring haystack i (+ i nlen)) needle) #t)
+19
(else (loop (+ i 1)))))))
+20
+21
(test-group "palette"
+22
(test "default-palette has all colors"
+23
(assert-true (string? (palette-background default-palette)))
+24
(assert-true (string? (palette-surface default-palette)))
+25
(assert-true (string? (palette-primary default-palette)))
+26
(assert-true (string? (palette-text default-palette)))
+27
(assert-true (string? (palette-success default-palette)))
+28
(assert-true (string? (palette-warning default-palette)))
+29
(assert-true (string? (palette-error default-palette))))
+30
+31
(test "default palette uses black+gold"
+32
(assert-equal "#0d0d0d" (palette-background default-palette))
+33
(assert-equal "#d4a017" (palette-primary default-palette)))
+34
+35
(test "make-palette creates custom palette"
+36
(let ((p (make-palette
+37
background: "#fff" surface: "#f0f0f0" surface-hover: "#e0e0e0"
+38
primary: "#0066cc" primary-hover: "#004c99"
+39
text: "#111" text-muted: "#666" border: "#ccc"
+40
success: "#0a0" warning: "#fa0" error: "#f00")))
+41
(assert-equal "#fff" (palette-background p))
+42
(assert-equal "#0066cc" (palette-primary p))))
+43
+44
(test "palette->css-vars generates :root block"
+45
(let ((css (css->string (palette->css-vars default-palette))))
+46
(assert-true (string-contains? css ":root"))
+47
(assert-true (string-contains? css "--color-bg: #0d0d0d"))
+48
(assert-true (string-contains? css "--color-primary: #d4a017")))))
+49
+50
(test-group "typography"
+51
(test "typography-styles generates body styles"
+52
(let ((css (css->string (typography-styles))))
+53
(assert-true (string-contains? css "body"))
+54
(assert-true (string-contains? css "font-family"))
+55
(assert-true (string-contains? css "line-height: 1.6")))))
+56
+57
(test-group "components"
+58
(test "card-styles generates .card"
+59
(let ((css (css->string (card-styles))))
+60
(assert-true (string-contains? css ".card"))
+61
(assert-true (string-contains? css "linear-gradient"))))
+62
+63
(test "table-styles generates .table"
+64
(let ((css (css->string (table-styles))))
+65
(assert-true (string-contains? css ".table"))
+66
(assert-true (string-contains? css "border-collapse"))))
+67
+68
(test "status-styles generates status classes"
+69
(let ((css (css->string (status-styles))))
+70
(assert-true (string-contains? css ".status-up"))
+71
(assert-true (string-contains? css ".status-down"))
+72
(assert-true (string-contains? css ".status-passed"))
+73
(assert-true (string-contains? css ".status-failed"))
+74
(assert-true (string-contains? css "@keyframes pulse"))))
+75
+76
(test "button-styles has gradient shine"
+77
(let ((css (css->string (button-styles))))
+78
(assert-true (string-contains? css ".btn-primary"))
+79
(assert-true (string-contains? css "linear-gradient"))))
+80
+81
(test "nav-styles generates header"
+82
(let ((css (css->string (nav-styles))))
+83
(assert-true (string-contains? css ".header"))
+84
(assert-true (string-contains? css ".header-logo"))))
+85
+86
(test "log-viewer-styles generates log classes"
+87
(let ((css (css->string (log-viewer-styles))))
+88
(assert-true (string-contains? css ".log-viewer"))
+89
(assert-true (string-contains? css ".log-line"))))
+90
+91
(test "ansi-color-styles generates ANSI classes"
+92
(let ((css (css->string (ansi-color-styles))))
+93
(assert-true (string-contains? css ".a-bold"))
+94
(assert-true (string-contains? css ".a-red"))
+95
(assert-true (string-contains? css ".a-green")))))
+96
+97
(test-group "layout"
+98
(test "reset-styles generates box-sizing"
+99
(let ((css (css->string (reset-styles))))
+100
(assert-true (string-contains? css "box-sizing: border-box"))))
+101
+102
(test "layout-styles generates .main"
+103
(let ((css (css->string (layout-styles))))
+104
(assert-true (string-contains? css ".main"))
+105
(assert-true (string-contains? css "max-width"))))
+106
+107
(test "grid-styles generates grid"
+108
(let ((css (css->string (grid-styles))))
+109
(assert-true (string-contains? css ".grid"))
+110
(assert-true (string-contains? css "grid-template-columns")))))
+111
+112
(test-group "theme-stylesheet"
+113
(test "generates complete stylesheet with default palette"
+114
(let ((css (theme-stylesheet)))
+115
(assert-true (string-contains? css ":root"))
+116
(assert-true (string-contains? css "--color-bg: #0d0d0d"))
+117
(assert-true (string-contains? css ".card"))
+118
(assert-true (string-contains? css ".table"))
+119
(assert-true (string-contains? css ".header"))
+120
(assert-true (string-contains? css ".btn"))
+121
(assert-true (string-contains? css "@keyframes pulse"))))
+122
+123
(test "custom palette changes CSS variables"
+124
(let* ((p (make-palette
+125
background: "#ffffff" surface: "#f0f0f0" surface-hover: "#e0e0e0"
+126
primary: "#0066cc" primary-hover: "#004c99"
+127
text: "#111111" text-muted: "#666666" border: "#cccccc"
+128
success: "#00aa00" warning: "#ffaa00" error: "#ff0000"))
+129
(css (theme-stylesheet palette: p)))
+130
(assert-true (string-contains? css "--color-bg: #ffffff"))
+131
(assert-true (string-contains? css "--color-primary: #0066cc")))))
+132
+133
(run-tests)