@devslab/site-kit 0.16.0 → 0.17.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/README.ko.md +5 -5
- package/README.md +5 -5
- package/dist/consent.d.ts +10 -2
- package/dist/consent.d.ts.map +1 -1
- package/dist/solid.js +79 -89
- package/dist/solid.js.map +1 -1
- package/dist/solid.server.js +21 -28
- package/dist/solid.server.js.map +1 -1
- package/package.json +2 -2
- package/src/core/consent.d.mts +9 -0
- package/src/core/consent.mjs +25 -15
- package/src/core/index.d.mts +1 -0
- package/src/core/index.mjs +15 -11
- package/styles.css +25 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devslab/site-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Strict i18n, SEO/GEO, and Solid public-site shells for DevsLab products",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"./fonts/*": "./fonts/*"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@devslab/dds-solid": "0.
|
|
68
|
+
"@devslab/dds-solid": "0.17.0"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"@tanstack/solid-router": "1.170.30",
|
package/src/core/consent.d.mts
CHANGED
|
@@ -134,10 +134,17 @@ export interface ConsentManager {
|
|
|
134
134
|
}
|
|
135
135
|
export declare function createConsentManager(options: ConsentManagerOptions): ConsentManager;
|
|
136
136
|
|
|
137
|
+
/**
|
|
138
|
+
* The bar is short: `title`, `body` (what, why, that it is optional) and `learnMore`, a link to the
|
|
139
|
+
* privacy policy's analytics section (ConsentBanner's `learnMoreHref`), which carries the full disclosure.
|
|
140
|
+
* The settings dialog: one line each for necessary and analytics, a policy link, cancel and save.
|
|
141
|
+
*/
|
|
137
142
|
export interface ConsentMessages {
|
|
138
143
|
regionLabel: string;
|
|
139
144
|
title: string;
|
|
140
145
|
body: string;
|
|
146
|
+
/** "자세히 보기" / "Learn more": the bar's link to the policy section. */
|
|
147
|
+
learnMore: string;
|
|
141
148
|
privacyLink: string;
|
|
142
149
|
acceptAll: string;
|
|
143
150
|
rejectAll: string;
|
|
@@ -152,6 +159,8 @@ export interface ConsentMessages {
|
|
|
152
159
|
analyticsBody: string;
|
|
153
160
|
analyticsSwitch: string;
|
|
154
161
|
save: string;
|
|
162
|
+
/** Closes the settings dialog without saving, like ✕ and Escape. */
|
|
163
|
+
cancel: string;
|
|
155
164
|
close: string;
|
|
156
165
|
saved: string;
|
|
157
166
|
trigger: string;
|
package/src/core/consent.mjs
CHANGED
|
@@ -518,25 +518,33 @@ export function createConsentManager(options) {
|
|
|
518
518
|
});
|
|
519
519
|
}
|
|
520
520
|
|
|
521
|
-
/**
|
|
521
|
+
/**
|
|
522
|
+
* Default strings, Korean. Products pass these (or their own) to the banner.
|
|
523
|
+
* Short on purpose (owner decision, 2026-10-06): the bar says what and why and
|
|
524
|
+
* that it is optional; "자세히 보기" links to the product's privacy policy,
|
|
525
|
+
* whose analytics section carries the full disclosure (Google Analytics,
|
|
526
|
+
* recipient, overseas transfer, retention, no advertising, withdrawal).
|
|
527
|
+
*/
|
|
522
528
|
export const CONSENT_MESSAGES_KO = Object.freeze({
|
|
523
529
|
regionLabel: "쿠키 동의",
|
|
524
|
-
title: "
|
|
525
|
-
body: "
|
|
530
|
+
title: "이용 통계 수집 동의 (선택)",
|
|
531
|
+
body: "서비스를 더 낫게 만들기 위해 이용 통계를 수집합니다. 동의는 선택이며, 동의하지 않아도 모든 기능을 쓸 수 있습니다.",
|
|
532
|
+
learnMore: "자세히 보기",
|
|
526
533
|
privacyLink: "개인정보처리방침",
|
|
527
534
|
acceptAll: "모두 허용",
|
|
528
535
|
rejectAll: "거부",
|
|
529
536
|
settings: "설정",
|
|
530
537
|
dismiss: "선택하지 않고 닫기",
|
|
531
538
|
settingsTitle: "쿠키 설정",
|
|
532
|
-
settingsIntro: "
|
|
539
|
+
settingsIntro: "바닥글의 ‘쿠키 설정’에서 언제든 다시 바꿀 수 있습니다.",
|
|
533
540
|
necessaryTitle: "필수",
|
|
534
|
-
necessaryBody: "
|
|
541
|
+
necessaryBody: "사이트가 동작하는 데 꼭 필요해 항상 사용합니다.",
|
|
535
542
|
necessaryStatus: "항상 사용",
|
|
536
|
-
analyticsTitle: "
|
|
537
|
-
analyticsBody: "
|
|
538
|
-
analyticsSwitch: "
|
|
543
|
+
analyticsTitle: "이용 통계 (선택)",
|
|
544
|
+
analyticsBody: "서비스를 개선하는 데 쓰는 이용 통계입니다.",
|
|
545
|
+
analyticsSwitch: "이용 통계 수집 허용",
|
|
539
546
|
save: "선택 저장",
|
|
547
|
+
cancel: "취소",
|
|
540
548
|
close: "닫기",
|
|
541
549
|
saved: "쿠키 설정을 저장했습니다.",
|
|
542
550
|
trigger: "쿠키 설정",
|
|
@@ -545,22 +553,24 @@ export const CONSENT_MESSAGES_KO = Object.freeze({
|
|
|
545
553
|
/** Default strings, English. */
|
|
546
554
|
export const CONSENT_MESSAGES_EN = Object.freeze({
|
|
547
555
|
regionLabel: "Cookie consent",
|
|
548
|
-
title: "
|
|
549
|
-
body: "
|
|
556
|
+
title: "Analytics (optional)",
|
|
557
|
+
body: "We collect usage statistics to improve the service. It's optional, and everything works without it.",
|
|
558
|
+
learnMore: "Learn more",
|
|
550
559
|
privacyLink: "Privacy policy",
|
|
551
560
|
acceptAll: "Accept all",
|
|
552
561
|
rejectAll: "Reject",
|
|
553
562
|
settings: "Settings",
|
|
554
563
|
dismiss: "Close without choosing",
|
|
555
564
|
settingsTitle: "Cookie settings",
|
|
556
|
-
settingsIntro: "
|
|
565
|
+
settingsIntro: "You can change this at any time under “Cookie settings” in the footer.",
|
|
557
566
|
necessaryTitle: "Necessary",
|
|
558
|
-
necessaryBody: "Needed
|
|
567
|
+
necessaryBody: "Needed for the site to work, so always on.",
|
|
559
568
|
necessaryStatus: "Always on",
|
|
560
|
-
analyticsTitle: "
|
|
561
|
-
analyticsBody: "
|
|
562
|
-
analyticsSwitch: "Allow
|
|
569
|
+
analyticsTitle: "Analytics (optional)",
|
|
570
|
+
analyticsBody: "Usage statistics that help us improve the service.",
|
|
571
|
+
analyticsSwitch: "Allow analytics",
|
|
563
572
|
save: "Save choices",
|
|
573
|
+
cancel: "Cancel",
|
|
564
574
|
close: "Close",
|
|
565
575
|
saved: "Your cookie settings are saved.",
|
|
566
576
|
trigger: "Cookie settings",
|
package/src/core/index.d.mts
CHANGED
package/src/core/index.mjs
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
// The root barrel re-exports each module whole, statement for statement the
|
|
2
|
+
// same as index.d.mts. It used to name every export by hand, and the consent
|
|
3
|
+
// list fell behind its own declarations: CONSENT_RECORD_MAX_BYTES and nine
|
|
4
|
+
// other names type-checked from "@devslab/site-kit" and were undefined at
|
|
5
|
+
// runtime. A module that should stay off the root (flags, devslab) is simply
|
|
6
|
+
// not listed here; scripts/verify-site-kit-release.mjs checks the packed
|
|
7
|
+
// tarball's declared exports against what each entry point really exports.
|
|
8
|
+
export * from "./locales.mjs";
|
|
9
|
+
export * from "./catalog.mjs";
|
|
10
|
+
export * from "./seo.mjs";
|
|
11
|
+
export * from "./geo.mjs";
|
|
12
|
+
export * from "./publisher.mjs";
|
|
13
|
+
export * from "./gtm.mjs";
|
|
14
|
+
export * from "./fonts.mjs";
|
|
15
|
+
export * from "./consent.mjs";
|
package/styles.css
CHANGED
|
@@ -110,22 +110,28 @@
|
|
|
110
110
|
.site-locale-flag__option[aria-current="true"] { font-weight: 700; }
|
|
111
111
|
@media (max-width: 720px) { .site-locale-flag__list { position: static; inline-size: 100%; max-block-size: none; box-shadow: none; } }
|
|
112
112
|
|
|
113
|
-
/* Consent (D-034): a bottom bar with three equal choices, and a settings dialog
|
|
114
|
-
|
|
115
|
-
drawn heavier than another.
|
|
113
|
+
/* Consent (D-034): a bottom bar with three equal choices, and a settings dialog
|
|
114
|
+
with two (cancel, save). Each set shares one tone and one grid track width,
|
|
115
|
+
so no choice is drawn heavier than another. Products bring their own, longer labels, so the
|
|
116
|
+
layout follows the bar's own width (a container), in three steps: one row
|
|
117
|
+
(copy, choices, close); copy above a row of three; copy above the three
|
|
118
|
+
stacked full width. A label wraps only at a space, never inside a word. */
|
|
116
119
|
/* Room under the page while the bar is up (ConsentBanner sets the height); zero specificity, so a product body rule wins. */
|
|
117
120
|
:where(body) { padding-block-end: var(--site-consent-block-size, 0px); }
|
|
118
|
-
.site-consent { position: fixed; inset-inline: 0; inset-block-end: 0; z-index: 900; max-block-size: 100dvh; overflow-y: auto; border-block-start: 1px solid var(--dds-color-border-default); background: var(--dds-color-bg-elevated); color: var(--dds-color-text-primary); box-shadow: var(--dds-elevation-3); }
|
|
119
|
-
.site-consent__inner { inline-size: min(100% - var(--dds-space-32), 1120px); margin-inline: auto; padding-block: var(--dds-space-16); display: grid; grid-template-columns: minmax(0, 1fr)
|
|
121
|
+
.site-consent { container: site-consent / inline-size; position: fixed; inset-inline: 0; inset-block-end: 0; z-index: 900; max-block-size: 100dvh; overflow-y: auto; border-block-start: 1px solid var(--dds-color-border-default); background: var(--dds-color-bg-elevated); color: var(--dds-color-text-primary); box-shadow: var(--dds-elevation-3); }
|
|
122
|
+
.site-consent__inner { inline-size: min(100% - var(--dds-space-32), 1120px); margin-inline: auto; padding-block: var(--dds-space-16); display: grid; grid-template-columns: minmax(0, 1fr) fit-content(50%) auto; grid-template-areas: "copy actions close"; align-items: center; gap: var(--dds-space-12) var(--dds-space-24); }
|
|
120
123
|
.site-consent__copy { grid-area: copy; display: grid; gap: var(--dds-space-4); min-inline-size: 0; }
|
|
121
124
|
.site-consent__title { margin: 0; font-size: var(--dds-typo-body-1-font-size); line-height: var(--dds-typo-body-1-line-height); font-weight: 700; }
|
|
122
125
|
.site-consent__body { margin: 0; max-inline-size: 72ch; font-size: var(--dds-typo-body-2-font-size); line-height: var(--dds-typo-body-2-line-height); color: var(--dds-color-text-secondary); }
|
|
123
126
|
.site-consent__link { color: var(--dds-color-text-brand); text-decoration: underline; text-underline-offset: 2px; }
|
|
124
127
|
.site-consent__link:focus-visible, .site-consent-trigger:focus-visible { outline: 2px solid var(--dds-color-border-focus); outline-offset: 2px; border-radius: var(--dds-radius-sm); }
|
|
125
128
|
.site-consent__actions { grid-area: actions; display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: var(--dds-space-8); }
|
|
126
|
-
.
|
|
129
|
+
/* dds.css lets a button label break anywhere (overflow-wrap: anywhere); here a
|
|
130
|
+
line ends only at a space. Korean keeps whole words, whatever the page root says. */
|
|
131
|
+
.site-consent__action { inline-size: 100%; min-inline-size: 7rem; overflow-wrap: normal; word-break: normal; text-align: center; }
|
|
132
|
+
.site-consent__action:lang(ko) { word-break: keep-all; }
|
|
127
133
|
.site-consent__dismiss { grid-area: close; align-self: start; }
|
|
128
|
-
.dds-dialog.site-consent-dialog { position: relative; max-inline-size: 36rem; max-block-size: calc(100dvh - 2 * var(--dds-space-16)); overflow-y: auto; }
|
|
134
|
+
.dds-dialog.site-consent-dialog { container: site-consent-dialog / inline-size; position: relative; max-inline-size: 36rem; max-block-size: calc(100dvh - 2 * var(--dds-space-16)); overflow-y: auto; }
|
|
129
135
|
.site-consent-dialog .dds-dialog__title { padding-inline-end: var(--dds-space-40); }
|
|
130
136
|
.site-consent-dialog__close { position: absolute; inset-block-start: var(--dds-space-12); inset-inline-end: var(--dds-space-12); }
|
|
131
137
|
.site-consent-categories { display: grid; margin: 0 0 var(--dds-space-12); padding: 0; list-style: none; }
|
|
@@ -137,18 +143,24 @@
|
|
|
137
143
|
.site-consent-category__status, .site-consent-category__switch { justify-self: end; }
|
|
138
144
|
.site-consent-category__status { background: var(--dds-color-bg-subtle); color: var(--dds-color-text-secondary); }
|
|
139
145
|
.site-consent-dialog__policy { margin: 0 0 var(--dds-space-16); font-size: var(--dds-typo-body-2-font-size); }
|
|
140
|
-
.site-consent-dialog .dds-dialog__actions { display: grid; grid-template-columns: repeat(
|
|
146
|
+
.site-consent-dialog .dds-dialog__actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
141
147
|
/* The footer's "쿠키 설정" reads as one of its links. */
|
|
142
148
|
.site-consent-trigger { appearance: none; margin: 0; padding: 0; border: 0; background: none; font: inherit; color: var(--dds-color-text-secondary); cursor: pointer; }
|
|
143
149
|
.site-consent-trigger:hover { color: var(--dds-color-text-primary); text-decoration: underline; }
|
|
144
|
-
|
|
150
|
+
/* One row only while the copy keeps a readable measure beside the choices
|
|
151
|
+
(fit-content caps them at half the bar; their labels then wrap at spaces). */
|
|
152
|
+
@container site-consent (max-width: 60rem) {
|
|
145
153
|
.site-consent__inner { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "copy close" "actions actions"; align-items: start; }
|
|
146
154
|
.site-consent__actions { grid-auto-flow: row; grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
147
155
|
.site-consent__action { min-inline-size: 0; }
|
|
148
156
|
}
|
|
149
|
-
|
|
150
|
-
|
|
157
|
+
/* A phone: a third of the bar is too narrow for a long word (Tamil, Telugu,
|
|
158
|
+
German), so the choices stack — full width, every row as tall as the tallest. */
|
|
159
|
+
@container site-consent (max-width: 36rem) {
|
|
160
|
+
.site-consent__actions { grid-template-columns: minmax(0, 1fr); grid-auto-rows: 1fr; }
|
|
151
161
|
}
|
|
152
|
-
|
|
153
|
-
|
|
162
|
+
/* The same in the settings dialog. A container query measures the content box:
|
|
163
|
+
the dialog's 36rem less its padding is 536px. */
|
|
164
|
+
@container site-consent-dialog (max-width: 32rem) {
|
|
165
|
+
.site-consent-dialog .dds-dialog__actions { grid-template-columns: minmax(0, 1fr); grid-auto-rows: 1fr; }
|
|
154
166
|
}
|