@appaflytech/zeyrek-ai-mcp 0.0.7 → 0.0.9
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.md +27 -21
- package/dist/config.js +2 -0
- package/dist/knowledge/backendConstraints.js +3 -0
- package/dist/knowledge/componentCatalog.js +172 -33
- package/dist/knowledge/componentEvents.js +35 -4
- package/dist/knowledge/errorPath.js +1 -1
- package/dist/knowledge/normalize.js +474 -23
- package/dist/knowledge/propTypes.js +5 -4
- package/dist/knowledge/rules.js +113 -6
- package/dist/knowledge/styleResolve.js +52 -5
- package/dist/knowledge/themeResolve.js +936 -0
- package/dist/knowledge/themeRules.js +221 -0
- package/dist/knowledge/themeSchema.js +335 -0
- package/dist/platform/domSummary.js +144 -0
- package/dist/platform/http.js +10 -2
- package/dist/platform/screenshot.js +492 -29
- package/dist/platform/screenshotMemory.js +55 -0
- package/dist/platform/strictArguments.js +32 -0
- package/dist/platform/writeDiff.js +6 -3
- package/dist/resources/examples/layout-app-shell.json +1 -1
- package/dist/resources/examples/page-sign-in.json +1 -1
- package/dist/resources/examples/theme-brand.json +162 -0
- package/dist/resources/guides/component.md +8 -2
- package/dist/resources/guides/expressions.md +6 -0
- package/dist/resources/guides/getting-started.md +6 -0
- package/dist/resources/guides/layout.md +36 -26
- package/dist/resources/guides/microservice.md +160 -6
- package/dist/resources/guides/page.md +165 -59
- package/dist/resources/guides/theme.md +210 -0
- package/dist/resources/guides/translation.md +13 -10
- package/dist/resources/guides/workflow.md +141 -7
- package/dist/resources/schema-fingerprint.json +2 -2
- package/dist/resources/schemas/CreateMicroserviceCommand.json +4 -1
- package/dist/resources/schemas/CreateWorkflowCommand.json +4 -1
- package/dist/resources/schemas/PreviewMicroserviceCommand.json +4 -1
- package/dist/resources/schemas/PreviewWorkflowCommand.json +4 -1
- package/dist/resources/schemas/StepDto.json +4 -1
- package/dist/resources/schemas/UpdateMicroserviceCommand.json +4 -1
- package/dist/resources/schemas/UpdateWorkflowCommand.json +4 -1
- package/dist/server.js +52 -42
- package/dist/tools/components.js +8 -0
- package/dist/tools/designSchemaPatch.js +152 -0
- package/dist/tools/flows.js +24 -21
- package/dist/tools/layouts.js +8 -8
- package/dist/tools/microservices.js +74 -10
- package/dist/tools/pages.js +275 -332
- package/dist/tools/projects.js +66 -9
- package/dist/tools/queries.js +72 -6
- package/dist/tools/schemaOps.js +280 -0
- package/dist/tools/screenWrite.js +2 -1
- package/dist/tools/screens.js +0 -7
- package/dist/tools/themes.js +163 -0
- package/dist/tools/workflows.js +10 -6
- package/package.json +1 -1
|
@@ -0,0 +1,936 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ÖZET — Bir TEMA kaydının ekrandaki karşılığı: gateway tarafında `Theme.svelte`'nin yaptığının
|
|
3
|
+
* yeniden kurulması. `theme_get(view: 'resolved')` bir projenin temasını bu modülle çözer ve
|
|
4
|
+
* "accent'i ezmedim, ekranda hangi mavi çiziliyor" sorusu çağrı başına yanıtlanabilir olur;
|
|
5
|
+
* `theme_update` de değişikliğin hangi `--ng-*` değişkenini nereden nereye taşıdığını buradan
|
|
6
|
+
* çıkarır.
|
|
7
|
+
*
|
|
8
|
+
* ZİNCİR (`packages/ng-apps-ui/src/shared/theme/`):
|
|
9
|
+
* mod seçimi (`Theme.svelte`) → palet birleşimi (`white.ts` | `dark.ts` + override)
|
|
10
|
+
* → token birleşimi (`tokens.ts`) → form token'ları (`form.ts`) → `buildThemeStyle` (`utils.ts`)
|
|
11
|
+
*
|
|
12
|
+
* KOPYA: gateway frontend workspace'ine dahil DEĞİLDİR (AGENTS §4), paket import edilemez —
|
|
13
|
+
* `styleResolve.ts` ile aynı gerekçe ve aynı risk: kaynak değişir, gateway eski temayı çözer ve
|
|
14
|
+
* ajan yanlış rengi doğru sanır. `test/theme-resolve.test.ts` üç kilitle izler:
|
|
15
|
+
*
|
|
16
|
+
* 1. DAVRANIŞ — varsayılan/koyu/override senaryoları (frontend olmadan da koşar).
|
|
17
|
+
* 2. PARİTE — frontend modülleri dinamik `import()` ile yüklenir; palet/token nesneleri
|
|
18
|
+
* deep-equal, `buildThemeStyle` çıktısı ise METİN OLARAK karşılaştırılır. Şablonun içindeki
|
|
19
|
+
* SEKMELER veridir (style attribute'una öyle basılır), bu yüzden kod 2 boşlukla girintili
|
|
20
|
+
* olsa da şablonun kendi girintisine dokunulmaz.
|
|
21
|
+
* 3. SABİTLER — panelin kuralları (Google Fonts listesi, preset ad kuralı, versiyon sınırı,
|
|
22
|
+
* boşluk anahtarları, `ProjectTheme` üst anahtarları) kaynak metinden okunup karşılaştırılır.
|
|
23
|
+
*
|
|
24
|
+
* Frontend'e yeni bir tema alanı eklendiğinde buraya da eklenir; eklenmezse parite kırmızı yanar.
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* `ProjectTheme`'in TANIDIĞI üst anahtarlar. Panel tanımadığı anahtarı körce taşır
|
|
28
|
+
* (`themeDataToProjectTheme` `...base`), yani yazım hatası kayıtta sessizce yaşar —
|
|
29
|
+
* `theme_get` bunları `unknownKeys` olarak gösterir, `theme_update` şeması reddeder.
|
|
30
|
+
*/
|
|
31
|
+
export const THEME_TOP_LEVEL_KEYS = [
|
|
32
|
+
'mode', 'palette', 'paletteDark', 'fontFamily', 'headingFontFamily', 'typeScale',
|
|
33
|
+
'fontSize', 'fontWeight', 'borderRadius', 'radiusScale', 'spacing', 'spacingScale',
|
|
34
|
+
'shadow', 'defaultInputSize', 'colors', 'actions', 'presets', 'componentStyles',
|
|
35
|
+
'componentPresets'
|
|
36
|
+
];
|
|
37
|
+
const isPlainObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
38
|
+
/* ---- Palet ve token tabanları (`white.ts` · `dark.ts` · `tokens.ts` kopyası) ---- */
|
|
39
|
+
export const WHITE_PALETTE = {
|
|
40
|
+
text: {
|
|
41
|
+
primary: '#262626',
|
|
42
|
+
secondary: '#4d4d4d',
|
|
43
|
+
disabled: '#979797',
|
|
44
|
+
},
|
|
45
|
+
background: {
|
|
46
|
+
canvas: '#fff',
|
|
47
|
+
surface: '#fff',
|
|
48
|
+
surfaceAlt: '#F6F6F6',
|
|
49
|
+
readonly: '#F8F8F8',
|
|
50
|
+
disabled: '#F5F5F5',
|
|
51
|
+
overlay: '#364b764d',
|
|
52
|
+
/** Zıt zemin: aydınlık temada koyu yüzey (tooltip, ters vurgular). */
|
|
53
|
+
inverse: '#262626',
|
|
54
|
+
},
|
|
55
|
+
border: {
|
|
56
|
+
primary: '#dfe1e6',
|
|
57
|
+
secondary: '#9E9E9E',
|
|
58
|
+
},
|
|
59
|
+
accent: {
|
|
60
|
+
primary: '#0052CC',
|
|
61
|
+
hover: '#4688EC',
|
|
62
|
+
muted: '#E6F0FF',
|
|
63
|
+
subtle: '#F2F7FF',
|
|
64
|
+
},
|
|
65
|
+
status: {
|
|
66
|
+
info: '#F8F8F8',
|
|
67
|
+
success: '#00875A',
|
|
68
|
+
warning: '#FFAB00',
|
|
69
|
+
error: '#DE350B',
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
export const DARK_PALETTE = {
|
|
73
|
+
text: {
|
|
74
|
+
primary: '#E4E4E4',
|
|
75
|
+
secondary: '#A0A0A0',
|
|
76
|
+
disabled: '#606060',
|
|
77
|
+
},
|
|
78
|
+
background: {
|
|
79
|
+
canvas: '#111111',
|
|
80
|
+
surface: '#262626',
|
|
81
|
+
surfaceAlt: '#1A1A1A',
|
|
82
|
+
readonly: '#1E1E1E',
|
|
83
|
+
disabled: '#2A2A2A',
|
|
84
|
+
overlay: '#364b764d',
|
|
85
|
+
/** Zıt zemin: karanlık temada aydınlık yüzey. */
|
|
86
|
+
inverse: '#F6F6F6',
|
|
87
|
+
},
|
|
88
|
+
border: {
|
|
89
|
+
primary: '#3A3A3A',
|
|
90
|
+
secondary: '#5A5A5A',
|
|
91
|
+
},
|
|
92
|
+
accent: {
|
|
93
|
+
// Karanlıkta accent'in kendisi yeterince okunur; hover bir tık açılır.
|
|
94
|
+
primary: '#4C8DFF',
|
|
95
|
+
hover: '#7AABFF',
|
|
96
|
+
// `muted` ve `subtle` DOLGU rolündedir (seçili satır, çip zemini). Aydınlık
|
|
97
|
+
// paletten kopyalandıkları sürece karanlık zeminde beyaz blok gibi
|
|
98
|
+
// duruyorlardı; artık accent'in koyu tonlarıdır.
|
|
99
|
+
muted: '#16283F',
|
|
100
|
+
subtle: '#111B2B',
|
|
101
|
+
},
|
|
102
|
+
status: {
|
|
103
|
+
// `info` bir renk değil, nötr durum YÜZEYİDİR — aydınlıkta #F8F8F8, yani
|
|
104
|
+
// zeminden bir tık ayrık bir gri. Karanlıkta karşılığı da öyle olmalı.
|
|
105
|
+
info: '#2E2E2E',
|
|
106
|
+
// Uyarı/başarı/hata dolgu olarak kullanılıyor ve üstlerine kontrast metin
|
|
107
|
+
// yazılıyor; hue korunur, karanlık zeminde seçilebilmeleri için açılır.
|
|
108
|
+
success: '#2FA37A',
|
|
109
|
+
warning: '#E5A93C',
|
|
110
|
+
error: '#F2634B',
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
const BASE_TOKENS = {
|
|
114
|
+
fontFamily: '"Inter", sans-serif',
|
|
115
|
+
fontSource: 'Inter',
|
|
116
|
+
fontSize: '14px',
|
|
117
|
+
fontWeight: '400',
|
|
118
|
+
borderRadius: '4px',
|
|
119
|
+
spacing: '10px',
|
|
120
|
+
defaultInputSize: 'md',
|
|
121
|
+
shadow: {
|
|
122
|
+
offsetX: 0,
|
|
123
|
+
offsetY: 4,
|
|
124
|
+
blur: 6,
|
|
125
|
+
spread: -1,
|
|
126
|
+
color: '#000000',
|
|
127
|
+
opacity: 10,
|
|
128
|
+
},
|
|
129
|
+
colors: {
|
|
130
|
+
blue: {
|
|
131
|
+
b50: '#F5F9FF',
|
|
132
|
+
b100: '#E5F1FF',
|
|
133
|
+
b150: '#DCE8FE',
|
|
134
|
+
b200: '#BFDBFE',
|
|
135
|
+
b300: '#92C5FD',
|
|
136
|
+
b400: '#60A5FA',
|
|
137
|
+
b500: '#3C82F6',
|
|
138
|
+
b600: '#3170F9',
|
|
139
|
+
b700: '#1C4ED8',
|
|
140
|
+
b800: '#1D40AE',
|
|
141
|
+
b900: '#1F3A8A',
|
|
142
|
+
},
|
|
143
|
+
red: {
|
|
144
|
+
r50: '#FFF6F6',
|
|
145
|
+
r100: '#FEEAEA',
|
|
146
|
+
r150: '#FEDCDC',
|
|
147
|
+
r200: '#FECACA',
|
|
148
|
+
r500: '#EF4444',
|
|
149
|
+
r600: '#DC2625',
|
|
150
|
+
r700: '#B91C1B',
|
|
151
|
+
r800: '#991B1B',
|
|
152
|
+
r900: '#7F1C1D',
|
|
153
|
+
},
|
|
154
|
+
grey: {
|
|
155
|
+
r100: '#F6F6F6',
|
|
156
|
+
r150: '#EBEBEB',
|
|
157
|
+
r200: '#DFDFDF',
|
|
158
|
+
r300: '#C4C4C4',
|
|
159
|
+
r400: '#A0A0A0',
|
|
160
|
+
r500: '#808080',
|
|
161
|
+
r600: '#808080',
|
|
162
|
+
r700: '#555555',
|
|
163
|
+
r800: '#222222',
|
|
164
|
+
r900: '#0D0D0D',
|
|
165
|
+
},
|
|
166
|
+
yellow: {
|
|
167
|
+
r50: '#FFFDF5',
|
|
168
|
+
r100: '#FFF9E0',
|
|
169
|
+
r150: '#FEF3C7',
|
|
170
|
+
r200: '#FDE68A',
|
|
171
|
+
r300: '#FCD34D',
|
|
172
|
+
r400: '#FBBF24',
|
|
173
|
+
r500: '#F59E0B',
|
|
174
|
+
r600: '#CD6F00',
|
|
175
|
+
r700: '#B45309',
|
|
176
|
+
r800: '#92400E',
|
|
177
|
+
r900: '#78350F',
|
|
178
|
+
},
|
|
179
|
+
green: {
|
|
180
|
+
r50: '#F4FCF8',
|
|
181
|
+
r100: '#ECFDF5',
|
|
182
|
+
r150: '#D1FAE5',
|
|
183
|
+
r200: '#A7F3D0',
|
|
184
|
+
r500: '#10B981',
|
|
185
|
+
r900: '#064E3B',
|
|
186
|
+
},
|
|
187
|
+
purple: {
|
|
188
|
+
r50: '#F5F7FF',
|
|
189
|
+
r100: '#EBEFFF',
|
|
190
|
+
r150: '#E0E7FF',
|
|
191
|
+
r200: '#C7D2FE',
|
|
192
|
+
r900: '#302E81',
|
|
193
|
+
},
|
|
194
|
+
plump: {
|
|
195
|
+
r50: '#FFF8FF',
|
|
196
|
+
r100: '#FDECFF',
|
|
197
|
+
r150: '#F4DCF8',
|
|
198
|
+
r200: '#EECFF3',
|
|
199
|
+
r300: '#E1B6E8',
|
|
200
|
+
r400: '#CF95D8',
|
|
201
|
+
r500: '#BD75C7',
|
|
202
|
+
r600: '#AE57BB',
|
|
203
|
+
r700: '#9846A4',
|
|
204
|
+
r800: '#893F94',
|
|
205
|
+
r900: '#6E3275',
|
|
206
|
+
},
|
|
207
|
+
teal: {
|
|
208
|
+
r50: '#F0FDFA',
|
|
209
|
+
r100: '#CCFBF1',
|
|
210
|
+
r150: '#99F6E4',
|
|
211
|
+
r200: '#5EEAD4',
|
|
212
|
+
r500: '#14B8A6',
|
|
213
|
+
r600: '#0D9488',
|
|
214
|
+
r700: '#0F766E',
|
|
215
|
+
r800: '#115E59',
|
|
216
|
+
r900: '#134E4A',
|
|
217
|
+
},
|
|
218
|
+
pink: {
|
|
219
|
+
r50: '#FDF2F8',
|
|
220
|
+
r100: '#FCE7F3',
|
|
221
|
+
r150: '#FBCFE8',
|
|
222
|
+
r200: '#F9A8D4',
|
|
223
|
+
r500: '#EC4899',
|
|
224
|
+
r600: '#DB2777',
|
|
225
|
+
r700: '#BE185D',
|
|
226
|
+
r800: '#9D174D',
|
|
227
|
+
r900: '#831843',
|
|
228
|
+
},
|
|
229
|
+
cyan: {
|
|
230
|
+
r50: '#ECFEFF',
|
|
231
|
+
r100: '#CFFAFE',
|
|
232
|
+
r150: '#A5F3FC',
|
|
233
|
+
r200: '#67E8F9',
|
|
234
|
+
r500: '#06B6D4',
|
|
235
|
+
r600: '#0891B2',
|
|
236
|
+
r700: '#0E7490',
|
|
237
|
+
r800: '#155E75',
|
|
238
|
+
r900: '#164E63',
|
|
239
|
+
},
|
|
240
|
+
orange: {
|
|
241
|
+
r50: '#FFF7ED',
|
|
242
|
+
r100: '#FFEDD5',
|
|
243
|
+
r150: '#FED7AA',
|
|
244
|
+
r200: '#FDBA74',
|
|
245
|
+
r500: '#F97316',
|
|
246
|
+
r600: '#EA580C',
|
|
247
|
+
r700: '#C2410C',
|
|
248
|
+
r800: '#9A3412',
|
|
249
|
+
r900: '#7C2D12',
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
};
|
|
253
|
+
export const TOKENS = BASE_TOKENS;
|
|
254
|
+
/** Palet gruplarının anahtarları — paletin KENDİSİNDEN türer ki listeyi ikinci kez yazmayalım. */
|
|
255
|
+
export const PALETTE_GROUPS = Object.fromEntries(Object.entries(WHITE_PALETTE).map(([group, values]) => [group, Object.keys(values)]));
|
|
256
|
+
/* ---- Birleştiriciler ve ölçekler (`utils.ts` kopyası) ---- */
|
|
257
|
+
export function mergePalette(base, overrides) {
|
|
258
|
+
const result = { ...base };
|
|
259
|
+
for (const [group, values] of Object.entries(overrides)) {
|
|
260
|
+
if (values === undefined)
|
|
261
|
+
continue;
|
|
262
|
+
const baseValue = result[group];
|
|
263
|
+
result[group] = isPlainObject(baseValue) && isPlainObject(values) ? { ...baseValue, ...values } : values;
|
|
264
|
+
}
|
|
265
|
+
return result;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Renk rampalarını aile aile birleştirir: bir ailenin yalnız verilen tonları değişir. Temanın
|
|
269
|
+
* `colors` alanının panelde UI'ı YOKTUR, yalnız veri yoluyla (bu tool'la ya da şablonla) kurulur.
|
|
270
|
+
*/
|
|
271
|
+
export function mergeColorRamps(base, overrides) {
|
|
272
|
+
const result = { ...base };
|
|
273
|
+
for (const [family, tones] of Object.entries(overrides)) {
|
|
274
|
+
if (!tones)
|
|
275
|
+
continue;
|
|
276
|
+
const baseFamily = result[family];
|
|
277
|
+
result[family] = isPlainObject(baseFamily) ? { ...baseFamily, ...tones } : tones;
|
|
278
|
+
}
|
|
279
|
+
return result;
|
|
280
|
+
}
|
|
281
|
+
/** Metin seviyelerinin taban puntoya oranı; `text.style.ts`'in eski gömülü çarpanları. */
|
|
282
|
+
export const TYPE_SCALE_DEFAULTS = {
|
|
283
|
+
h1: 2.25,
|
|
284
|
+
h2: 2,
|
|
285
|
+
h3: 1.7,
|
|
286
|
+
h4: 1.15,
|
|
287
|
+
label: 1,
|
|
288
|
+
p: 0.925,
|
|
289
|
+
small: 0.715
|
|
290
|
+
};
|
|
291
|
+
/** Köşe kademelerinin `--ng-rounded`'a oranı; 4px tabanda sm=2px, lg=12px. */
|
|
292
|
+
export const RADIUS_SCALE_DEFAULTS = { sm: 0.5, lg: 3 };
|
|
293
|
+
/** Hap biçimi orana bağlanmaz; her tabanda tam yuvarlak kalmalıdır. */
|
|
294
|
+
export const RADIUS_PILL_DEFAULT = '999px';
|
|
295
|
+
/** Boşluk kademelerinin `--ng-spacing`'e oranı; sm/md/lg builder'ın gap preset'leriyle aynı. */
|
|
296
|
+
export const SPACING_SCALE_DEFAULTS = { xs: 0.4, sm: 0.8, md: 1.6, lg: 3.2, xl: 4.8 };
|
|
297
|
+
/**
|
|
298
|
+
* Oranın kabul aralığı (panelin `readScaleRatio`'su). Dışarıda kalan değer panelde ESKİ değeri
|
|
299
|
+
* korur, temada ise `mergeRatioScale` tarafından sessizce yok sayılır — THEME-007 bunu yakalar.
|
|
300
|
+
*/
|
|
301
|
+
export const SCALE_RATIO_MAX = 20;
|
|
302
|
+
/** Oran override'ları tabana bindirilir; 0/negatif/geçersiz değer tabanı korur. */
|
|
303
|
+
function mergeRatioScale(defaults, overrides) {
|
|
304
|
+
const result = { ...defaults };
|
|
305
|
+
for (const [level, value] of Object.entries(overrides ?? {})) {
|
|
306
|
+
if (typeof value === 'number' && value > 0)
|
|
307
|
+
result[level] = value;
|
|
308
|
+
}
|
|
309
|
+
return result;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* `--ng-radius-*` kademeleri. `md`, `--ng-rounded`'ın takma adıdır: kademeli adları komponentler
|
|
313
|
+
* ve builder kullanır, eski tüketiciler `--ng-rounded`'ı görmeye devam eder.
|
|
314
|
+
*/
|
|
315
|
+
export function buildRadiusScaleVars(scale) {
|
|
316
|
+
const ratios = mergeRatioScale(RADIUS_SCALE_DEFAULTS, scale);
|
|
317
|
+
const pill = scale?.pill || RADIUS_PILL_DEFAULT;
|
|
318
|
+
return [
|
|
319
|
+
`--ng-radius-sm: calc(var(--ng-rounded) * ${ratios.sm});`,
|
|
320
|
+
'--ng-radius-md: var(--ng-rounded);',
|
|
321
|
+
`--ng-radius-lg: calc(var(--ng-rounded) * ${ratios.lg});`,
|
|
322
|
+
`--ng-radius-pill: ${pill};`
|
|
323
|
+
].join('\n\t');
|
|
324
|
+
}
|
|
325
|
+
/** `--ng-spacing-xs..xl`; eski `--ng-spacing-small/large` tüketicileri bozulmasın diye onlar kalır. */
|
|
326
|
+
export function buildSpacingScaleVars(scale) {
|
|
327
|
+
const ratios = mergeRatioScale(SPACING_SCALE_DEFAULTS, scale);
|
|
328
|
+
return Object.entries(ratios)
|
|
329
|
+
.map(([level, ratio]) => `--ng-spacing-${level}: calc(var(--ng-spacing) * ${ratio});`)
|
|
330
|
+
.join('\n\t');
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Bir seviyenin mobil karşılığının masaüstüne oranı — bugünkü breakpoint değerlerinden türer.
|
|
334
|
+
* Kullanıcı tek çarpan ayarlar, mobil ona orantılı hareket eder.
|
|
335
|
+
*/
|
|
336
|
+
const TYPE_SCALE_MOBILE_RATIO = {
|
|
337
|
+
h1: 1.7 / 2.25,
|
|
338
|
+
h2: 1.5 / 2,
|
|
339
|
+
h3: 1.3 / 1.7,
|
|
340
|
+
h4: 1 / 1.15
|
|
341
|
+
};
|
|
342
|
+
/**
|
|
343
|
+
* Köşe kademelerinin BİRLEŞİK hâli. Frontend bunu ayrı bir fonksiyonla vermez, doğrudan
|
|
344
|
+
* `buildRadiusScaleVars` içinde üretir; gateway'in `theme_get(view:'resolved')` yanıtında
|
|
345
|
+
* kademeleri SAYI olarak göstermesi gerektiği için burada ayrıca dışa verilir — kural aynı
|
|
346
|
+
* `mergeRatioScale`'den gelir, ikinci bir kopya yoktur.
|
|
347
|
+
*/
|
|
348
|
+
export function mergeRadiusScale(scale) {
|
|
349
|
+
return { ...mergeRatioScale(RADIUS_SCALE_DEFAULTS, scale), pill: scale?.pill || RADIUS_PILL_DEFAULT };
|
|
350
|
+
}
|
|
351
|
+
/** Boşluk kademelerinin birleşik hâli; `mergeRadiusScale` ile aynı gerekçe. */
|
|
352
|
+
export function mergeSpacingScale(scale) {
|
|
353
|
+
return mergeRatioScale(SPACING_SCALE_DEFAULTS, scale);
|
|
354
|
+
}
|
|
355
|
+
/** Ölçek override'ları taban değerlere bindirilir; eksik seviye tabanı korur. */
|
|
356
|
+
export function mergeTypeScale(overrides) {
|
|
357
|
+
const result = { ...TYPE_SCALE_DEFAULTS };
|
|
358
|
+
for (const [level, value] of Object.entries(overrides ?? {})) {
|
|
359
|
+
if (typeof value === 'number' && value > 0)
|
|
360
|
+
result[level] = value;
|
|
361
|
+
}
|
|
362
|
+
return result;
|
|
363
|
+
}
|
|
364
|
+
/** Ölçekten `--ng-font-size-*` değişkenlerini üretir (masaüstü + mobil). */
|
|
365
|
+
export function buildTypeScaleVars(scale) {
|
|
366
|
+
const lines = [];
|
|
367
|
+
for (const [level, factor] of Object.entries(scale)) {
|
|
368
|
+
lines.push(`--ng-font-size-${level}: calc(var(--ng-font-size) * ${factor});`);
|
|
369
|
+
const ratio = TYPE_SCALE_MOBILE_RATIO[level];
|
|
370
|
+
if (ratio) {
|
|
371
|
+
const mobile = Math.round(factor * ratio * 1000) / 1000;
|
|
372
|
+
lines.push(`--ng-font-size-${level}-mobile: calc(var(--ng-font-size) * ${mobile});`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return lines.join('\n\t');
|
|
376
|
+
}
|
|
377
|
+
export function mergeTokens(base, overrides) {
|
|
378
|
+
return {
|
|
379
|
+
...base,
|
|
380
|
+
...(overrides.fontFamily !== undefined && {
|
|
381
|
+
fontFamily: `"${overrides.fontFamily}", sans-serif`,
|
|
382
|
+
fontSource: overrides.fontFamily
|
|
383
|
+
}),
|
|
384
|
+
...(overrides.fontSize !== undefined && { fontSize: overrides.fontSize }),
|
|
385
|
+
...(overrides.fontWeight !== undefined && { fontWeight: overrides.fontWeight }),
|
|
386
|
+
...(overrides.spacing !== undefined && { spacing: overrides.spacing }),
|
|
387
|
+
...(overrides.borderRadius !== undefined && { borderRadius: overrides.borderRadius }),
|
|
388
|
+
...(overrides.defaultInputSize !== undefined && { defaultInputSize: overrides.defaultInputSize }),
|
|
389
|
+
...(overrides.shadow !== undefined && { shadow: { ...base.shadow, ...overrides.shadow } }),
|
|
390
|
+
...(overrides.colors !== undefined && { colors: mergeColorRamps(base.colors, overrides.colors) }),
|
|
391
|
+
...(overrides.actions !== undefined && { actions: overrides.actions }),
|
|
392
|
+
...(overrides.headingFontFamily !== undefined && {
|
|
393
|
+
headingFontFamily: `"${overrides.headingFontFamily}", sans-serif`,
|
|
394
|
+
headingFontSource: overrides.headingFontFamily
|
|
395
|
+
}),
|
|
396
|
+
...(overrides.typeScale !== undefined && { typeScale: overrides.typeScale }),
|
|
397
|
+
...(overrides.radiusScale !== undefined && { radiusScale: overrides.radiusScale }),
|
|
398
|
+
...(overrides.spacingScale !== undefined && { spacingScale: overrides.spacingScale })
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
/* ---- Form token'ları (`form.ts` kopyası) ---- */
|
|
402
|
+
export function formTokens(palette, t) {
|
|
403
|
+
return {
|
|
404
|
+
color: {
|
|
405
|
+
default: palette.text.primary,
|
|
406
|
+
disabled: palette.text.disabled,
|
|
407
|
+
placeholder: palette.text.disabled,
|
|
408
|
+
invalid: palette.status.error
|
|
409
|
+
},
|
|
410
|
+
background: {
|
|
411
|
+
default: palette.background.surface,
|
|
412
|
+
disabled: palette.background.disabled,
|
|
413
|
+
readonly: palette.background.readonly
|
|
414
|
+
},
|
|
415
|
+
border: {
|
|
416
|
+
// Odak halkası temayı izler: accent'i turuncu yapan projede mavi halka kalmamalı.
|
|
417
|
+
default: palette.border.primary,
|
|
418
|
+
focus: palette.accent.hover,
|
|
419
|
+
disabled: palette.border.primary,
|
|
420
|
+
invalid: palette.status.error
|
|
421
|
+
},
|
|
422
|
+
fontFamily: t.fontFamily,
|
|
423
|
+
defaultSize: t.defaultInputSize,
|
|
424
|
+
fontSize: {
|
|
425
|
+
sm: `calc(${t.fontSize} * 0.9)`,
|
|
426
|
+
md: t.fontSize,
|
|
427
|
+
lg: `calc(${t.fontSize} * 1.125)`
|
|
428
|
+
},
|
|
429
|
+
radius: {
|
|
430
|
+
sm: t.borderRadius,
|
|
431
|
+
md: t.borderRadius,
|
|
432
|
+
lg: t.borderRadius
|
|
433
|
+
},
|
|
434
|
+
height: {
|
|
435
|
+
sm: `calc(${t.fontSize} * 2.25)`,
|
|
436
|
+
md: `calc(${t.fontSize} * 2.57)`,
|
|
437
|
+
lg: `calc(${t.fontSize} * 3.25)`
|
|
438
|
+
},
|
|
439
|
+
paddingX: {
|
|
440
|
+
sm: `calc(${t.spacing} * 0.8)`,
|
|
441
|
+
md: t.spacing,
|
|
442
|
+
lg: `calc(${t.spacing} * 1.2)`
|
|
443
|
+
},
|
|
444
|
+
label: {
|
|
445
|
+
color: palette.text.primary,
|
|
446
|
+
fontWeight: '600',
|
|
447
|
+
marginBottom: {
|
|
448
|
+
sm: `calc(${t.spacing} * 0.50)`,
|
|
449
|
+
md: `calc(${t.spacing} * 0.70)`,
|
|
450
|
+
lg: t.spacing
|
|
451
|
+
},
|
|
452
|
+
viewmodeMarginBottom: {
|
|
453
|
+
sm: `calc(${t.spacing} * 0.5)`,
|
|
454
|
+
md: `calc(${t.spacing} * 0.7)`,
|
|
455
|
+
lg: t.spacing
|
|
456
|
+
},
|
|
457
|
+
fontSize: {
|
|
458
|
+
sm: `calc(${t.fontSize} * 0.875)`,
|
|
459
|
+
md: t.fontSize,
|
|
460
|
+
lg: `calc(${t.fontSize} * 1.125)`
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Gölge üçlüsü tek bir gölge tarifinden türer. `color` 7 karakterlik hex DEĞİLSE üçü de
|
|
467
|
+
* GÖRÜNMEZ bir gölgeye düşer ('red' yazmak gölgeyi kapatır) — THEME-004 bunu yakalar.
|
|
468
|
+
*/
|
|
469
|
+
export function shadowTokens(t) {
|
|
470
|
+
const { offsetX, offsetY, blur, spread, color, opacity } = t.shadow;
|
|
471
|
+
if (!color || color.length < 7) {
|
|
472
|
+
const fallback = '0px 0px 0px 0px rgba(0, 0, 0, 0)';
|
|
473
|
+
return { none: 'none', sm: fallback, md: fallback, lg: fallback };
|
|
474
|
+
}
|
|
475
|
+
const r = parseInt(color.slice(1, 3), 16) || 0;
|
|
476
|
+
const g = parseInt(color.slice(3, 5), 16) || 0;
|
|
477
|
+
const b = parseInt(color.slice(5, 7), 16) || 0;
|
|
478
|
+
const a = opacity / 100;
|
|
479
|
+
const smOffsetY = offsetY === 0 ? 0 : (offsetY > 0 ? Math.max(1, Math.round(offsetY * 0.25)) : Math.min(-1, Math.round(offsetY * 0.25)));
|
|
480
|
+
const smBlur = blur === 0 ? 0 : Math.max(1, Math.round(blur * 0.5));
|
|
481
|
+
const lgSpread = Math.max(-20, Math.min(20, Math.round(spread * 3)));
|
|
482
|
+
return {
|
|
483
|
+
none: 'none',
|
|
484
|
+
sm: `${offsetX}px ${smOffsetY}px ${smBlur}px 0px rgba(${r}, ${g}, ${b}, ${a})`,
|
|
485
|
+
md: `${offsetX}px ${offsetY}px ${blur}px ${spread}px rgba(${r}, ${g}, ${b}, ${a})`,
|
|
486
|
+
lg: `${offsetX}px ${Math.round(offsetY * 2.5)}px ${Math.round(blur * 2.5)}px ${lgSpread}px rgba(${r}, ${g}, ${b}, ${a})`
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
export function getContrastColor(hex) {
|
|
490
|
+
if (!hex || hex.length < 7)
|
|
491
|
+
return '#ffffff';
|
|
492
|
+
const r = parseInt(hex.slice(1, 3), 16) || 0;
|
|
493
|
+
const g = parseInt(hex.slice(3, 5), 16) || 0;
|
|
494
|
+
const b = parseInt(hex.slice(5, 7), 16) || 0;
|
|
495
|
+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
496
|
+
return luminance > 0.5 ? '#000000' : '#ffffff';
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Temanın yaydığı TÜM CSS değişkenlerini üreten saf şablon; `Theme.svelte`'nin tek görevi bunu
|
|
500
|
+
* satır içi style olarak basmaktır.
|
|
501
|
+
*
|
|
502
|
+
* Şablonun içindeki SEKMELER veridir (frontend'in çıktısıyla metin eşitliği parite testinin
|
|
503
|
+
* kilididir); kodun 2 boşluklu girintisine bakıp düzeltmeye çalışmayın.
|
|
504
|
+
*/
|
|
505
|
+
export function buildThemeStyle(palette, form, t, shadow, formDefaultSize) {
|
|
506
|
+
const colors = t.colors;
|
|
507
|
+
const actions = t.actions || {};
|
|
508
|
+
return `
|
|
509
|
+
--ng-font: ${t.fontFamily};
|
|
510
|
+
--ng-font-heading: ${t.headingFontFamily || t.fontFamily};
|
|
511
|
+
--ng-font-size: ${t.fontSize};
|
|
512
|
+
--ng-font-weight: ${t.fontWeight};
|
|
513
|
+
${buildTypeScaleVars(mergeTypeScale(t.typeScale))}
|
|
514
|
+
--ng-text-primary: ${palette.text.primary};
|
|
515
|
+
--ng-text-secondary: ${palette.text.secondary};
|
|
516
|
+
--ng-text-disabled: ${palette.text.disabled};
|
|
517
|
+
--ng-background-canvas: ${palette.background.canvas};
|
|
518
|
+
--ng-background-surface-alt: ${palette.background.surfaceAlt};
|
|
519
|
+
--ng-background-surface: ${palette.background.surface};
|
|
520
|
+
--ng-background-readonly: ${palette.background.readonly};
|
|
521
|
+
--ng-background-disabled: ${palette.background.disabled};
|
|
522
|
+
--ng-background-overlay: ${palette.background.overlay};
|
|
523
|
+
--ng-background-inverse: ${palette.background.inverse};
|
|
524
|
+
--ng-border-primary: ${palette.border.primary};
|
|
525
|
+
--ng-border-secondary: ${palette.border.secondary};
|
|
526
|
+
|
|
527
|
+
--ng-accent-primary: ${palette.accent.primary};
|
|
528
|
+
--ng-accent-hover: ${palette.accent.hover};
|
|
529
|
+
--ng-accent-muted: ${palette.accent.muted};
|
|
530
|
+
--ng-accent-subtle: ${palette.accent.subtle};
|
|
531
|
+
--ng-status-info: ${palette.status.info};
|
|
532
|
+
--ng-status-success: ${palette.status.success};
|
|
533
|
+
--ng-status-warning: ${palette.status.warning};
|
|
534
|
+
--ng-status-error: ${palette.status.error};
|
|
535
|
+
|
|
536
|
+
--ng-spacing: ${t.spacing};
|
|
537
|
+
--ng-spacing-small: calc(var(--ng-spacing) / 2);
|
|
538
|
+
--ng-spacing-large: calc(var(--ng-spacing) * 1.5);
|
|
539
|
+
${buildSpacingScaleVars(t.spacingScale)}
|
|
540
|
+
--ng-rounded: ${t.borderRadius};
|
|
541
|
+
${buildRadiusScaleVars(t.radiusScale)}
|
|
542
|
+
|
|
543
|
+
--ng-shadow-none: ${shadow.none};
|
|
544
|
+
--ng-shadow-sm: ${shadow.sm};
|
|
545
|
+
--ng-shadow-md: ${shadow.md};
|
|
546
|
+
--ng-shadow-lg: ${shadow.lg};
|
|
547
|
+
|
|
548
|
+
--ng-form-default-size: ${formDefaultSize};
|
|
549
|
+
|
|
550
|
+
--ng-form-color: ${form.color.default};
|
|
551
|
+
--ng-form-color-disabled: ${form.color.disabled};
|
|
552
|
+
--ng-form-color-placeholder: ${form.color.placeholder};
|
|
553
|
+
--ng-form-color-invalid: ${form.color.invalid};
|
|
554
|
+
--ng-form-background: color-mix(in srgb, ${form.background.default} 92%, white);
|
|
555
|
+
--ng-form-background-disabled: ${form.background.disabled};
|
|
556
|
+
--ng-form-background-readonly: ${form.background.readonly};
|
|
557
|
+
--ng-form-border: ${form.border.default};
|
|
558
|
+
--ng-form-border-focus: ${form.border.focus};
|
|
559
|
+
--ng-form-border-disabled: ${form.border.disabled};
|
|
560
|
+
--ng-form-border-invalid: ${form.border.invalid};
|
|
561
|
+
--ng-form-font-family: ${form.fontFamily};
|
|
562
|
+
--ng-form-font-size-sm: ${form.fontSize.sm};
|
|
563
|
+
--ng-form-font-size-md: ${form.fontSize.md};
|
|
564
|
+
--ng-form-font-size-lg: ${form.fontSize.lg};
|
|
565
|
+
--ng-form-radius-sm: ${form.radius.sm};
|
|
566
|
+
--ng-form-radius-md: ${form.radius.md};
|
|
567
|
+
--ng-form-radius-lg: ${form.radius.lg};
|
|
568
|
+
--ng-form-height-sm: ${form.height.sm};
|
|
569
|
+
--ng-form-height-md: ${form.height.md};
|
|
570
|
+
--ng-form-height-lg: ${form.height.lg};
|
|
571
|
+
--ng-form-padding-x-sm: ${form.paddingX.sm};
|
|
572
|
+
--ng-form-padding-x-md: ${form.paddingX.md};
|
|
573
|
+
--ng-form-padding-x-lg: ${form.paddingX.lg};
|
|
574
|
+
--ng-form-label-color: ${form.label.color};
|
|
575
|
+
--ng-form-label-font-weight: ${form.label.fontWeight};
|
|
576
|
+
--ng-form-label-font-size-sm: ${form.label.fontSize.sm};
|
|
577
|
+
--ng-form-label-font-size-md: ${form.label.fontSize.md};
|
|
578
|
+
--ng-form-label-font-size-lg: ${form.label.fontSize.lg};
|
|
579
|
+
--ng-form-label-margin-bottom-sm: ${form.label.marginBottom.sm};
|
|
580
|
+
--ng-form-label-margin-bottom-md: ${form.label.marginBottom.md};
|
|
581
|
+
--ng-form-label-margin-bottom-lg: ${form.label.marginBottom.lg};
|
|
582
|
+
--ng-form-label-viewmode-margin-bottom-sm: ${form.label.viewmodeMarginBottom.sm};
|
|
583
|
+
--ng-form-label-viewmode-margin-bottom-md: ${form.label.viewmodeMarginBottom.md};
|
|
584
|
+
--ng-form-label-viewmode-margin-bottom-lg: ${form.label.viewmodeMarginBottom.lg};
|
|
585
|
+
|
|
586
|
+
--ng-blue-50: ${colors.blue.b50};
|
|
587
|
+
--ng-blue-100: ${colors.blue.b100};
|
|
588
|
+
--ng-blue-150: ${colors.blue.b150};
|
|
589
|
+
--ng-blue-200: ${colors.blue.b200};
|
|
590
|
+
--ng-blue-300: ${colors.blue.b300};
|
|
591
|
+
--ng-blue-400: ${colors.blue.b400};
|
|
592
|
+
--ng-blue-500: ${colors.blue.b500};
|
|
593
|
+
--ng-blue-600: ${colors.blue.b600};
|
|
594
|
+
--ng-blue-700: ${colors.blue.b700};
|
|
595
|
+
--ng-blue-800: ${colors.blue.b800};
|
|
596
|
+
--ng-blue-900: ${colors.blue.b900};
|
|
597
|
+
--ng-red-50: ${colors.red.r50};
|
|
598
|
+
--ng-red-100: ${colors.red.r100};
|
|
599
|
+
--ng-red-150: ${colors.red.r150};
|
|
600
|
+
--ng-red-200: ${colors.red.r200};
|
|
601
|
+
--ng-red-500: ${colors.red.r500};
|
|
602
|
+
--ng-red-600: ${colors.red.r600};
|
|
603
|
+
--ng-red-700: ${colors.red.r700};
|
|
604
|
+
--ng-red-800: ${colors.red.r800};
|
|
605
|
+
--ng-red-900: ${colors.red.r900};
|
|
606
|
+
--ng-grey-100: ${colors.grey.r100};
|
|
607
|
+
--ng-grey-150: ${colors.grey.r150};
|
|
608
|
+
--ng-grey-200: ${colors.grey.r200};
|
|
609
|
+
--ng-grey-300: ${colors.grey.r300};
|
|
610
|
+
--ng-grey-400: ${colors.grey.r400};
|
|
611
|
+
--ng-grey-500: ${colors.grey.r500};
|
|
612
|
+
--ng-grey-600: ${colors.grey.r600};
|
|
613
|
+
--ng-grey-700: ${colors.grey.r700};
|
|
614
|
+
--ng-grey-800: ${colors.grey.r800};
|
|
615
|
+
--ng-grey-900: ${colors.grey.r900};
|
|
616
|
+
--ng-yellow-50: ${colors.yellow.r50};
|
|
617
|
+
--ng-yellow-100: ${colors.yellow.r100};
|
|
618
|
+
--ng-yellow-150: ${colors.yellow.r150};
|
|
619
|
+
--ng-yellow-200: ${colors.yellow.r200};
|
|
620
|
+
--ng-yellow-400: ${colors.yellow.r400};
|
|
621
|
+
--ng-yellow-500: ${colors.yellow.r500};
|
|
622
|
+
--ng-yellow-900: ${colors.yellow.r900};
|
|
623
|
+
--ng-green-50: ${colors.green.r50};
|
|
624
|
+
--ng-green-100: ${colors.green.r100};
|
|
625
|
+
--ng-green-150: ${colors.green.r150};
|
|
626
|
+
--ng-green-200: ${colors.green.r200};
|
|
627
|
+
--ng-green-500: ${colors.green.r500};
|
|
628
|
+
--ng-green-900: ${colors.green.r900};
|
|
629
|
+
--ng-purple-50: ${colors.purple.r50};
|
|
630
|
+
--ng-purple-100: ${colors.purple.r100};
|
|
631
|
+
--ng-purple-150: ${colors.purple.r150};
|
|
632
|
+
--ng-purple-200: ${colors.purple.r200};
|
|
633
|
+
--ng-purple-900: ${colors.purple.r900};
|
|
634
|
+
--ng-plump-50: ${colors.plump.r50};
|
|
635
|
+
--ng-plump-100: ${colors.plump.r100};
|
|
636
|
+
--ng-plump-150: ${colors.plump.r150};
|
|
637
|
+
--ng-plump-200: ${colors.plump.r200};
|
|
638
|
+
--ng-plump-900: ${colors.plump.r900};
|
|
639
|
+
--ng-teal-50: ${colors.teal.r50};
|
|
640
|
+
--ng-teal-100: ${colors.teal.r100};
|
|
641
|
+
--ng-teal-150: ${colors.teal.r150};
|
|
642
|
+
--ng-teal-200: ${colors.teal.r200};
|
|
643
|
+
--ng-teal-500: ${colors.teal.r500};
|
|
644
|
+
--ng-teal-600: ${colors.teal.r600};
|
|
645
|
+
--ng-teal-700: ${colors.teal.r700};
|
|
646
|
+
--ng-teal-800: ${colors.teal.r800};
|
|
647
|
+
--ng-teal-900: ${colors.teal.r900};
|
|
648
|
+
--ng-pink-50: ${colors.pink.r50};
|
|
649
|
+
--ng-pink-100: ${colors.pink.r100};
|
|
650
|
+
--ng-pink-150: ${colors.pink.r150};
|
|
651
|
+
--ng-pink-200: ${colors.pink.r200};
|
|
652
|
+
--ng-pink-500: ${colors.pink.r500};
|
|
653
|
+
--ng-pink-600: ${colors.pink.r600};
|
|
654
|
+
--ng-pink-700: ${colors.pink.r700};
|
|
655
|
+
--ng-pink-800: ${colors.pink.r800};
|
|
656
|
+
--ng-pink-900: ${colors.pink.r900};
|
|
657
|
+
--ng-cyan-50: ${colors.cyan.r50};
|
|
658
|
+
--ng-cyan-100: ${colors.cyan.r100};
|
|
659
|
+
--ng-cyan-150: ${colors.cyan.r150};
|
|
660
|
+
--ng-cyan-200: ${colors.cyan.r200};
|
|
661
|
+
--ng-cyan-500: ${colors.cyan.r500};
|
|
662
|
+
--ng-cyan-600: ${colors.cyan.r600};
|
|
663
|
+
--ng-cyan-700: ${colors.cyan.r700};
|
|
664
|
+
--ng-cyan-800: ${colors.cyan.r800};
|
|
665
|
+
--ng-cyan-900: ${colors.cyan.r900};
|
|
666
|
+
--ng-orange-50: ${colors.orange.r50};
|
|
667
|
+
--ng-orange-100: ${colors.orange.r100};
|
|
668
|
+
--ng-orange-150: ${colors.orange.r150};
|
|
669
|
+
--ng-orange-200: ${colors.orange.r200};
|
|
670
|
+
--ng-orange-500: ${colors.orange.r500};
|
|
671
|
+
--ng-orange-600: ${colors.orange.r600};
|
|
672
|
+
--ng-orange-700: ${colors.orange.r700};
|
|
673
|
+
--ng-orange-800: ${colors.orange.r800};
|
|
674
|
+
--ng-orange-900: ${colors.orange.r900};
|
|
675
|
+
|
|
676
|
+
--ng-action-gray: ${actions.gray || colors.grey.r900};
|
|
677
|
+
--ng-action-red: ${actions.red || colors.red.r600};
|
|
678
|
+
--ng-action-green: ${actions.green || colors.green.r500};
|
|
679
|
+
--ng-action-blue: ${actions.blue || palette.accent.primary};
|
|
680
|
+
--ng-action-teal: ${actions.teal || colors.teal.r600};
|
|
681
|
+
--ng-action-pink: ${actions.pink || colors.pink.r600};
|
|
682
|
+
--ng-action-purple: ${actions.purple || colors.purple.r900};
|
|
683
|
+
--ng-action-cyan: ${actions.cyan || colors.cyan.r600};
|
|
684
|
+
--ng-action-orange: ${actions.orange || colors.orange.r600};
|
|
685
|
+
--ng-action-yellow: ${actions.yellow || colors.yellow.r600};
|
|
686
|
+
--ng-action-white: ${actions.white || palette.background.surface};
|
|
687
|
+
--ng-action-black: ${actions.black || colors.grey.r900};
|
|
688
|
+
--ng-text-on-accent: ${getContrastColor(palette.accent.primary)};
|
|
689
|
+
`;
|
|
690
|
+
}
|
|
691
|
+
/** Temanın yaydığı değişken adlarının tam listesi — elle tutulmaz, gerçek şablondan türer. */
|
|
692
|
+
export function listThemeVarNames() {
|
|
693
|
+
const style = buildThemeStyle(WHITE_PALETTE, formTokens(WHITE_PALETTE, TOKENS), TOKENS, shadowTokens(TOKENS), TOKENS.defaultInputSize);
|
|
694
|
+
return [...new Set(style.match(/--ng-[\w-]+(?=:)/g) || [])];
|
|
695
|
+
}
|
|
696
|
+
/** `--ad: değer;` satırlarını sözlüğe çözer. */
|
|
697
|
+
export function parseThemeStyle(style) {
|
|
698
|
+
const vars = {};
|
|
699
|
+
for (const match of style.matchAll(/(--ng-[\w-]+):\s*([^;]+);/g)) {
|
|
700
|
+
const [, name, value] = match;
|
|
701
|
+
if (name && value)
|
|
702
|
+
vars[name] = value.trim();
|
|
703
|
+
}
|
|
704
|
+
return vars;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Temanın belirli bir MODDAKİ karşılığı.
|
|
708
|
+
*
|
|
709
|
+
* Palet override'ları mod başına tutulur (`palette` / `paletteDark`): kayıtlı her tema TAM bir
|
|
710
|
+
* aydınlık palet taşıdığı için ortak bir küme karanlık modu aydınlık gösterirdi
|
|
711
|
+
* (`Theme.svelte`). Ziyaretçinin kendi tercihi (`theme-toggle` → localStorage) runtime'da
|
|
712
|
+
* projenin modunun önüne geçer; burada o kanal yoktur, `mode` parametresi onun yerini tutar.
|
|
713
|
+
*/
|
|
714
|
+
export function resolveTheme(theme, mode) {
|
|
715
|
+
const overrides = theme ?? {};
|
|
716
|
+
const effectiveMode = mode ?? (overrides.mode === 'dark' ? 'dark' : 'light');
|
|
717
|
+
const modePalette = effectiveMode === 'dark' ? DARK_PALETTE : WHITE_PALETTE;
|
|
718
|
+
const modeOverrides = effectiveMode === 'dark' ? overrides.paletteDark : overrides.palette;
|
|
719
|
+
const palette = modeOverrides ? mergePalette(modePalette, modeOverrides) : modePalette;
|
|
720
|
+
const tokens = mergeTokens(TOKENS, overrides);
|
|
721
|
+
const form = formTokens(palette, tokens);
|
|
722
|
+
const shadow = shadowTokens(tokens);
|
|
723
|
+
const style = buildThemeStyle(palette, form, tokens, shadow, tokens.defaultInputSize);
|
|
724
|
+
return { mode: effectiveMode, palette, tokens, form, shadow, cssVars: parseThemeStyle(style) };
|
|
725
|
+
}
|
|
726
|
+
/** İki çözüm arasındaki değişken farkı; eklenen/silinen değişken `null` ucuyla görünür. */
|
|
727
|
+
export function diffCssVars(before, after) {
|
|
728
|
+
const changes = {};
|
|
729
|
+
for (const name of new Set([...Object.keys(before), ...Object.keys(after)])) {
|
|
730
|
+
const from = before[name] ?? null;
|
|
731
|
+
const to = after[name] ?? null;
|
|
732
|
+
if (from !== to)
|
|
733
|
+
changes[name] = { from, to };
|
|
734
|
+
}
|
|
735
|
+
return changes;
|
|
736
|
+
}
|
|
737
|
+
/* ---- Panel sabitleri (studio `theme-settings/` kopyası) ---- */
|
|
738
|
+
/**
|
|
739
|
+
* `Theme.svelte` yazı tipi adını olduğu gibi Google Fonts'a gönderir: listede olmayan bir ad
|
|
740
|
+
* sessizce sans-serif'e düşer (THEME-008 uyarısı bu listeye bakar).
|
|
741
|
+
*/
|
|
742
|
+
export const GOOGLE_FONTS = [
|
|
743
|
+
'ABeeZee',
|
|
744
|
+
'Abel',
|
|
745
|
+
'Abril Fatface',
|
|
746
|
+
'Acme',
|
|
747
|
+
'Alata',
|
|
748
|
+
'Albert Sans',
|
|
749
|
+
'Alegreya',
|
|
750
|
+
'Alegreya Sans',
|
|
751
|
+
'Alfa Slab One',
|
|
752
|
+
'Alice',
|
|
753
|
+
'Amatic SC',
|
|
754
|
+
'Amiri',
|
|
755
|
+
'Antic Slab',
|
|
756
|
+
'Anton',
|
|
757
|
+
'Archivo',
|
|
758
|
+
'Archivo Black',
|
|
759
|
+
'Archivo Narrow',
|
|
760
|
+
'Arimo',
|
|
761
|
+
'Arsenal',
|
|
762
|
+
'Asap',
|
|
763
|
+
'Asap Condensed',
|
|
764
|
+
'Assistant',
|
|
765
|
+
'Barlow',
|
|
766
|
+
'Barlow Condensed',
|
|
767
|
+
'Barlow Semi Condensed',
|
|
768
|
+
'Be Vietnam Pro',
|
|
769
|
+
'Bebas Neue',
|
|
770
|
+
'Bitter',
|
|
771
|
+
'Black Ops One',
|
|
772
|
+
'Bodoni Moda',
|
|
773
|
+
'Bree Serif',
|
|
774
|
+
'Cabin',
|
|
775
|
+
'Cairo',
|
|
776
|
+
'Cantarell',
|
|
777
|
+
'Cardo',
|
|
778
|
+
'Catamaran',
|
|
779
|
+
'Caveat',
|
|
780
|
+
'Chakra Petch',
|
|
781
|
+
'Chivo',
|
|
782
|
+
'Cinzel',
|
|
783
|
+
'Comfortaa',
|
|
784
|
+
'Commissioner',
|
|
785
|
+
'Concert One',
|
|
786
|
+
'Cormorant',
|
|
787
|
+
'Cormorant Garamond',
|
|
788
|
+
'Crimson Pro',
|
|
789
|
+
'Crimson Text',
|
|
790
|
+
'DM Mono',
|
|
791
|
+
'DM Sans',
|
|
792
|
+
'DM Serif Display',
|
|
793
|
+
'DM Serif Text',
|
|
794
|
+
'Dancing Script',
|
|
795
|
+
'Domine',
|
|
796
|
+
'Dosis',
|
|
797
|
+
'EB Garamond',
|
|
798
|
+
'Encode Sans',
|
|
799
|
+
'Exo 2',
|
|
800
|
+
'Figtree',
|
|
801
|
+
'Fira Code',
|
|
802
|
+
'Fira Sans',
|
|
803
|
+
'Fira Sans Condensed',
|
|
804
|
+
'Fjalla One',
|
|
805
|
+
'Francois One',
|
|
806
|
+
'Frank Ruhl Libre',
|
|
807
|
+
'Gelasio',
|
|
808
|
+
'Gloria Hallelujah',
|
|
809
|
+
'Gothic A1',
|
|
810
|
+
'Great Vibes',
|
|
811
|
+
'Heebo',
|
|
812
|
+
'Hind',
|
|
813
|
+
'Hind Siliguri',
|
|
814
|
+
'IBM Plex Mono',
|
|
815
|
+
'IBM Plex Sans',
|
|
816
|
+
'IBM Plex Serif',
|
|
817
|
+
'Inconsolata',
|
|
818
|
+
'Inter',
|
|
819
|
+
'Inter Tight',
|
|
820
|
+
'JetBrains Mono',
|
|
821
|
+
'Josefin Sans',
|
|
822
|
+
'Josefin Slab',
|
|
823
|
+
'Jost',
|
|
824
|
+
'Kalam',
|
|
825
|
+
'Kanit',
|
|
826
|
+
'Karla',
|
|
827
|
+
'Khand',
|
|
828
|
+
'Lato',
|
|
829
|
+
'League Spartan',
|
|
830
|
+
'Lexend',
|
|
831
|
+
'Libre Baskerville',
|
|
832
|
+
'Libre Franklin',
|
|
833
|
+
'Lilita One',
|
|
834
|
+
'Lora',
|
|
835
|
+
'M PLUS Rounded 1c',
|
|
836
|
+
'Manrope',
|
|
837
|
+
'Marcellus',
|
|
838
|
+
'Maven Pro',
|
|
839
|
+
'Merriweather',
|
|
840
|
+
'Merriweather Sans',
|
|
841
|
+
'Montserrat',
|
|
842
|
+
'Montserrat Alternates',
|
|
843
|
+
'Mukta',
|
|
844
|
+
'Mulish',
|
|
845
|
+
'Nanum Gothic',
|
|
846
|
+
'Nanum Myeongjo',
|
|
847
|
+
'Neuton',
|
|
848
|
+
'Noticia Text',
|
|
849
|
+
'Noto Sans',
|
|
850
|
+
'Noto Sans JP',
|
|
851
|
+
'Noto Sans KR',
|
|
852
|
+
'Noto Serif',
|
|
853
|
+
'Nunito',
|
|
854
|
+
'Nunito Sans',
|
|
855
|
+
'Old Standard TT',
|
|
856
|
+
'Onest',
|
|
857
|
+
'Open Sans',
|
|
858
|
+
'Oswald',
|
|
859
|
+
'Outfit',
|
|
860
|
+
'Overpass',
|
|
861
|
+
'Oxygen',
|
|
862
|
+
'PT Sans',
|
|
863
|
+
'PT Serif',
|
|
864
|
+
'Pacifico',
|
|
865
|
+
'Pathway Gothic One',
|
|
866
|
+
'Philosopher',
|
|
867
|
+
'Play',
|
|
868
|
+
'Playfair Display',
|
|
869
|
+
'Plus Jakarta Sans',
|
|
870
|
+
'Poppins',
|
|
871
|
+
'Prompt',
|
|
872
|
+
'Public Sans',
|
|
873
|
+
'Quicksand',
|
|
874
|
+
'Rajdhani',
|
|
875
|
+
'Raleway',
|
|
876
|
+
'Readex Pro',
|
|
877
|
+
'Red Hat Display',
|
|
878
|
+
'Roboto',
|
|
879
|
+
'Roboto Condensed',
|
|
880
|
+
'Roboto Flex',
|
|
881
|
+
'Roboto Mono',
|
|
882
|
+
'Roboto Slab',
|
|
883
|
+
'Rubik',
|
|
884
|
+
'Russo One',
|
|
885
|
+
'Saira',
|
|
886
|
+
'Satisfy',
|
|
887
|
+
'Sawarabi Gothic',
|
|
888
|
+
'Secular One',
|
|
889
|
+
'Shadows Into Light',
|
|
890
|
+
'Signika',
|
|
891
|
+
'Signika Negative',
|
|
892
|
+
'Silkscreen',
|
|
893
|
+
'Slabo 27px',
|
|
894
|
+
'Sora',
|
|
895
|
+
'Source Code Pro',
|
|
896
|
+
'Source Sans 3',
|
|
897
|
+
'Source Serif 4',
|
|
898
|
+
'Space Grotesk',
|
|
899
|
+
'Space Mono',
|
|
900
|
+
'Spectral',
|
|
901
|
+
'Teko',
|
|
902
|
+
'Titillium Web',
|
|
903
|
+
'Ubuntu',
|
|
904
|
+
'Ubuntu Condensed',
|
|
905
|
+
'Ubuntu Mono',
|
|
906
|
+
'Urbanist',
|
|
907
|
+
'Varela Round',
|
|
908
|
+
'Vollkorn',
|
|
909
|
+
'Work Sans',
|
|
910
|
+
'Yanone Kaffeesatz',
|
|
911
|
+
'Yellowtail',
|
|
912
|
+
'Zen Kaku Gothic New',
|
|
913
|
+
'Zilla Slab',
|
|
914
|
+
];
|
|
915
|
+
/**
|
|
916
|
+
* Preset adı `$preset` içinde ham metin olarak taşınır ve doğrudan bir nesne anahtarı olur.
|
|
917
|
+
* Boş ad, kırpılmamış ad ve `$` ile başlayan ad yasak: sonuncusu çözümleyicinin sihirli
|
|
918
|
+
* anahtarıyla karışırdı.
|
|
919
|
+
*/
|
|
920
|
+
export function isValidPresetName(name) {
|
|
921
|
+
return name.length > 0 && name === name.trim() && !name.startsWith('$') && name.length <= 40;
|
|
922
|
+
}
|
|
923
|
+
/** Bir tipin taşıyabileceği en fazla versiyon sayısı; panel dolduğunda düğmeyi hiç çizmez. */
|
|
924
|
+
export const MAX_PRESET_VERSIONS = 5;
|
|
925
|
+
/** Yeni eklenen bir bileşen preset'inin ilk versiyonunun adı. */
|
|
926
|
+
export const FIRST_VERSION_NAME = 'V1';
|
|
927
|
+
/** Eski `componentStyles` kayıtları sarılırken kullanılan versiyon adı. */
|
|
928
|
+
export const DEFAULT_VERSION_NAME = 'Default';
|
|
929
|
+
/**
|
|
930
|
+
* Versiyonun `appearance` zarfının TANIDIĞI alanlar. Kanal ölçü, hizalama ve z-index de taşır;
|
|
931
|
+
* onlar bir TİPİN varsayılanı değil o ÖRNEĞİN ızgaradaki geometrisidir ve temada saklanmaları
|
|
932
|
+
* yanlış olurdu.
|
|
933
|
+
*/
|
|
934
|
+
export const SPACING_KEYS = [
|
|
935
|
+
'marginType', 'marginValue', 'marginValues', 'paddingType', 'paddingValue', 'paddingValues'
|
|
936
|
+
];
|