ds-one 0.2.0-alpha.3 → 0.2.5-alpha.1
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/DS1/{utils/language.ts → 0-face/i18n.ts} +197 -2
- package/DS1/0-face/preferences.ts +23 -0
- package/DS1/0-face/pricing.ts +57 -0
- package/DS1/2-core/ds-button.ts +1 -1
- package/DS1/2-core/ds-cycle.ts +17 -18
- package/DS1/2-core/{ds-year.ts → ds-date.ts} +4 -4
- package/DS1/2-core/ds-input.ts +1 -0
- package/DS1/2-core/ds-text.ts +1 -1
- package/DS1/2-core/ds-tooltip.ts +4 -3
- package/DS1/3-unit/doublenav-v1.ts +105 -0
- package/DS1/3-unit/{ds-doublenav.ts → ds-portfolio-doublenav.ts} +4 -5
- package/DS1/3-unit/ds-portfolio-panel.ts +27 -0
- package/DS1/3-unit/ds-portfolio-singlenav.ts +79 -0
- package/DS1/3-unit/list-v1.ts +24 -0
- package/DS1/3-unit/{ds-panel.ts → panel-v1.ts} +2 -3
- package/DS1/3-unit/row-v1.ts +52 -0
- package/DS1/3-unit/{ds-singlenav.ts → singlenav-v1.ts} +4 -5
- package/DS1/4-page/ds-grid.ts +1 -1
- package/DS1/index.ts +39 -37
- package/dist/0-face/{2025-04-23-device.d.ts → device.d.ts} +1 -1
- package/dist/0-face/device.d.ts.map +1 -0
- package/dist/{utils/language.d.ts → 0-face/i18n.d.ts} +1 -1
- package/dist/0-face/i18n.d.ts.map +1 -0
- package/dist/{utils/language.js → 0-face/i18n.js} +141 -2
- package/dist/0-face/preferences.d.ts +9 -0
- package/dist/0-face/preferences.d.ts.map +1 -0
- package/dist/0-face/preferences.js +14 -0
- package/dist/0-face/pricing.d.ts +15 -0
- package/dist/0-face/pricing.d.ts.map +1 -0
- package/dist/0-face/pricing.js +46 -0
- package/dist/0-face/theme.d.ts.map +1 -0
- package/dist/2-core/ds-button.js +1 -1
- package/dist/2-core/ds-cycle.js +15 -15
- package/dist/2-core/{ds-year.d.ts → ds-date.d.ts} +4 -4
- package/dist/2-core/ds-date.d.ts.map +1 -0
- package/dist/2-core/{ds-year.js → ds-date.js} +4 -4
- package/dist/2-core/ds-input.d.ts +1 -0
- package/dist/2-core/ds-input.d.ts.map +1 -0
- package/dist/2-core/ds-input.js +1 -0
- package/dist/2-core/ds-text.js +1 -1
- package/dist/2-core/ds-tooltip.d.ts.map +1 -1
- package/dist/2-core/ds-tooltip.js +4 -2
- package/dist/3-unit/{ds-doublenav.d.ts → ds-portfolio-doublenav.d.ts} +4 -4
- package/dist/3-unit/ds-portfolio-doublenav.d.ts.map +1 -0
- package/dist/3-unit/{ds-doublenav.js → ds-portfolio-doublenav.js} +4 -4
- package/dist/3-unit/{ds-panel.d.ts → ds-portfolio-panel.d.ts} +3 -3
- package/dist/3-unit/ds-portfolio-panel.d.ts.map +1 -0
- package/dist/3-unit/{ds-panel.js → ds-portfolio-panel.js} +3 -3
- package/dist/3-unit/{ds-singlenav.d.ts → ds-portfolio-singlenav.d.ts} +4 -4
- package/dist/3-unit/ds-portfolio-singlenav.d.ts.map +1 -0
- package/dist/3-unit/{ds-singlenav.js → ds-portfolio-singlenav.js} +4 -4
- package/dist/4-page/ds-grid.js +1 -1
- package/dist/ds-one.bundle.js +2075 -3774
- package/dist/ds-one.bundle.js.map +4 -4
- package/dist/ds-one.bundle.min.js +74 -740
- package/dist/ds-one.bundle.min.js.map +4 -4
- package/dist/index.d.ts +16 -26
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -34
- package/package.json +2 -2
- package/DS1/0-face/2025-04-23-language.ts +0 -4
- package/DS1/2-core/ds-article.ts +0 -454
- package/DS1/2-core/ds-attributes.ts +0 -155
- package/DS1/2-core/ds-downloadcv.ts +0 -146
- package/DS1/2-core/ds-header.ts +0 -82
- package/DS1/2-core/ds-home.ts +0 -168
- package/DS1/2-core/ds-link.ts +0 -121
- package/DS1/2-core/ds-markdown.ts +0 -252
- package/DS1/2-core/ds-price.ts +0 -108
- package/DS1/2-core/ds-squarecircle.ts +0 -155
- package/DS1/2-core/ds-title.ts +0 -139
- package/DS1/2-core/ds-viewtoggle.ts +0 -83
- package/DS1/utils/cdn-loader.ts +0 -208
- package/DS1/utils/keys.json +0 -41
- package/DS1/utils/pricing.ts +0 -24
- package/DS1/utils/scroll.ts +0 -184
- package/DS1/utils/settings.ts +0 -23
- package/DS1/utils/viewMode.ts +0 -55
- package/dist/0-face/2025-04-23-device.d.ts.map +0 -1
- package/dist/0-face/2025-04-23-language.d.ts +0 -1
- package/dist/0-face/2025-04-23-language.d.ts.map +0 -1
- package/dist/0-face/2025-04-23-language.js +0 -3
- package/dist/2-core/article-v1.d.ts +0 -129
- package/dist/2-core/article-v1.d.ts.map +0 -1
- package/dist/2-core/article-v1.js +0 -361
- package/dist/2-core/attributes-v1.d.ts +0 -47
- package/dist/2-core/attributes-v1.d.ts.map +0 -1
- package/dist/2-core/attributes-v1.js +0 -128
- package/dist/2-core/cycle-v1.d.ts +0 -66
- package/dist/2-core/cycle-v1.d.ts.map +0 -1
- package/dist/2-core/cycle-v1.js +0 -586
- package/dist/2-core/downloadcv-v1.d.ts +0 -58
- package/dist/2-core/downloadcv-v1.d.ts.map +0 -1
- package/dist/2-core/downloadcv-v1.js +0 -119
- package/dist/2-core/ds-article.d.ts +0 -129
- package/dist/2-core/ds-article.d.ts.map +0 -1
- package/dist/2-core/ds-article.js +0 -361
- package/dist/2-core/ds-attributes.d.ts +0 -47
- package/dist/2-core/ds-attributes.d.ts.map +0 -1
- package/dist/2-core/ds-attributes.js +0 -128
- package/dist/2-core/ds-button.figma.d.ts +0 -2
- package/dist/2-core/ds-button.figma.d.ts.map +0 -1
- package/dist/2-core/ds-button.figma.js +0 -6
- package/dist/2-core/ds-downloadcv.d.ts +0 -58
- package/dist/2-core/ds-downloadcv.d.ts.map +0 -1
- package/dist/2-core/ds-downloadcv.js +0 -119
- package/dist/2-core/ds-header.d.ts +0 -28
- package/dist/2-core/ds-header.d.ts.map +0 -1
- package/dist/2-core/ds-header.js +0 -66
- package/dist/2-core/ds-home.d.ts +0 -26
- package/dist/2-core/ds-home.d.ts.map +0 -1
- package/dist/2-core/ds-home.js +0 -148
- package/dist/2-core/ds-link.d.ts +0 -35
- package/dist/2-core/ds-link.d.ts.map +0 -1
- package/dist/2-core/ds-link.js +0 -85
- package/dist/2-core/ds-markdown.d.ts +0 -7
- package/dist/2-core/ds-markdown.d.ts.map +0 -1
- package/dist/2-core/ds-markdown.js +0 -240
- package/dist/2-core/ds-price.d.ts +0 -46
- package/dist/2-core/ds-price.d.ts.map +0 -1
- package/dist/2-core/ds-price.js +0 -72
- package/dist/2-core/ds-squarecircle.d.ts +0 -50
- package/dist/2-core/ds-squarecircle.d.ts.map +0 -1
- package/dist/2-core/ds-squarecircle.js +0 -133
- package/dist/2-core/ds-title.d.ts +0 -50
- package/dist/2-core/ds-title.d.ts.map +0 -1
- package/dist/2-core/ds-title.js +0 -103
- package/dist/2-core/ds-viewtoggle.d.ts +0 -27
- package/dist/2-core/ds-viewtoggle.d.ts.map +0 -1
- package/dist/2-core/ds-viewtoggle.js +0 -49
- package/dist/2-core/ds-year.d.ts.map +0 -1
- package/dist/2-core/header-v1.d.ts +0 -28
- package/dist/2-core/header-v1.d.ts.map +0 -1
- package/dist/2-core/header-v1.js +0 -66
- package/dist/2-core/home-v1.d.ts +0 -26
- package/dist/2-core/home-v1.d.ts.map +0 -1
- package/dist/2-core/home-v1.js +0 -148
- package/dist/2-core/icon-v1.d.ts +0 -28
- package/dist/2-core/icon-v1.d.ts.map +0 -1
- package/dist/2-core/icon-v1.js +0 -297
- package/dist/2-core/link-v1.d.ts +0 -35
- package/dist/2-core/link-v1.d.ts.map +0 -1
- package/dist/2-core/link-v1.js +0 -85
- package/dist/2-core/markdown-v1.d.ts +0 -7
- package/dist/2-core/markdown-v1.d.ts.map +0 -1
- package/dist/2-core/markdown-v1.js +0 -240
- package/dist/2-core/price-v1.d.ts +0 -46
- package/dist/2-core/price-v1.d.ts.map +0 -1
- package/dist/2-core/price-v1.js +0 -72
- package/dist/2-core/squarecircle-v1.d.ts +0 -50
- package/dist/2-core/squarecircle-v1.d.ts.map +0 -1
- package/dist/2-core/squarecircle-v1.js +0 -133
- package/dist/2-core/text-v1.d.ts +0 -48
- package/dist/2-core/text-v1.d.ts.map +0 -1
- package/dist/2-core/text-v1.js +0 -83
- package/dist/2-core/title-v1.d.ts +0 -50
- package/dist/2-core/title-v1.d.ts.map +0 -1
- package/dist/2-core/title-v1.js +0 -103
- package/dist/2-core/tooltip-v1.d.ts +0 -39
- package/dist/2-core/tooltip-v1.d.ts.map +0 -1
- package/dist/2-core/tooltip-v1.js +0 -145
- package/dist/2-core/viewtoggle-v1.d.ts +0 -27
- package/dist/2-core/viewtoggle-v1.d.ts.map +0 -1
- package/dist/2-core/viewtoggle-v1.js +0 -49
- package/dist/2-core/year-v1.d.ts +0 -16
- package/dist/2-core/year-v1.d.ts.map +0 -1
- package/dist/2-core/year-v1.js +0 -21
- package/dist/3-unit/ds-doublenav.d.ts.map +0 -1
- package/dist/3-unit/ds-panel.d.ts.map +0 -1
- package/dist/3-unit/ds-singlenav.d.ts.map +0 -1
- package/dist/utils/cdn-loader.d.ts +0 -19
- package/dist/utils/cdn-loader.d.ts.map +0 -1
- package/dist/utils/cdn-loader.js +0 -142
- package/dist/utils/keys.json +0 -41
- package/dist/utils/language.d.ts.map +0 -1
- package/dist/utils/pricing.d.ts +0 -8
- package/dist/utils/pricing.d.ts.map +0 -1
- package/dist/utils/pricing.js +0 -14
- package/dist/utils/scroll.d.ts +0 -34
- package/dist/utils/scroll.d.ts.map +0 -1
- package/dist/utils/scroll.js +0 -140
- package/dist/utils/settings.d.ts +0 -9
- package/dist/utils/settings.d.ts.map +0 -1
- package/dist/utils/settings.js +0 -14
- package/dist/utils/theme.d.ts.map +0 -1
- package/dist/utils/viewMode.d.ts +0 -14
- package/dist/utils/viewMode.d.ts.map +0 -1
- package/dist/utils/viewMode.js +0 -46
- /package/DS1/0-face/{2025-04-23-device.ts → device.ts} +0 -0
- /package/DS1/{utils → 0-face}/theme.ts +0 -0
- /package/DS1/{x Icon → x-icon}/1x.svg +0 -0
- /package/DS1/{x Icon → x-icon}/1xdots.svg +0 -0
- /package/DS1/{x Icon → x-icon}/1xgrid.svg +0 -0
- /package/DS1/{x Icon → x-icon}/1xlines.svg +0 -0
- /package/DS1/{x Icon → x-icon}/2x.svg +0 -0
- /package/DS1/{x Icon → x-icon}/2xdots.svg +0 -0
- /package/DS1/{x Icon → x-icon}/2xgrid.svg +0 -0
- /package/DS1/{x Icon → x-icon}/2xlines.svg +0 -0
- /package/DS1/{x Icon → x-icon}/big.svg +0 -0
- /package/DS1/{x Icon → x-icon}/blank.svg +0 -0
- /package/DS1/{x Icon → x-icon}/check.svg +0 -0
- /package/DS1/{x Icon → x-icon}/close.svg +0 -0
- /package/DS1/{x Icon → x-icon}/collapse.svg +0 -0
- /package/DS1/{x Icon → x-icon}/color.svg +0 -0
- /package/DS1/{x Icon → x-icon}/column.svg +0 -0
- /package/DS1/{x Icon → x-icon}/default.svg +0 -0
- /package/DS1/{x Icon → x-icon}/delete.svg +0 -0
- /package/DS1/{x Icon → x-icon}/do.svg +0 -0
- /package/DS1/{x Icon → x-icon}/down.svg +0 -0
- /package/DS1/{x Icon → x-icon}/duplicate.svg +0 -0
- /package/DS1/{x Icon → x-icon}/email.svg +0 -0
- /package/DS1/{x Icon → x-icon}/expand.svg +0 -0
- /package/DS1/{x Icon → x-icon}/gallery.svg +0 -0
- /package/DS1/{x Icon → x-icon}/group.svg +0 -0
- /package/DS1/{x Icon → x-icon}/head.svg +0 -0
- /package/DS1/{x Icon → x-icon}/icon.svg +0 -0
- /package/DS1/{x Icon → x-icon}/left.svg +0 -0
- /package/DS1/{x Icon → x-icon}/lock.svg +0 -0
- /package/DS1/{x Icon → x-icon}/mic.svg +0 -0
- /package/DS1/{x Icon → x-icon}/minimize.svg +0 -0
- /package/DS1/{x Icon → x-icon}/more.svg +0 -0
- /package/DS1/{x Icon → x-icon}/note.svg +0 -0
- /package/DS1/{x Icon → x-icon}/open.svg +0 -0
- /package/DS1/{x Icon → x-icon}/page.svg +0 -0
- /package/DS1/{x Icon → x-icon}/plus.svg +0 -0
- /package/DS1/{x Icon → x-icon}/rewind.svg +0 -0
- /package/DS1/{x Icon → x-icon}/right.svg +0 -0
- /package/DS1/{x Icon → x-icon}/row..svg +0 -0
- /package/DS1/{x Icon → x-icon}/search.svg +0 -0
- /package/DS1/{x Icon → x-icon}/see.svg +0 -0
- /package/DS1/{x Icon → x-icon}/star.svg +0 -0
- /package/DS1/{x Icon → x-icon}/title.svg +0 -0
- /package/DS1/{x Icon → x-icon}/undo.svg +0 -0
- /package/DS1/{x Icon → x-icon}/ungroup.svg +0 -0
- /package/DS1/{x Icon → x-icon}/unhead.svg +0 -0
- /package/DS1/{x Icon → x-icon}/unicon.svg +0 -0
- /package/DS1/{x Icon → x-icon}/unlock.svg +0 -0
- /package/DS1/{x Icon → x-icon}/unmic.svg +0 -0
- /package/DS1/{x Icon → x-icon}/unsee.svg +0 -0
- /package/DS1/{x Icon → x-icon}/unstar.svg +0 -0
- /package/DS1/{x Icon → x-icon}/untitle.svg +0 -0
- /package/DS1/{x Icon → x-icon}/up.svg +0 -0
- /package/dist/0-face/{2025-04-23-device.js → device.js} +0 -0
- /package/dist/{utils → 0-face}/theme.d.ts +0 -0
- /package/dist/{utils → 0-face}/theme.js +0 -0
|
@@ -8,8 +8,9 @@ type TranslationData = {
|
|
|
8
8
|
|
|
9
9
|
type TranslationMap = Record<string, TranslationData>;
|
|
10
10
|
|
|
11
|
-
//
|
|
12
|
-
|
|
11
|
+
// Bundled translations (keys.json may not exist - will use external translations if not available)
|
|
12
|
+
// This is a fallback for when external translations aren't loaded
|
|
13
|
+
let translationKeys: TranslationMap = {};
|
|
13
14
|
|
|
14
15
|
// Primary language list – prioritise the 10 requested languages when cycling
|
|
15
16
|
const LANGUAGE_PRIORITY_ORDER = [
|
|
@@ -67,6 +68,187 @@ declare global {
|
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
// CDN Loader: Automatically detects and loads translation JSON files
|
|
72
|
+
// for CDN users who want to use external translations
|
|
73
|
+
|
|
74
|
+
const DEFAULT_TRANSLATION_FILE = "./translations.json";
|
|
75
|
+
let loadAttempted = false;
|
|
76
|
+
|
|
77
|
+
function normalizeCandidate(path: string): string | null {
|
|
78
|
+
if (!path) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
const trimmed = path.trim();
|
|
82
|
+
if (!trimmed) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (
|
|
87
|
+
trimmed.startsWith("./") ||
|
|
88
|
+
trimmed.startsWith("../") ||
|
|
89
|
+
trimmed.startsWith("/") ||
|
|
90
|
+
/^https?:\/\//i.test(trimmed)
|
|
91
|
+
) {
|
|
92
|
+
return trimmed;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return `./${trimmed}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function findAttributeCandidate(): string | null {
|
|
99
|
+
if (typeof document === "undefined") {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const scriptWithAttribute = document.querySelector(
|
|
104
|
+
"script[data-ds-one-translations]"
|
|
105
|
+
);
|
|
106
|
+
const scriptCandidate = scriptWithAttribute?.getAttribute(
|
|
107
|
+
"data-ds-one-translations"
|
|
108
|
+
);
|
|
109
|
+
if (scriptCandidate) {
|
|
110
|
+
return scriptCandidate;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const metaCandidate = document
|
|
114
|
+
.querySelector('meta[name="ds-one:translations"]')
|
|
115
|
+
?.getAttribute("content");
|
|
116
|
+
if (metaCandidate) {
|
|
117
|
+
return metaCandidate;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const linkCandidate = document
|
|
121
|
+
.querySelector('link[rel="ds-one-translations"]')
|
|
122
|
+
?.getAttribute("href");
|
|
123
|
+
if (linkCandidate) {
|
|
124
|
+
return linkCandidate;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function resolveTranslationSources(): string[] {
|
|
131
|
+
const candidates: string[] = [];
|
|
132
|
+
|
|
133
|
+
const windowCandidate =
|
|
134
|
+
typeof window !== "undefined" ? window.DS_ONE_TRANSLATIONS_FILE : null;
|
|
135
|
+
const attributeCandidate = findAttributeCandidate();
|
|
136
|
+
|
|
137
|
+
// Only use explicitly configured paths, or the single default
|
|
138
|
+
const windowNormalized = normalizeCandidate(windowCandidate ?? "");
|
|
139
|
+
if (windowNormalized) {
|
|
140
|
+
candidates.push(windowNormalized);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const attrNormalized = normalizeCandidate(attributeCandidate ?? "");
|
|
144
|
+
if (attrNormalized && !candidates.includes(attrNormalized)) {
|
|
145
|
+
candidates.push(attrNormalized);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Only try default if no explicit path was configured
|
|
149
|
+
if (candidates.length === 0) {
|
|
150
|
+
candidates.push(DEFAULT_TRANSLATION_FILE);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return candidates;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function validateTranslationMap(
|
|
157
|
+
candidate: unknown
|
|
158
|
+
): candidate is TranslationMap {
|
|
159
|
+
if (!candidate || typeof candidate !== "object") {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return Object.values(candidate).every(
|
|
164
|
+
(entry) => entry && typeof entry === "object"
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function fetchTranslationFile(
|
|
169
|
+
source: string
|
|
170
|
+
): Promise<TranslationMap | null> {
|
|
171
|
+
try {
|
|
172
|
+
const response = await fetch(source);
|
|
173
|
+
|
|
174
|
+
if (!response.ok) {
|
|
175
|
+
// 404 is expected if no translations file exists - don't log as error
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const translations = await response.json();
|
|
180
|
+
|
|
181
|
+
if (!validateTranslationMap(translations)) {
|
|
182
|
+
console.warn(
|
|
183
|
+
`[DS one] Invalid translation format in ${source}. Expected object with language codes as keys.`
|
|
184
|
+
);
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const languages = Object.keys(translations);
|
|
189
|
+
if (languages.length === 0) {
|
|
190
|
+
console.warn(`[DS one] No languages found in ${source}`);
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return translations;
|
|
195
|
+
} catch {
|
|
196
|
+
// Silently fail - file likely doesn't exist or isn't valid JSON
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Attempts to load translations from a JSON file in the same directory
|
|
203
|
+
*/
|
|
204
|
+
async function loadExternalTranslations(): Promise<boolean> {
|
|
205
|
+
// Only attempt once
|
|
206
|
+
if (loadAttempted) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
loadAttempted = true;
|
|
210
|
+
|
|
211
|
+
if (typeof window === "undefined") {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Check if translations are already loaded (e.g., by the application)
|
|
216
|
+
if (
|
|
217
|
+
window.DS_ONE_TRANSLATIONS &&
|
|
218
|
+
Object.keys(window.DS_ONE_TRANSLATIONS).length > 0
|
|
219
|
+
) {
|
|
220
|
+
console.log(
|
|
221
|
+
`[DS one] Translations already loaded (${Object.keys(window.DS_ONE_TRANSLATIONS).length} languages), skipping auto-load`
|
|
222
|
+
);
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const sources = resolveTranslationSources();
|
|
227
|
+
|
|
228
|
+
for (const source of sources) {
|
|
229
|
+
const translations = await fetchTranslationFile(source);
|
|
230
|
+
if (!translations) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
window.DS_ONE_TRANSLATIONS = translations;
|
|
235
|
+
|
|
236
|
+
const languages = Object.keys(translations);
|
|
237
|
+
console.log(
|
|
238
|
+
`[DS one] External translations loaded from ${source}: ${languages.length} language(s) – ${languages.join(", ")}`
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
window.dispatchEvent(new CustomEvent("translations-ready"));
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
console.info(
|
|
246
|
+
`[DS one] No external translations found at ${sources[0] ?? DEFAULT_TRANSLATION_FILE}. Using bundled translations.`
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
|
|
70
252
|
// Get translation data - prioritize external, fall back to bundled
|
|
71
253
|
function getTranslationData(): TranslationMap {
|
|
72
254
|
// Check for externally loaded translations first (CDN usage)
|
|
@@ -329,6 +511,19 @@ export const currentLanguage = {
|
|
|
329
511
|
},
|
|
330
512
|
};
|
|
331
513
|
|
|
514
|
+
// Auto-load translations when this module is imported (for CDN bundle)
|
|
515
|
+
if (typeof window !== "undefined") {
|
|
516
|
+
// Wait a bit to ensure the DOM is ready
|
|
517
|
+
if (document.readyState === "loading") {
|
|
518
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
519
|
+
loadExternalTranslations();
|
|
520
|
+
});
|
|
521
|
+
} else {
|
|
522
|
+
// DOM is already ready
|
|
523
|
+
loadExternalTranslations();
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
332
527
|
// Listen for external translations being loaded
|
|
333
528
|
if (typeof window !== "undefined") {
|
|
334
529
|
window.addEventListener("translations-ready", () => {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { LanguageCode } from "./i18n";
|
|
2
|
+
import type { ThemeType } from "./theme";
|
|
3
|
+
|
|
4
|
+
export type Preferences = {
|
|
5
|
+
language?: LanguageCode;
|
|
6
|
+
theme?: ThemeType;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function savePreferences(preferences: Preferences): void {
|
|
11
|
+
if (typeof window === "undefined") {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const raw = window.localStorage?.getItem("ds-one:preferences");
|
|
17
|
+
const existing = raw ? (JSON.parse(raw) as Record<string, unknown>) : {};
|
|
18
|
+
const next = { ...existing, ...preferences };
|
|
19
|
+
window.localStorage?.setItem("ds-one:preferences", JSON.stringify(next));
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.warn("ds-one: unable to persist preferences", error);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Currency label utilities for regional price display
|
|
3
|
+
*
|
|
4
|
+
* Note: This module provides currency symbols/labels based on language and region.
|
|
5
|
+
* Consider moving this functionality into i18n.ts as it's region/locale-related.
|
|
6
|
+
* Actual price values will be stored in a database or managed via Stripe.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { LanguageCode } from "./i18n";
|
|
10
|
+
|
|
11
|
+
type PriceLabelOptions = {
|
|
12
|
+
language: LanguageCode;
|
|
13
|
+
country?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// Simple price label mapping based on language/country
|
|
17
|
+
const PRICE_LABELS: Record<string, string> = {
|
|
18
|
+
da: "kr.",
|
|
19
|
+
nb: "kr.",
|
|
20
|
+
sv: "kr.",
|
|
21
|
+
de: "€",
|
|
22
|
+
en: "$",
|
|
23
|
+
pt: "€",
|
|
24
|
+
es: "€",
|
|
25
|
+
zh: "¥",
|
|
26
|
+
ja: "¥",
|
|
27
|
+
ko: "₩",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export function getPriceLabel(options: PriceLabelOptions): string {
|
|
31
|
+
const { language, country } = options;
|
|
32
|
+
|
|
33
|
+
// If country is provided, try to map it to a currency
|
|
34
|
+
if (country) {
|
|
35
|
+
const countryUpper = country.toUpperCase();
|
|
36
|
+
// Add country-specific mappings if needed
|
|
37
|
+
if (countryUpper === "US" || countryUpper === "USA") {
|
|
38
|
+
return "$";
|
|
39
|
+
}
|
|
40
|
+
if (countryUpper === "GB" || countryUpper === "UK") {
|
|
41
|
+
return "£";
|
|
42
|
+
}
|
|
43
|
+
if (countryUpper === "JP" || countryUpper === "JPN") {
|
|
44
|
+
return "¥";
|
|
45
|
+
}
|
|
46
|
+
if (countryUpper === "CN" || countryUpper === "CHN") {
|
|
47
|
+
return "¥";
|
|
48
|
+
}
|
|
49
|
+
if (countryUpper === "KR" || countryUpper === "KOR") {
|
|
50
|
+
return "₩";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Fall back to language-based mapping
|
|
55
|
+
const primaryLang = language.toLowerCase().split(/[-_]/)[0];
|
|
56
|
+
return PRICE_LABELS[primaryLang] || "$";
|
|
57
|
+
}
|
package/DS1/2-core/ds-button.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Core button component
|
|
3
3
|
|
|
4
4
|
import { LitElement, html, css, type PropertyValues } from "lit";
|
|
5
|
-
import { getText, currentLanguage } from "../
|
|
5
|
+
import { getText, currentLanguage } from "../0-face/i18n";
|
|
6
6
|
|
|
7
7
|
export class Button extends LitElement {
|
|
8
8
|
static properties = {
|
package/DS1/2-core/ds-cycle.ts
CHANGED
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
getAvailableLanguagesSync,
|
|
6
6
|
getLanguageDisplayName,
|
|
7
7
|
setLanguage,
|
|
8
|
-
} from "../
|
|
9
|
-
import type { LanguageCode } from "../
|
|
10
|
-
import { currentTheme, setTheme } from "../
|
|
11
|
-
import type { ThemeType } from "../
|
|
12
|
-
import {
|
|
8
|
+
} from "../0-face/i18n";
|
|
9
|
+
import type { LanguageCode } from "../0-face/i18n";
|
|
10
|
+
import { currentTheme, setTheme } from "../0-face/theme";
|
|
11
|
+
import type { ThemeType } from "../0-face/theme";
|
|
12
|
+
import { savePreferences } from "../0-face/preferences";
|
|
13
13
|
import "./ds-button";
|
|
14
14
|
import "./ds-icon";
|
|
15
15
|
|
|
@@ -362,8 +362,8 @@ export class Cycle extends LitElement {
|
|
|
362
362
|
setLanguage(newLanguage as LanguageCode);
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
-
// Save
|
|
366
|
-
|
|
365
|
+
// Save preferences
|
|
366
|
+
savePreferences({ language: newLanguage as LanguageCode });
|
|
367
367
|
|
|
368
368
|
// Dispatch language change event
|
|
369
369
|
window.dispatchEvent(
|
|
@@ -383,8 +383,8 @@ export class Cycle extends LitElement {
|
|
|
383
383
|
// Set the new theme using the shared helper
|
|
384
384
|
setTheme(newTheme as ThemeType);
|
|
385
385
|
|
|
386
|
-
// Save
|
|
387
|
-
|
|
386
|
+
// Save preferences
|
|
387
|
+
savePreferences({ theme: newTheme as ThemeType });
|
|
388
388
|
|
|
389
389
|
// Theme helper already emits the change event, so no manual dispatch here
|
|
390
390
|
} else if (this.type === "accent-color") {
|
|
@@ -402,8 +402,8 @@ export class Cycle extends LitElement {
|
|
|
402
402
|
// Apply the new accent color
|
|
403
403
|
applyAccentColor();
|
|
404
404
|
|
|
405
|
-
// Save
|
|
406
|
-
|
|
405
|
+
// Save preferences
|
|
406
|
+
savePreferences({ accentColor: newColor });
|
|
407
407
|
|
|
408
408
|
// Dispatch accent color change event
|
|
409
409
|
window.dispatchEvent(
|
|
@@ -423,8 +423,8 @@ export class Cycle extends LitElement {
|
|
|
423
423
|
// Save the new notes style medium
|
|
424
424
|
saveNotesStyleMedium(newStyle);
|
|
425
425
|
|
|
426
|
-
// Save
|
|
427
|
-
|
|
426
|
+
// Save preferences
|
|
427
|
+
savePreferences({ notesStyleMedium: newStyle });
|
|
428
428
|
|
|
429
429
|
// Dispatch notes style medium change event
|
|
430
430
|
window.dispatchEvent(
|
|
@@ -444,8 +444,8 @@ export class Cycle extends LitElement {
|
|
|
444
444
|
// Save the new note behavior
|
|
445
445
|
savePageStyle(newBehavior);
|
|
446
446
|
|
|
447
|
-
// Save
|
|
448
|
-
|
|
447
|
+
// Save preferences
|
|
448
|
+
savePreferences({ pageStyle: newBehavior });
|
|
449
449
|
|
|
450
450
|
// Dispatch note behavior change event
|
|
451
451
|
window.dispatchEvent(
|
|
@@ -465,8 +465,8 @@ export class Cycle extends LitElement {
|
|
|
465
465
|
// Save the new page style
|
|
466
466
|
savePageStyle(newIconOnlyValue);
|
|
467
467
|
|
|
468
|
-
// Save
|
|
469
|
-
|
|
468
|
+
// Save preferences
|
|
469
|
+
savePreferences({ pageStyle: newIconOnlyValue });
|
|
470
470
|
|
|
471
471
|
// No label update for icon-only type
|
|
472
472
|
this.label = "";
|
|
@@ -736,4 +736,3 @@ declare global {
|
|
|
736
736
|
"ds-cycle": Cycle;
|
|
737
737
|
}
|
|
738
738
|
}
|
|
739
|
-
|
|
@@ -3,9 +3,9 @@ import { LitElement, html, css } from "lit";
|
|
|
3
3
|
/**
|
|
4
4
|
* A component for displaying the current year
|
|
5
5
|
*
|
|
6
|
-
* @element ds-
|
|
6
|
+
* @element ds-date
|
|
7
7
|
*/
|
|
8
|
-
export class
|
|
8
|
+
export class DateComponent extends LitElement {
|
|
9
9
|
static styles = css`
|
|
10
10
|
:host {
|
|
11
11
|
display: inline;
|
|
@@ -21,11 +21,11 @@ export class Year extends LitElement {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
customElements.define("ds-
|
|
24
|
+
customElements.define("ds-date", DateComponent);
|
|
25
25
|
|
|
26
26
|
declare global {
|
|
27
27
|
interface HTMLElementTagNameMap {
|
|
28
|
-
"ds-
|
|
28
|
+
"ds-date": DateComponent;
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// here should be an input component
|
package/DS1/2-core/ds-text.ts
CHANGED
package/DS1/2-core/ds-tooltip.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LitElement, html, css } from "lit";
|
|
2
|
-
import { translate, getNotionText } from "../
|
|
2
|
+
import { translate, getNotionText } from "../0-face/i18n";
|
|
3
3
|
|
|
4
4
|
export class Tooltip extends LitElement {
|
|
5
5
|
static properties = {
|
|
@@ -84,7 +84,9 @@ export class Tooltip extends LitElement {
|
|
|
84
84
|
pointer-events: none;
|
|
85
85
|
height: calc(var(--08) * var(--scaling-factor));
|
|
86
86
|
opacity: 0;
|
|
87
|
-
transition:
|
|
87
|
+
transition:
|
|
88
|
+
opacity 120ms ease,
|
|
89
|
+
transform 120ms ease;
|
|
88
90
|
background-color: light-dark(var(--black), var(--white));
|
|
89
91
|
color: light-dark(var(--white), var(--black));
|
|
90
92
|
border-radius: 0;
|
|
@@ -192,4 +194,3 @@ declare global {
|
|
|
192
194
|
"ds-tooltip": Tooltip;
|
|
193
195
|
}
|
|
194
196
|
}
|
|
195
|
-
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { LitElement, html, css } from "lit";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* A component for double navigation (previous/next)
|
|
5
|
+
*
|
|
6
|
+
* @element doublenav-v1
|
|
7
|
+
* @prop {string} previous - URL for previous link
|
|
8
|
+
* @prop {string} next - URL for next link
|
|
9
|
+
* @prop {string} previousText - Text for previous link
|
|
10
|
+
* @prop {string} nextText - Text for next link
|
|
11
|
+
* @prop {string} overlay - Overlay color (blue, red, orange, green, yellow)
|
|
12
|
+
*/
|
|
13
|
+
export class DoubleNav extends LitElement {
|
|
14
|
+
static get properties() {
|
|
15
|
+
return {
|
|
16
|
+
previous: { type: String, reflect: true },
|
|
17
|
+
next: { type: String, reflect: true },
|
|
18
|
+
previousText: { type: String, reflect: true, attribute: "previous-text" },
|
|
19
|
+
nextText: { type: String, reflect: true, attribute: "next-text" },
|
|
20
|
+
overlay: { type: String, reflect: true },
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare previous: string;
|
|
25
|
+
declare next: string;
|
|
26
|
+
declare previousText: string;
|
|
27
|
+
declare nextText: string;
|
|
28
|
+
declare overlay?: string;
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
super();
|
|
32
|
+
this.previous = "";
|
|
33
|
+
this.next = "";
|
|
34
|
+
this.previousText = "";
|
|
35
|
+
this.nextText = "";
|
|
36
|
+
this.overlay = "";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static styles = css`
|
|
40
|
+
:host {
|
|
41
|
+
display: flex;
|
|
42
|
+
justify-content: space-between;
|
|
43
|
+
gap: calc(5px * var(--scaling-factor));
|
|
44
|
+
padding: calc(2px * var(--scaling-factor));
|
|
45
|
+
align-items: center;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
a {
|
|
49
|
+
display: inline-flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
gap: calc(5px * var(--scaling-factor));
|
|
52
|
+
text-decoration: none;
|
|
53
|
+
color: inherit;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.nav-previous {
|
|
57
|
+
justify-self: start;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.nav-next {
|
|
61
|
+
justify-self: end;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.nav-previous icon-v1 {
|
|
65
|
+
order: -1;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.nav-next icon-v1 {
|
|
69
|
+
padding-top: 3px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.nav-previous icon-v1 {
|
|
73
|
+
padding-top: 3px;
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
render() {
|
|
78
|
+
return html`
|
|
79
|
+
${this.previous
|
|
80
|
+
? html`
|
|
81
|
+
<a href="${this.previous}" class="nav-previous">
|
|
82
|
+
<icon-v1 type="left"></icon-v1>
|
|
83
|
+
<ds-text>${this.previousText || "Previous"}</ds-text>
|
|
84
|
+
</a>
|
|
85
|
+
`
|
|
86
|
+
: html`<div></div>`}
|
|
87
|
+
${this.next
|
|
88
|
+
? html`
|
|
89
|
+
<a href="${this.next}" class="nav-next">
|
|
90
|
+
<ds-text>${this.nextText || "Next"}</ds-text>
|
|
91
|
+
<icon-v1 type="right"></icon-v1>
|
|
92
|
+
</a>
|
|
93
|
+
`
|
|
94
|
+
: html`<div></div>`}
|
|
95
|
+
`;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
customElements.define("doublenav-v1", DoubleNav);
|
|
100
|
+
|
|
101
|
+
declare global {
|
|
102
|
+
interface HTMLElementTagNameMap {
|
|
103
|
+
"doublenav-v1": DoubleNav;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -3,14 +3,14 @@ import { LitElement, html, css } from "lit";
|
|
|
3
3
|
/**
|
|
4
4
|
* A component for double navigation (previous/next)
|
|
5
5
|
*
|
|
6
|
-
* @element
|
|
6
|
+
* @element portfolio-doublenav
|
|
7
7
|
* @prop {string} previous - URL for previous link
|
|
8
8
|
* @prop {string} next - URL for next link
|
|
9
9
|
* @prop {string} previousText - Text for previous link
|
|
10
10
|
* @prop {string} nextText - Text for next link
|
|
11
11
|
* @prop {string} overlay - Overlay color (blue, red, orange, green, yellow)
|
|
12
12
|
*/
|
|
13
|
-
export class
|
|
13
|
+
export class PortfolioDoubleNav extends LitElement {
|
|
14
14
|
static get properties() {
|
|
15
15
|
return {
|
|
16
16
|
previous: { type: String, reflect: true },
|
|
@@ -96,11 +96,10 @@ export class DoubleNav extends LitElement {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
customElements.define("
|
|
99
|
+
customElements.define("portfolio-doublenav", PortfolioDoubleNav);
|
|
100
100
|
|
|
101
101
|
declare global {
|
|
102
102
|
interface HTMLElementTagNameMap {
|
|
103
|
-
"
|
|
103
|
+
"portfolio-doublenav": PortfolioDoubleNav;
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
import { LitElement, html, css } from "lit";
|
|
3
|
+
|
|
4
|
+
export class PortfolioPanel extends LitElement {
|
|
5
|
+
static styles = css`
|
|
6
|
+
:host {
|
|
7
|
+
display: flex;
|
|
8
|
+
flex-direction: row;
|
|
9
|
+
height: var(--08);
|
|
10
|
+
align-items: end;
|
|
11
|
+
gap: var(--025);
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
|
|
15
|
+
render() {
|
|
16
|
+
return html`<slot></slot>`;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
customElements.define("portfolio-panel", PortfolioPanel);
|
|
21
|
+
|
|
22
|
+
declare global {
|
|
23
|
+
interface HTMLElementTagNameMap {
|
|
24
|
+
"portfolio-panel": PortfolioPanel;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|