@cogenta/theme-canonical 0.2.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/render/actions.d.ts +2 -16
- package/dist/src/render/actions.d.ts.map +1 -1
- package/dist/src/render/actions.js +2 -42
- package/dist/src/render/actions.js.map +1 -1
- package/dist/src/render/blocks/accordion.d.ts +5 -0
- package/dist/src/render/blocks/accordion.d.ts.map +1 -0
- package/dist/src/render/blocks/accordion.js +19 -0
- package/dist/src/render/blocks/accordion.js.map +1 -0
- package/dist/src/render/blocks/collection-list.d.ts +9 -7
- package/dist/src/render/blocks/collection-list.d.ts.map +1 -1
- package/dist/src/render/blocks/collection-list.js +8 -14
- package/dist/src/render/blocks/collection-list.js.map +1 -1
- package/dist/src/render/blocks/feature-grid.d.ts.map +1 -1
- package/dist/src/render/blocks/feature-grid.js +7 -2
- package/dist/src/render/blocks/feature-grid.js.map +1 -1
- package/dist/src/render/blocks/logo-strip.d.ts +5 -0
- package/dist/src/render/blocks/logo-strip.d.ts.map +1 -0
- package/dist/src/render/blocks/logo-strip.js +18 -0
- package/dist/src/render/blocks/logo-strip.js.map +1 -0
- package/dist/src/render/blocks/pricing-table.d.ts +5 -0
- package/dist/src/render/blocks/pricing-table.d.ts.map +1 -0
- package/dist/src/render/blocks/pricing-table.js +29 -0
- package/dist/src/render/blocks/pricing-table.js.map +1 -0
- package/dist/src/render/blocks/stat-counter.d.ts +5 -0
- package/dist/src/render/blocks/stat-counter.d.ts.map +1 -0
- package/dist/src/render/blocks/stat-counter.js +17 -0
- package/dist/src/render/blocks/stat-counter.js.map +1 -0
- package/dist/src/render/blocks/testimonial.d.ts +14 -0
- package/dist/src/render/blocks/testimonial.d.ts.map +1 -0
- package/dist/src/render/blocks/testimonial.js +24 -0
- package/dist/src/render/blocks/testimonial.js.map +1 -0
- package/dist/src/render/chrome.d.ts +3 -0
- package/dist/src/render/chrome.d.ts.map +1 -0
- package/dist/src/render/chrome.js +82 -0
- package/dist/src/render/chrome.js.map +1 -0
- package/dist/src/render/comments.d.ts +3 -0
- package/dist/src/render/comments.d.ts.map +1 -0
- package/dist/src/render/comments.js +3 -0
- package/dist/src/render/comments.js.map +1 -0
- package/dist/src/render/entry.d.ts +2 -6
- package/dist/src/render/entry.d.ts.map +1 -1
- package/dist/src/render/entry.js +2 -34
- package/dist/src/render/entry.js.map +1 -1
- package/dist/src/render/heading.d.ts +2 -13
- package/dist/src/render/heading.d.ts.map +1 -1
- package/dist/src/render/heading.js +2 -33
- package/dist/src/render/heading.js.map +1 -1
- package/dist/src/render/html.d.ts +2 -43
- package/dist/src/render/html.d.ts.map +1 -1
- package/dist/src/render/html.js +2 -95
- package/dist/src/render/html.js.map +1 -1
- package/dist/src/render/icons.d.ts +3 -0
- package/dist/src/render/icons.d.ts.map +1 -0
- package/dist/src/render/icons.js +3 -0
- package/dist/src/render/icons.js.map +1 -0
- package/dist/src/render/media.d.ts +2 -31
- package/dist/src/render/media.d.ts.map +1 -1
- package/dist/src/render/media.js +2 -41
- package/dist/src/render/media.js.map +1 -1
- package/dist/src/render/render-block.d.ts +11 -22
- package/dist/src/render/render-block.d.ts.map +1 -1
- package/dist/src/render/render-block.js +63 -62
- package/dist/src/render/render-block.js.map +1 -1
- package/dist/src/render/rich-text.d.ts +2 -4
- package/dist/src/render/rich-text.d.ts.map +1 -1
- package/dist/src/render/rich-text.js +2 -104
- package/dist/src/render/rich-text.js.map +1 -1
- package/dist/src/render/term-archive.d.ts +12 -0
- package/dist/src/render/term-archive.d.ts.map +1 -0
- package/dist/src/render/term-archive.js +39 -0
- package/dist/src/render/term-archive.js.map +1 -0
- package/dist/src/theme-contract.d.ts +10 -162
- package/dist/src/theme-contract.d.ts.map +1 -1
- package/dist/src/theme-contract.js +9 -17
- package/dist/src/theme-contract.js.map +1 -1
- package/dist/theme.config.d.ts +5 -16
- package/dist/theme.config.d.ts.map +1 -1
- package/dist/theme.config.js +16 -5
- package/dist/theme.config.js.map +1 -1
- package/package.json +4 -2
- package/src/index.ts +4 -0
- package/src/render/actions.ts +2 -57
- package/src/render/blocks/accordion.ts +44 -0
- package/src/render/blocks/collection-list.ts +9 -15
- package/src/render/blocks/feature-grid.ts +11 -2
- package/src/render/blocks/logo-strip.ts +38 -0
- package/src/render/blocks/pricing-table.ts +65 -0
- package/src/render/blocks/stat-counter.ts +34 -0
- package/src/render/blocks/testimonial.ts +41 -0
- package/src/render/chrome.ts +105 -0
- package/src/render/comments.ts +6 -0
- package/src/render/entry.ts +2 -40
- package/src/render/heading.ts +7 -44
- package/src/render/html.ts +15 -122
- package/src/render/icons.ts +2 -0
- package/src/render/media.ts +2 -62
- package/src/render/render-block.ts +85 -75
- package/src/render/rich-text.ts +2 -150
- package/src/render/term-archive.ts +85 -0
- package/src/styles/archive.css +40 -0
- package/src/styles/base.css +525 -3
- package/src/styles/blocks.css +344 -14
- package/src/styles/theme.css +1 -0
- package/src/theme-contract.ts +23 -155
package/src/styles/blocks.css
CHANGED
|
@@ -9,16 +9,17 @@
|
|
|
9
9
|
|
|
10
10
|
/* --- hero ----------------------------------------------------------------
|
|
11
11
|
The page's first impression, so it is the one block that gets a decorative
|
|
12
|
-
element of its own: a
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
element of its own: a flat solid disc of the skin's accent behind the
|
|
13
|
+
media — a geometric accent rather than a wash. It is drawn on a
|
|
14
|
+
pseudo-element and sized to stay inside the block's own box — a
|
|
15
|
+
decoration that widens the page produces a horizontal scrollbar, which is
|
|
15
16
|
the classic way a hero breaks a phone.
|
|
16
17
|
------------------------------------------------------------------------- */
|
|
17
18
|
|
|
18
19
|
.cg-hero {
|
|
19
20
|
position: relative;
|
|
20
|
-
/* A stacking context of its own, so `z-index: -1` on the
|
|
21
|
-
the hero's content and not behind the page background. */
|
|
21
|
+
/* A stacking context of its own, so `z-index: -1` on the disc puts it
|
|
22
|
+
behind the hero's content and not behind the page background. */
|
|
22
23
|
isolation: isolate;
|
|
23
24
|
display: grid;
|
|
24
25
|
gap: var(--cg-gap-loose);
|
|
@@ -34,7 +35,8 @@
|
|
|
34
35
|
inline-size: min(30rem, 70%);
|
|
35
36
|
aspect-ratio: 1;
|
|
36
37
|
z-index: -1;
|
|
37
|
-
|
|
38
|
+
border-radius: 50%;
|
|
39
|
+
background: var(--cg-accent-soft);
|
|
38
40
|
pointer-events: none;
|
|
39
41
|
}
|
|
40
42
|
|
|
@@ -336,17 +338,27 @@
|
|
|
336
338
|
color: var(--cg-accent);
|
|
337
339
|
}
|
|
338
340
|
|
|
339
|
-
/* The vocabulary's `icon` names a symbol
|
|
340
|
-
|
|
341
|
-
|
|
341
|
+
/* The vocabulary's `icon` names a symbol — a tinted, ringed square that holds
|
|
342
|
+
the space an icon would, whether or not `renderIcon` (`@cogenta/theme-kit`,
|
|
343
|
+
L25) recognises the name: an unrecognised one still gets the chip, empty,
|
|
344
|
+
exactly the pre-L25 look; a recognised one gets a real glyph, centred and
|
|
345
|
+
coloured to the same accent as the ring around it. */
|
|
342
346
|
.cg-feature__icon {
|
|
343
|
-
display:
|
|
347
|
+
display: flex;
|
|
348
|
+
align-items: center;
|
|
349
|
+
justify-content: center;
|
|
344
350
|
inline-size: var(--cg-s10);
|
|
345
351
|
block-size: var(--cg-s10);
|
|
346
352
|
margin-block-end: var(--cg-s5);
|
|
347
353
|
background: var(--cg-accent-soft);
|
|
348
354
|
border-radius: var(--cg-radius-md);
|
|
349
355
|
box-shadow: var(--cg-ring-accent);
|
|
356
|
+
color: var(--cg-accent);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.cg-feature__icon svg {
|
|
360
|
+
inline-size: var(--cg-s6);
|
|
361
|
+
block-size: var(--cg-s6);
|
|
350
362
|
}
|
|
351
363
|
|
|
352
364
|
.cg-feature__title {
|
|
@@ -377,13 +389,16 @@
|
|
|
377
389
|
text-align: center;
|
|
378
390
|
}
|
|
379
391
|
|
|
380
|
-
/* A
|
|
381
|
-
it inside the radius, so it
|
|
392
|
+
/* A flat accent bar across the top of the panel — structure instead of a
|
|
393
|
+
sheen. `overflow: hidden` on the panel keeps it inside the radius, so it
|
|
394
|
+
never leaks past a rounded corner. */
|
|
382
395
|
.cg-cta::before {
|
|
383
396
|
content: "";
|
|
384
397
|
position: absolute;
|
|
385
|
-
inset: 0;
|
|
386
|
-
|
|
398
|
+
inset-block-start: 0;
|
|
399
|
+
inset-inline: 0;
|
|
400
|
+
block-size: var(--cg-s2);
|
|
401
|
+
background: var(--cg-accent-soft);
|
|
387
402
|
pointer-events: none;
|
|
388
403
|
}
|
|
389
404
|
|
|
@@ -888,3 +903,318 @@
|
|
|
888
903
|
background: var(--cg-accent);
|
|
889
904
|
color: var(--cg-accent-fg);
|
|
890
905
|
}
|
|
906
|
+
|
|
907
|
+
/* --- testimonial (blocks@2.0) --------------------------------------------
|
|
908
|
+
Same silhouette as `quote`, left as a distinct rule block for the day the
|
|
909
|
+
two diverge visually — a testimonial wall reads differently from a single
|
|
910
|
+
pull quote once a theme has more than one on a page.
|
|
911
|
+
------------------------------------------------------------------------- */
|
|
912
|
+
|
|
913
|
+
.cg-testimonial {
|
|
914
|
+
max-inline-size: var(--cg-page-narrow);
|
|
915
|
+
margin-inline: auto;
|
|
916
|
+
text-align: center;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.cg-testimonial__quote {
|
|
920
|
+
margin: 0;
|
|
921
|
+
font-family: var(--cogenta-font-serif);
|
|
922
|
+
font-size: var(--cg-text-xl);
|
|
923
|
+
line-height: var(--cg-leading-snug);
|
|
924
|
+
text-wrap: balance;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.cg-testimonial__quote > :first-child {
|
|
928
|
+
margin-block-start: 0;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
.cg-testimonial__quote > :last-child {
|
|
932
|
+
margin-block-end: 0;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
.cg-testimonial__attribution {
|
|
936
|
+
display: flex;
|
|
937
|
+
align-items: center;
|
|
938
|
+
justify-content: center;
|
|
939
|
+
gap: var(--cg-s3);
|
|
940
|
+
margin-block-start: var(--cg-s6);
|
|
941
|
+
color: var(--cg-ink-subtle);
|
|
942
|
+
font-size: var(--cg-text-sm);
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
.cg-testimonial__avatar {
|
|
946
|
+
inline-size: var(--cg-s12);
|
|
947
|
+
block-size: var(--cg-s12);
|
|
948
|
+
border-radius: var(--cg-radius-pill);
|
|
949
|
+
box-shadow: var(--cg-ring);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
.cg-testimonial__names {
|
|
953
|
+
display: flex;
|
|
954
|
+
flex-direction: column;
|
|
955
|
+
align-items: flex-start;
|
|
956
|
+
line-height: var(--cg-leading-snug);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.cg-testimonial__name {
|
|
960
|
+
font-weight: var(--cg-weight-semibold);
|
|
961
|
+
color: var(--cg-ink);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/* --- pricingTable (blocks@2.0) -------------------------------------------
|
|
965
|
+
Cards in a row, the highlighted tier lifted and ringed in the accent —
|
|
966
|
+
the one place in this theme a card earns a border of its own, because a
|
|
967
|
+
pricing table's whole point is telling the tiers apart at a glance.
|
|
968
|
+
------------------------------------------------------------------------- */
|
|
969
|
+
|
|
970
|
+
.cg-pricing__tiers {
|
|
971
|
+
display: grid;
|
|
972
|
+
gap: var(--cg-gap);
|
|
973
|
+
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
|
|
974
|
+
align-items: start;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
.cg-pricing__tier {
|
|
978
|
+
display: flex;
|
|
979
|
+
flex-direction: column;
|
|
980
|
+
padding: var(--cg-s8) var(--cg-s6);
|
|
981
|
+
background: var(--cg-surface-raised);
|
|
982
|
+
border-radius: var(--cg-radius-xl);
|
|
983
|
+
box-shadow: var(--cg-ring);
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
.cg-pricing__tier[data-highlighted="true"] {
|
|
987
|
+
background: var(--cg-surface-tinted);
|
|
988
|
+
box-shadow: var(--cg-elevation-2), var(--cg-ring-accent);
|
|
989
|
+
transform: translateY(calc(var(--cg-s3) * -1));
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
.cg-pricing__name {
|
|
993
|
+
margin: 0;
|
|
994
|
+
font-size: var(--cg-text-md);
|
|
995
|
+
font-weight: var(--cg-weight-semibold);
|
|
996
|
+
letter-spacing: var(--cg-tracking-snug);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
.cg-pricing__price {
|
|
1000
|
+
display: flex;
|
|
1001
|
+
align-items: baseline;
|
|
1002
|
+
gap: var(--cg-s1);
|
|
1003
|
+
margin: var(--cg-s4) 0 var(--cg-s6);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
.cg-pricing__amount {
|
|
1007
|
+
font-size: var(--cg-text-2xl);
|
|
1008
|
+
font-weight: var(--cg-weight-bold);
|
|
1009
|
+
letter-spacing: var(--cg-tracking-tight);
|
|
1010
|
+
font-variant-numeric: tabular-nums;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
.cg-pricing__interval {
|
|
1014
|
+
color: var(--cg-ink-muted);
|
|
1015
|
+
font-size: var(--cg-text-sm);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
.cg-pricing__features {
|
|
1019
|
+
flex: 1;
|
|
1020
|
+
margin: 0 0 var(--cg-s6);
|
|
1021
|
+
padding: 0;
|
|
1022
|
+
list-style: none;
|
|
1023
|
+
display: flex;
|
|
1024
|
+
flex-direction: column;
|
|
1025
|
+
gap: var(--cg-s2);
|
|
1026
|
+
color: var(--cg-ink-muted);
|
|
1027
|
+
line-height: var(--cg-leading-relaxed);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
.cg-pricing__features li {
|
|
1031
|
+
padding-inline-start: var(--cg-s6);
|
|
1032
|
+
position: relative;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/* A drawn checkmark — no icon set, exactly the `faq` chevron's own approach. */
|
|
1036
|
+
.cg-pricing__features li::before {
|
|
1037
|
+
content: "";
|
|
1038
|
+
position: absolute;
|
|
1039
|
+
inset-inline-start: 0;
|
|
1040
|
+
inset-block-start: 0.4em;
|
|
1041
|
+
inline-size: 0.6em;
|
|
1042
|
+
block-size: 0.35em;
|
|
1043
|
+
border-inline-start: 2px solid var(--cg-accent);
|
|
1044
|
+
border-block-end: 2px solid var(--cg-accent);
|
|
1045
|
+
transform: rotate(-45deg);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
.cg-pricing__action {
|
|
1049
|
+
margin-block-start: auto;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
.cg-pricing__action .cg-action {
|
|
1053
|
+
inline-size: 100%;
|
|
1054
|
+
justify-content: center;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
/* --- accordion (blocks@2.0) ----------------------------------------------
|
|
1058
|
+
Identical mechanics to `faq`'s panel, kept as its own rule block so the
|
|
1059
|
+
two can diverge visually without either one's CSS becoming a conditional.
|
|
1060
|
+
------------------------------------------------------------------------- */
|
|
1061
|
+
|
|
1062
|
+
.cg-accordion {
|
|
1063
|
+
max-inline-size: var(--cg-page-narrow);
|
|
1064
|
+
margin-inline: auto;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
.cg-accordion__items {
|
|
1068
|
+
background: var(--cg-surface-raised);
|
|
1069
|
+
border-radius: var(--cg-radius-lg);
|
|
1070
|
+
box-shadow: var(--cg-ring);
|
|
1071
|
+
overflow: hidden;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
.cg-accordion__item + .cg-accordion__item {
|
|
1075
|
+
border-block-start: 1px solid var(--cg-line-soft);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
.cg-accordion__question {
|
|
1079
|
+
display: flex;
|
|
1080
|
+
align-items: center;
|
|
1081
|
+
gap: var(--cg-s4);
|
|
1082
|
+
padding: var(--cg-s5) var(--cg-s6);
|
|
1083
|
+
font-weight: var(--cg-weight-semibold);
|
|
1084
|
+
cursor: pointer;
|
|
1085
|
+
list-style: none;
|
|
1086
|
+
transition: background-color var(--cg-duration) var(--cg-ease);
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
.cg-accordion__question::-webkit-details-marker {
|
|
1090
|
+
display: none;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
.cg-accordion__question:hover {
|
|
1094
|
+
background: var(--cg-accent-soft);
|
|
1095
|
+
color: var(--cg-accent-soft-fg);
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
.cg-accordion__question::after {
|
|
1099
|
+
content: "";
|
|
1100
|
+
flex: none;
|
|
1101
|
+
margin-inline-start: auto;
|
|
1102
|
+
inline-size: 0.6em;
|
|
1103
|
+
block-size: 0.6em;
|
|
1104
|
+
border-radius: var(--cg-radius-pill);
|
|
1105
|
+
border: 2px solid currentColor;
|
|
1106
|
+
position: relative;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/* A plus that becomes a minus, rather than the `faq` chevron — visually
|
|
1110
|
+
distinct from its sibling block, on the same zero-JavaScript mechanics. */
|
|
1111
|
+
.cg-accordion__question::before {
|
|
1112
|
+
content: "";
|
|
1113
|
+
position: absolute;
|
|
1114
|
+
inset-inline-end: calc(var(--cg-s6) + 0.2em);
|
|
1115
|
+
inline-size: 0.32em;
|
|
1116
|
+
block-size: 0;
|
|
1117
|
+
border-block-start: 2px solid currentColor;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
.cg-accordion__details[open] .cg-accordion__question::before {
|
|
1121
|
+
content: none;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
.cg-accordion__details[open] .cg-accordion__question {
|
|
1125
|
+
color: var(--cg-accent);
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
.cg-accordion__answer {
|
|
1129
|
+
padding: 0 var(--cg-s6) var(--cg-s6);
|
|
1130
|
+
color: var(--cg-ink-muted);
|
|
1131
|
+
line-height: var(--cg-leading-relaxed);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
.cg-accordion__answer > :first-child {
|
|
1135
|
+
margin-block-start: 0;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
.cg-accordion__answer > :last-child {
|
|
1139
|
+
margin-block-end: 0;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
/* --- statCounter (blocks@2.0) ---------------------------------------------
|
|
1143
|
+
Same `<dl>` mechanics as `stats`, without a background card: a counter row
|
|
1144
|
+
reads as a single strip of figures rather than as `stats`'s set of panels.
|
|
1145
|
+
------------------------------------------------------------------------- */
|
|
1146
|
+
|
|
1147
|
+
.cg-stat-counters__items {
|
|
1148
|
+
display: grid;
|
|
1149
|
+
gap: var(--cg-gap);
|
|
1150
|
+
grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
|
|
1151
|
+
margin: 0;
|
|
1152
|
+
text-align: center;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
.cg-stat-counter {
|
|
1156
|
+
display: flex;
|
|
1157
|
+
flex-direction: column-reverse;
|
|
1158
|
+
gap: var(--cg-s2);
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
.cg-stat-counter__value {
|
|
1162
|
+
margin: 0;
|
|
1163
|
+
color: var(--cg-accent);
|
|
1164
|
+
font-size: calc(var(--cg-text-3xl) * 1.15);
|
|
1165
|
+
font-weight: var(--cg-weight-bold);
|
|
1166
|
+
line-height: var(--cg-leading-tight);
|
|
1167
|
+
letter-spacing: var(--cg-tracking-tight);
|
|
1168
|
+
font-variant-numeric: tabular-nums;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
.cg-stat-counter__label {
|
|
1172
|
+
color: var(--cg-ink-muted);
|
|
1173
|
+
font-size: var(--cg-text-xs);
|
|
1174
|
+
font-weight: var(--cg-weight-semibold);
|
|
1175
|
+
letter-spacing: var(--cg-tracking-wide);
|
|
1176
|
+
text-transform: uppercase;
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
/* --- logoStrip (blocks@2.0) ------------------------------------------------
|
|
1180
|
+
The lighter-weight sibling of `logos`: one row, no card, no link — the
|
|
1181
|
+
"as seen in" strip rather than the fuller partner grid.
|
|
1182
|
+
------------------------------------------------------------------------- */
|
|
1183
|
+
|
|
1184
|
+
.cg-logo-strip {
|
|
1185
|
+
margin-block: 0;
|
|
1186
|
+
text-align: center;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
.cg-logo-strip__items {
|
|
1190
|
+
display: flex;
|
|
1191
|
+
flex-wrap: wrap;
|
|
1192
|
+
align-items: center;
|
|
1193
|
+
justify-content: center;
|
|
1194
|
+
gap: var(--cg-gap-loose);
|
|
1195
|
+
margin: 0;
|
|
1196
|
+
padding: 0;
|
|
1197
|
+
list-style: none;
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
.cg-logo-strip__item {
|
|
1201
|
+
display: flex;
|
|
1202
|
+
align-items: center;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
.cg-logo-strip__image {
|
|
1206
|
+
block-size: var(--cg-s8);
|
|
1207
|
+
inline-size: auto;
|
|
1208
|
+
max-inline-size: 100%;
|
|
1209
|
+
object-fit: contain;
|
|
1210
|
+
opacity: 0.6;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
.cg-logo-strip__caption {
|
|
1214
|
+
margin-block-start: var(--cg-s4);
|
|
1215
|
+
color: var(--cg-ink-subtle);
|
|
1216
|
+
font-size: var(--cg-text-xs);
|
|
1217
|
+
font-weight: var(--cg-weight-semibold);
|
|
1218
|
+
letter-spacing: var(--cg-tracking-wide);
|
|
1219
|
+
text-transform: uppercase;
|
|
1220
|
+
}
|
package/src/styles/theme.css
CHANGED
package/src/theme-contract.ts
CHANGED
|
@@ -1,159 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Contract D — Thème,
|
|
2
|
+
* Contract D — Thème, `theme@1.0`/`1.1`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* that matches what is already frozen elsewhere; both are flagged in the code.
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Contract B stores a media field as the media library's identifier, never as
|
|
16
|
-
* an URL and never as a rendition (`f.media` in `@cogenta/blocks`). So a
|
|
17
|
-
* reference the theme can hold is that identifier.
|
|
18
|
-
*/
|
|
19
|
-
export type MediaReference = string
|
|
20
|
-
|
|
21
|
-
export interface ImageOptions {
|
|
22
|
-
readonly width?: number
|
|
23
|
-
readonly height?: number
|
|
24
|
-
readonly format?: 'avif' | 'webp' | 'jpeg' | 'png'
|
|
25
|
-
readonly fit?: 'cover' | 'contain'
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface ImageSource {
|
|
29
|
-
readonly src: string
|
|
30
|
-
readonly srcset: string
|
|
31
|
-
readonly width: number
|
|
32
|
-
readonly height: number
|
|
33
|
-
/** Alt text and focal point come from the media entity, never invented here. */
|
|
34
|
-
readonly alt: string
|
|
35
|
-
readonly focal: { readonly x: number; readonly y: number } | null
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Contract A, "Champs système". A theme only ever sees published entries — the
|
|
40
|
-
* read token carries the `public` role — so `status` is narrow in practice but
|
|
41
|
-
* kept whole here rather than guessed at.
|
|
42
|
-
*
|
|
43
|
-
* The schema-defined fields are open: which of them exist depends on the
|
|
44
|
-
* collection, and a theme must not assume one is present. `entryTitle` in
|
|
45
|
-
* `src/render/entry.ts` is the only place that reaches for one.
|
|
46
|
-
*/
|
|
47
|
-
export interface ContentEntry {
|
|
48
|
-
readonly id: string
|
|
49
|
-
readonly collection: string
|
|
50
|
-
readonly locale: string
|
|
51
|
-
readonly status: 'draft' | 'scheduled' | 'published' | 'archived'
|
|
52
|
-
readonly [field: string]: unknown
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface QueryRequest {
|
|
56
|
-
readonly collection: string
|
|
57
|
-
readonly filter?: Readonly<Record<string, unknown>>
|
|
58
|
-
readonly sort?: { readonly field: string; readonly direction: 'asc' | 'desc' }
|
|
59
|
-
readonly limit?: number
|
|
60
|
-
readonly cursor?: string
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface Page<T> {
|
|
64
|
-
readonly items: readonly T[]
|
|
65
|
-
readonly nextCursor: string | null
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface ContentClient {
|
|
69
|
-
entry(collection: string, id: string): Promise<ContentEntry | null>
|
|
70
|
-
byPath(path: string): Promise<ContentEntry | null>
|
|
71
|
-
list(request: QueryRequest): Promise<Page<ContentEntry>>
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export type LinkTargetInput = { collection: string; id: string } | { path: string } | string
|
|
75
|
-
|
|
76
|
-
export interface RenderContext {
|
|
77
|
-
readonly site: {
|
|
78
|
-
readonly name: string
|
|
79
|
-
readonly url: string
|
|
80
|
-
readonly locales: readonly string[]
|
|
81
|
-
readonly defaultLocale: string
|
|
82
|
-
}
|
|
83
|
-
/** The locale being rendered. */
|
|
84
|
-
readonly locale: string
|
|
85
|
-
/** The URL being rendered, already resolved. */
|
|
86
|
-
readonly url: URL
|
|
87
|
-
|
|
88
|
-
/** Translation. An unknown key returns the key, never an empty string. */
|
|
89
|
-
t(key: string, values?: Readonly<Record<string, string | number>>): string
|
|
90
|
-
|
|
91
|
-
/** Image variants. Returns what a responsive `<img>` needs, nothing more. */
|
|
92
|
-
image(media: MediaReference, options?: ImageOptions): ImageSource
|
|
93
|
-
|
|
94
|
-
/** URL of an entry, of a path, or of an external target. Locale-aware. */
|
|
95
|
-
link(target: LinkTargetInput): string
|
|
96
|
-
|
|
97
|
-
/** Read-only content access. The only door to data a theme has. */
|
|
98
|
-
readonly content: ContentClient
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** Contract D, "Besoins runtime". */
|
|
102
|
-
export type ThemeRuntime = 'static' | 'server' | 'edge'
|
|
103
|
-
|
|
104
|
-
export interface ThemeManifest {
|
|
105
|
-
readonly name: string
|
|
106
|
-
readonly version: string
|
|
107
|
-
/** Version of the theme contract. */
|
|
108
|
-
readonly engine: string
|
|
109
|
-
/** Version of the block vocabulary supported. */
|
|
110
|
-
readonly blocks: string
|
|
111
|
-
/** Every vocabulary block the theme renders. A gap fails installation. */
|
|
112
|
-
readonly implements: readonly string[]
|
|
113
|
-
/** Content types expected, or `'*'`. */
|
|
114
|
-
readonly collections: readonly string[] | '*'
|
|
115
|
-
readonly runtime: ThemeRuntime
|
|
116
|
-
/** Path to the default skin, relative to the manifest. */
|
|
117
|
-
readonly tokens: string
|
|
118
|
-
readonly a11y: { readonly verified: 'WCAG-2.2-AA' | 'WCAG-2.2-AAA' | 'none' }
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Identity function. It exists for the inference and for the single place a
|
|
123
|
-
* manifest is recognised, not to validate: validation happens at installation,
|
|
124
|
-
* on the theme's sources, where a lie can actually be caught.
|
|
4
|
+
* Re-exported from `@cogenta/theme-kit`, which now holds the one real copy of
|
|
5
|
+
* this contract every theme package (this one included) implements against —
|
|
6
|
+
* see that package's own `contract.ts` for why. This file stays only because
|
|
7
|
+
* `@cogenta/theme-canonical`'s own public surface (`index.ts`'s
|
|
8
|
+
* `export * from './theme-contract.js'`) has always named these symbols, and
|
|
9
|
+
* a theme installed from this package before today must keep resolving them
|
|
10
|
+
* from the same place.
|
|
125
11
|
*/
|
|
126
|
-
export function defineTheme<const M extends ThemeManifest>(manifest: M): M {
|
|
127
|
-
return manifest
|
|
128
|
-
}
|
|
129
12
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
readonly font: {
|
|
146
|
-
readonly sans: string
|
|
147
|
-
readonly serif: string
|
|
148
|
-
readonly mono: string
|
|
149
|
-
readonly scale: number
|
|
150
|
-
readonly baseSize: string
|
|
151
|
-
}
|
|
152
|
-
readonly space: {
|
|
153
|
-
readonly unit: string
|
|
154
|
-
readonly density: 'compact' | 'comfortable' | 'spacious'
|
|
155
|
-
}
|
|
156
|
-
readonly radius: { readonly sm: string; readonly md: string; readonly lg: string }
|
|
157
|
-
readonly motion: { readonly duration: string; readonly easing: string; readonly reduced: boolean }
|
|
158
|
-
readonly shadow: { readonly sm: string; readonly md: string }
|
|
159
|
-
}
|
|
13
|
+
export {
|
|
14
|
+
type ContentClient,
|
|
15
|
+
type ContentEntry,
|
|
16
|
+
defineTheme,
|
|
17
|
+
type ImageOptions,
|
|
18
|
+
type ImageSource,
|
|
19
|
+
type LinkTargetInput,
|
|
20
|
+
type MediaReference,
|
|
21
|
+
type Page,
|
|
22
|
+
type QueryRequest,
|
|
23
|
+
type RenderContext,
|
|
24
|
+
type SkinTokens,
|
|
25
|
+
type ThemeManifest,
|
|
26
|
+
type ThemeRuntime,
|
|
27
|
+
} from '@cogenta/theme-kit'
|