@xyd-js/themes 0.0.0-build

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.
Files changed (41) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +7 -0
  4. package/dist/decorators/atlas-vars.css +29 -0
  5. package/dist/decorators/header-sketch.css +23 -0
  6. package/dist/decorators/page-layout.css +11 -0
  7. package/dist/decorators/page-leftpad.css +46 -0
  8. package/dist/decorators/page-sketch.css +52 -0
  9. package/dist/decorators/sidebar-pad.css +24 -0
  10. package/dist/decorators/sidebar-scroll.css +51 -0
  11. package/dist/index.css +1259 -0
  12. package/dist/index.d.ts +116 -0
  13. package/dist/index.js +669 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/reset.css +56 -0
  16. package/dist/rollup.d.ts +28 -0
  17. package/dist/rollup.js +139 -0
  18. package/dist/rollup.js.map +1 -0
  19. package/package.json +60 -0
  20. package/postcss.config.cjs +7 -0
  21. package/scripts/build-css.js +73 -0
  22. package/src/BaseTheme.tsx +471 -0
  23. package/src/Theme.tsx +363 -0
  24. package/src/context.tsx +9 -0
  25. package/src/copyPresetsPlugin.ts +124 -0
  26. package/src/index.ts +11 -0
  27. package/src/rollup.ts +91 -0
  28. package/src/styles/decorators/atlas-vars.css +32 -0
  29. package/src/styles/decorators/header-sketch.css +23 -0
  30. package/src/styles/decorators/page-layout.css +11 -0
  31. package/src/styles/decorators/page-leftpad.css +46 -0
  32. package/src/styles/decorators/page-sketch.css +30 -0
  33. package/src/styles/decorators/sidebar-pad.css +24 -0
  34. package/src/styles/decorators/sidebar-scroll.css +51 -0
  35. package/src/styles/index.css +26 -0
  36. package/src/styles/reset.css +56 -0
  37. package/src/styles/styles.css +156 -0
  38. package/src/styles/tokens.css +472 -0
  39. package/tsconfig.json +51 -0
  40. package/tsup.config.ts +38 -0
  41. package/types.d.ts +13 -0
package/src/Theme.tsx ADDED
@@ -0,0 +1,363 @@
1
+ import * as React from "react"
2
+
3
+ import type { Appearance, Navigation, Theme as ThemeSettings, UserPreferences, WebEditor, WebEditorNavigationItem } from "@xyd-js/core"
4
+ import { ReactContent } from "@xyd-js/components/content"
5
+ import { IconSocial } from "@xyd-js/components/writer"
6
+ import { Surfaces } from "@xyd-js/framework"
7
+ import { useMetadata } from "@xyd-js/framework/react"
8
+
9
+ // ─── Theme Class ──────────────────────────────────────────────
10
+
11
+ // TODO: still issues with double settings on dev changing
12
+ // TODO: refactor
13
+ export abstract class Theme {
14
+ constructor() {
15
+ this.settings = globalThis.__xydThemeSettings
16
+
17
+ this.useHideToc = this.useHideToc.bind(this)
18
+ this.useHideSidebar = this.useHideSidebar.bind(this)
19
+ this.appearanceWebEditor = this.appearanceWebEditor.bind(this)
20
+ this.headerPrepend = this.headerPrepend.bind(this)
21
+ this.mergeUserAppearance = this.mergeUserAppearance.bind(this)
22
+ this.resetWebeditor = this.resetWebeditor.bind(this)
23
+
24
+ globalThis.__xydThemeSettings.Update = this.update.bind(this) // TODO: in the future better solution cuz we modify original object
25
+ globalThis.__xydThemeSettings.UpdatePreset = this.updateThemePreset.bind(this)
26
+
27
+ this.theme = globalThis.__xydThemeSettings
28
+ this.surfaces = globalThis.__xydSurfaces
29
+ this.reactContent = globalThis.__xydReactContent
30
+ this.navigation = globalThis.__xydNavigation as Navigation
31
+ this.webeditor = globalThis.__xydWebeditor as WebEditor
32
+ this.userPreferences = globalThis.__xydUserPreferences as UserPreferences
33
+
34
+ this.userAppearance = JSON.parse(JSON.stringify(this.theme.appearance || {}))
35
+
36
+ this.appearanceWebEditor()
37
+ }
38
+
39
+ private webeditor: WebEditor
40
+ private navigation: Navigation
41
+
42
+ private userAppearance: Appearance
43
+ protected settings: ThemeSettings
44
+ protected theme: CustomTheme<ThemeSettings>
45
+ protected readonly reactContent: ReactContent
46
+ protected readonly surfaces: Surfaces
47
+ private readonly userPreferences: UserPreferences
48
+
49
+ private get originalTheme(): ThemeSettings {
50
+ return JSON.parse(JSON.stringify(globalThis.__xydSettingsClone?.theme))
51
+ }
52
+
53
+ private get originalWebeditor(): WebEditor {
54
+ return JSON.parse(JSON.stringify(globalThis.__xydSettingsClone?.webeditor))
55
+ }
56
+
57
+ private get originalNavigation(): Navigation {
58
+ return JSON.parse(JSON.stringify(globalThis.__xydSettingsClone?.navigation))
59
+ }
60
+
61
+ public abstract Page({ children }: { children: React.ReactNode }): React.ReactElement
62
+
63
+ public abstract Layout({ children }: { children: React.ReactNode }): React.ReactElement
64
+
65
+ public abstract reactContentComponents(): { [component: string]: (props: any) => React.JSX.Element | null }
66
+
67
+ public abstract reactFileComponents(): { [component: string]: (props: any) => React.JSX.Element | null } | false
68
+
69
+ protected useHideToc() {
70
+ const meta = useMetadata()
71
+ return meta?.layout === "wide" || meta?.layout === "reader" || meta?.layout === "page"
72
+ }
73
+
74
+ protected useHideSidebar() {
75
+ const meta = useMetadata()
76
+ return meta?.layout === "page" || meta?.layout === "reader"
77
+ }
78
+
79
+ private headerPrepend(searchItem: any, float: string) {
80
+ const header = this.webeditor.header || []
81
+ const insertIndex = header.findIndex(item => item.float === float)
82
+ return insertIndex === -1
83
+ ? [...header, searchItem]
84
+ : [...header.slice(0, insertIndex), searchItem, ...header.slice(insertIndex)]
85
+ }
86
+
87
+ private headerAppend(searchItem: any, float: string = "") {
88
+ const header = this.webeditor.header || []
89
+ const insertIndex = header.findIndex(item => item.float === float)
90
+ return insertIndex === -1
91
+ ? [...header, searchItem]
92
+ : [...header.slice(0, insertIndex + 1), searchItem, ...header.slice(insertIndex + 1)]
93
+ }
94
+
95
+ private update(patch: DeepPartial<ThemeSettings>) {
96
+ deepMerge(this.theme, patch)
97
+ this.appearanceWebEditor()
98
+ }
99
+
100
+ private updateThemePreset(patch: string[]) {
101
+ this.update({
102
+ appearance: {
103
+ presets: [
104
+ ...(this.settings.appearance?.presets || []),
105
+ ...(patch || [])
106
+ ]
107
+ }
108
+ })
109
+ }
110
+
111
+ private appearanceWebEditor() {
112
+ if (!this.theme.appearance) {
113
+ return
114
+ }
115
+
116
+ this.resetWebeditor()
117
+ this.resetNavigation()
118
+
119
+ const searchAppearance = this.theme.appearance?.search?.sidebar || this.theme.appearance?.search?.middle
120
+ if (searchAppearance) {
121
+ const hasSearch = this.webeditor.header?.find(item => item.component === "Search")
122
+
123
+ if (hasSearch) {
124
+ console.warn("Search already exists in webeditor.header")
125
+ return
126
+ }
127
+
128
+ if (this.theme.appearance?.search?.sidebar) {
129
+ const search: WebEditorNavigationItem = {
130
+ component: "Search",
131
+ mobile: this.theme.appearance?.search?.sidebar === "mobile" || undefined,
132
+ desktop: this.theme.appearance?.search?.sidebar === "desktop" || undefined
133
+ }
134
+ if (!this.webeditor.sidebarTop) {
135
+ this.webeditor.sidebarTop = []
136
+ }
137
+
138
+ this.webeditor.sidebarTop?.unshift({
139
+ ...search,
140
+ })
141
+ }
142
+
143
+ if (this.theme.appearance?.search?.middle) {
144
+ const search: WebEditorNavigationItem = {
145
+ component: "Search",
146
+ mobile: this.theme.appearance?.search?.middle === "mobile" || undefined,
147
+ desktop: this.theme.appearance?.search?.middle === "desktop" || undefined
148
+ }
149
+ const searchItem = {
150
+ ...search,
151
+ float: "center" as const
152
+ }
153
+
154
+ this.webeditor.header = this.headerPrepend(searchItem, "center")
155
+ }
156
+ }
157
+
158
+ if (
159
+ this.theme.appearance?.sidebar?.scrollbarColor &&
160
+ !this.theme.appearance?.sidebar?.scrollbar
161
+ ) {
162
+ this.theme.appearance.sidebar.scrollbar = "secondary"
163
+ }
164
+
165
+ if (this.theme.appearance?.logo?.sidebar) {
166
+ const logo: WebEditorNavigationItem = {
167
+ component: "Logo",
168
+ mobile: this.theme.appearance?.logo?.sidebar === "mobile" || undefined,
169
+ desktop: this.theme.appearance?.logo?.sidebar === "desktop" || undefined
170
+ }
171
+ if (!this.webeditor.sidebarTop) {
172
+ this.webeditor.sidebarTop = []
173
+ }
174
+
175
+ // this.webeditor.sidebarTop = [
176
+ // logo,
177
+ // ...(this.originalWebeditor.sidebarTop || []),
178
+ // ]
179
+
180
+ this.webeditor.sidebarTop?.unshift(logo)
181
+ }
182
+
183
+ if (
184
+ this.theme.appearance?.tabs?.surface === "center" &&
185
+ this.navigation?.tabs?.length
186
+ ) {
187
+ this.insertCenterHeaderTabs()
188
+ }
189
+
190
+ if (
191
+ this.navigation?.tabs?.length &&
192
+ this.navigation?.segments?.length && // cuz segments defaults are inside subnav
193
+ this.theme.appearance?.tabs?.surface !== "center") {
194
+
195
+ this.navigation.segments = this.navigation.segments.map(segment => {
196
+ if (segment.appearance !== "sidebarDropdown") {
197
+ segment.appearance = "sidebarDropdown"
198
+ }
199
+ return segment
200
+ })
201
+ }
202
+
203
+ if (this.navigation?.anchors?.header?.length) {
204
+ this.navigation?.anchors?.header.forEach(item => {
205
+ const button = {
206
+ ...item,
207
+ component: "Button",
208
+ props: {},
209
+ float: "right" as const,
210
+ desktop: true,
211
+ }
212
+
213
+ if ("button" in item) {
214
+ this.webeditor.header = this.headerAppend({
215
+ ...button,
216
+ props: {
217
+ kind: item.button,
218
+ children: item.title,
219
+ size: this.theme.appearance?.header?.buttonSize || "md"
220
+ },
221
+ })
222
+
223
+ return
224
+ }
225
+
226
+ if ("social" in item) {
227
+ this.webeditor.header = this.headerAppend({
228
+ ...button,
229
+ icon: <IconSocial kind={item.social as any} />,
230
+ props: {
231
+ theme: "ghost",
232
+ icon: <IconSocial kind={item.social as any} />,
233
+ },
234
+ })
235
+
236
+ return
237
+ }
238
+
239
+ if (item.icon) {
240
+ this.webeditor.header = this.headerAppend({
241
+ ...button,
242
+ props: {
243
+ theme: "ghost",
244
+ icon: item.icon,
245
+ },
246
+ })
247
+
248
+ return
249
+ }
250
+
251
+ this.webeditor.header = this.headerAppend({
252
+ ...item,
253
+ float: "right" as const,
254
+ desktop: true,
255
+ })
256
+ })
257
+ }
258
+
259
+ // TODO: in the future it should be in theme level
260
+ if (this.theme.name === "gusto") {
261
+ if (this.navigation?.tabs?.length) {
262
+ this.navigation.sidebarDropdown = this.navigation.tabs
263
+
264
+ // this.navigation.tabs.map(tab => {
265
+ // this.webeditor.sidebarTop = this.headerAppend({
266
+ // ...tab,
267
+ // })
268
+ // })
269
+ }
270
+ }
271
+ }
272
+
273
+ private mergeUserAppearance() {
274
+ const update: DeepPartial<ThemeSettings> = {
275
+ appearance: this.userAppearance
276
+ }
277
+
278
+ if (this.originalTheme.coder) {
279
+ update.coder = this.originalTheme.coder
280
+ }
281
+
282
+ this.update(update)
283
+ }
284
+
285
+ private resetWebeditor() {
286
+ for (const key in this.webeditor) {
287
+ this.webeditor[key] = this.originalWebeditor[key] || []
288
+ }
289
+ }
290
+
291
+ private resetNavigation() {
292
+ for (const key in this.navigation) {
293
+ this.navigation[key] = this.originalNavigation[key] || []
294
+ }
295
+ }
296
+
297
+ private insertCenterHeaderTabs() {
298
+ const tabsWithFloat = this.navigation?.tabs?.map(item => ({
299
+ ...item,
300
+ float: "center" as const
301
+ })) ?? []
302
+
303
+ const searchIndex = this.webeditor.header?.findIndex(item => item.component === "Search") ?? -1
304
+ const currentHeader = this.webeditor.header ?? []
305
+
306
+ if (searchIndex !== -1) {
307
+ // Insert tabs after Search component
308
+ this.webeditor.header = [
309
+ ...currentHeader.slice(0, searchIndex + 1),
310
+ ...tabsWithFloat,
311
+ ...currentHeader.slice(searchIndex + 1)
312
+ ]
313
+ } else {
314
+ // If no Search component, insert at the beginning
315
+ this.webeditor.header = [
316
+ ...tabsWithFloat,
317
+ ...currentHeader
318
+ ]
319
+ }
320
+ }
321
+ }
322
+
323
+ // ─── DeepPartial Type ─────────────────────────────────────────
324
+
325
+ type DeepPartial<T> = {
326
+ [P in keyof T]?: T[P] extends object
327
+ ? T[P] extends Function
328
+ ? T[P]
329
+ : T[P] extends Array<infer U>
330
+ ? Array<DeepPartial<U>>
331
+ : DeepPartial<T[P]>
332
+ : T[P]
333
+ }
334
+
335
+ // ─── CustomTheme Type ─────────────────────────────────────────
336
+
337
+ type CustomTheme<T> = T & {
338
+ Update: (value: DeepPartial<T>) => void
339
+ UpdatePreset: (value: string[]) => void
340
+ }
341
+
342
+ // ─── Deep Merge Helper ────────────────────────────────────────
343
+
344
+ function deepMerge<T>(target: T, source: DeepPartial<T>): T {
345
+ for (const key in source) {
346
+ const sourceVal = source[key]
347
+ const targetVal = target[key]
348
+
349
+ if (
350
+ sourceVal &&
351
+ typeof sourceVal === "object" &&
352
+ !Array.isArray(sourceVal) &&
353
+ typeof targetVal === "object" &&
354
+ targetVal !== null
355
+ ) {
356
+ target[key] = deepMerge(targetVal, sourceVal)
357
+ } else if (sourceVal !== undefined) {
358
+ target[key] = sourceVal as any
359
+ }
360
+ }
361
+
362
+ return target
363
+ }
@@ -0,0 +1,9 @@
1
+ import { createContext } from "react";
2
+
3
+ import { BaseTheme } from "./BaseTheme";
4
+
5
+ export const PageContext = createContext<{
6
+ theme: BaseTheme | null
7
+ }>({
8
+ theme: null
9
+ })
@@ -0,0 +1,124 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * Creates a Rollup plugin to copy presets directory from src to dist
6
+ * @param options - Plugin options
7
+ * @param options.srcDir - Source directory (default: 'src/presets')
8
+ * @param options.distDir - Destination directory (default: 'dist/presets')
9
+ * @param options.packageRoot - Package root directory (default: process.cwd())
10
+ * @returns Rollup plugin
11
+ */
12
+ export function copyPresetsPlugin(options: {
13
+ srcDir?: string;
14
+ distDir?: string;
15
+ packageRoot?: string;
16
+ } = {}) {
17
+ const {
18
+ srcDir = 'src/presets',
19
+ distDir = 'dist/presets',
20
+ packageRoot = process.cwd()
21
+ } = options;
22
+
23
+ return {
24
+ name: 'copy-presets',
25
+ writeBundle() {
26
+ const srcPresetsPath = path.join(packageRoot, srcDir);
27
+ const distPresetsPath = path.join(packageRoot, distDir);
28
+
29
+ try {
30
+ // Check if src/presets exists
31
+ if (!fs.existsSync(srcPresetsPath)) {
32
+ console.log(`${srcDir} directory does not exist, skipping copy`);
33
+ return;
34
+ }
35
+
36
+ // Copy presets directory recursively
37
+ function copyDir(src: string, dest: string) {
38
+ if (!fs.existsSync(dest)) {
39
+ fs.mkdirSync(dest, { recursive: true });
40
+ }
41
+
42
+ const items = fs.readdirSync(src);
43
+ for (const item of items) {
44
+ const srcPath = path.join(src, item);
45
+ const destPath = path.join(dest, item);
46
+
47
+ const stat = fs.statSync(srcPath);
48
+ if (stat.isDirectory()) {
49
+ copyDir(srcPath, destPath);
50
+ } else {
51
+ fs.copyFileSync(srcPath, destPath);
52
+ }
53
+ }
54
+ }
55
+
56
+ copyDir(srcPresetsPath, distPresetsPath);
57
+ console.log(`✅ Successfully copied ${srcDir} to ${distDir}`);
58
+ } catch (error) {
59
+ console.error(`❌ Error copying presets:`, error);
60
+ }
61
+ }
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Creates a tsup plugin to copy presets directory
67
+ * @param options - Plugin options
68
+ * @param options.srcDir - Source directory (default: 'src/presets')
69
+ * @param options.distDir - Destination directory (default: 'dist/presets')
70
+ * @param options.packageRoot - Package root directory (default: process.cwd())
71
+ * @returns tsup plugin function
72
+ */
73
+ export function tsupCopyPresetsPlugin(options: {
74
+ srcDir?: string;
75
+ distDir?: string;
76
+ packageRoot?: string;
77
+ } = {}) {
78
+ const {
79
+ srcDir = 'src/presets',
80
+ distDir = 'dist/presets',
81
+ packageRoot = process.cwd()
82
+ } = options;
83
+
84
+ return () => ({
85
+ name: 'copy-presets',
86
+ closeBundle() {
87
+ const srcPresetsPath = path.join(packageRoot, srcDir);
88
+ const distPresetsPath = path.join(packageRoot, distDir);
89
+
90
+ try {
91
+ // Check if src/presets exists
92
+ if (!fs.existsSync(srcPresetsPath)) {
93
+ console.log(`${srcDir} directory does not exist, skipping copy`);
94
+ return;
95
+ }
96
+
97
+ // Copy presets directory recursively
98
+ function copyDir(src: string, dest: string) {
99
+ if (!fs.existsSync(dest)) {
100
+ fs.mkdirSync(dest, { recursive: true });
101
+ }
102
+
103
+ const items = fs.readdirSync(src);
104
+ for (const item of items) {
105
+ const srcPath = path.join(src, item);
106
+ const destPath = path.join(dest, item);
107
+
108
+ const stat = fs.statSync(srcPath);
109
+ if (stat.isDirectory()) {
110
+ copyDir(srcPath, destPath);
111
+ } else {
112
+ fs.copyFileSync(srcPath, destPath);
113
+ }
114
+ }
115
+ }
116
+
117
+ copyDir(srcPresetsPath, distPresetsPath);
118
+ console.log(`✅ Successfully copied ${srcDir} to ${distDir}`);
119
+ } catch (error) {
120
+ console.error(`❌ Error copying presets:`, error);
121
+ }
122
+ }
123
+ });
124
+ }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ export {
2
+ BaseTheme,
3
+ } from "./BaseTheme"
4
+
5
+ export {
6
+ type Theme
7
+ } from "./Theme"
8
+
9
+ // Export copy presets plugin
10
+ export { copyPresetsPlugin, tsupCopyPresetsPlugin } from "./copyPresetsPlugin";
11
+
package/src/rollup.ts ADDED
@@ -0,0 +1,91 @@
1
+ import {createRequire} from "module";
2
+
3
+ import resolve from '@rollup/plugin-node-resolve';
4
+ import commonjs from '@rollup/plugin-commonjs';
5
+ import typescript from '@rollup/plugin-typescript';
6
+ import dts from 'rollup-plugin-dts';
7
+ import postcss from 'rollup-plugin-postcss';
8
+ import postcssImport from 'postcss-import';
9
+ import postcssMixins from 'postcss-mixins';
10
+ import wyw from '@wyw-in-js/rollup';
11
+
12
+ import {copyPresetsPlugin} from './copyPresetsPlugin';
13
+
14
+ export default function (importPath: string) {
15
+ const require = createRequire(importPath);
16
+
17
+ const {
18
+ dependencies,
19
+ peerDependencies,
20
+ devDependencies
21
+ } = require('./package.json');
22
+
23
+ const external = [
24
+ ...Object.keys(dependencies),
25
+ ...Object.keys(peerDependencies),
26
+ ...Object.keys(devDependencies),
27
+ "@xyd-js/framework/react",
28
+ "@xyd-js/components/brand",
29
+ "@xyd-js/components/coder",
30
+ "@xyd-js/components/content",
31
+ "@xyd-js/components/layouts",
32
+ "@xyd-js/components/pages",
33
+ "@xyd-js/components/views",
34
+ ];
35
+
36
+ return [
37
+ {
38
+ input: {
39
+ index: './src/index.ts'
40
+ },
41
+ output: [
42
+ {
43
+ dir: 'dist',
44
+ format: 'esm',
45
+ sourcemap: true,
46
+ entryFileNames: '[name].js'
47
+ }
48
+ ],
49
+ plugins: [
50
+ wyw({
51
+ include: ['**/*.{ts,tsx}'],
52
+ babelOptions: {
53
+ presets: [
54
+ '@babel/preset-typescript',
55
+ '@babel/preset-react'
56
+ ],
57
+ },
58
+ }),
59
+ resolve(),
60
+ commonjs(),
61
+ typescript({
62
+ tsconfig: './tsconfig.json',
63
+ }),
64
+ postcss({
65
+ extensions: ['.css'],
66
+ plugins: [postcssImport(), postcssMixins()],
67
+ extract: true, // Extract CSS into a separate file
68
+ minimize: true, // Minify the CSS
69
+ }),
70
+ copyPresetsPlugin(),
71
+ ],
72
+ external
73
+ },
74
+ {
75
+ input: './src/index.ts',
76
+ output: {
77
+ file: 'dist/index.d.ts',
78
+ format: 'es',
79
+ },
80
+ plugins: [
81
+ dts({
82
+ respectExternal: true, // Ignore unresolved imports
83
+ }),
84
+ ],
85
+ external: [
86
+ ...external,
87
+ /\.css$/ // Mark CSS imports as external
88
+ ],
89
+ },
90
+ ];
91
+ }
@@ -0,0 +1,32 @@
1
+ /* Atlas */
2
+ :root {
3
+ --XydAtlas-Ref-Palette-White: var(--white);
4
+ --XydAtlas-Ref-Palette-Primary-60: var(--color-primary);
5
+ --XydAtlas-Ref-Palette-Primary-70: var(--color-primary--active);
6
+ --XydAtlas-Ref-Palette-Primary-80: var(--color-primary--active);
7
+
8
+ --XydAtlas-Ref-Palette-Neutral-10: var(--dark8);
9
+ --XydAtlas-Ref-Palette-Neutral-20: var(--dark16);
10
+ --XydAtlas-Ref-Palette-Neutral-30: var(--dark32);
11
+ --XydAtlas-Ref-Palette-Neutral-40: var(--dark40);
12
+ --XydAtlas-Ref-Palette-Neutral-70: var(--dark48);
13
+ --XydAtlas-Ref-Palette-Neutral-80: var(--dark60);
14
+ --XydAtlas-Ref-Palette-Neutral-100: var(--dark80);
15
+
16
+ --XydAtlas-Sys-Color-Text-Primary: var(--color-text);
17
+ }
18
+
19
+ @define-mixin dark-theme {
20
+ --XydAtlas-Ref-Palette-Primary-60: var(--color-text);
21
+ }
22
+
23
+ [data-color-scheme="dark"] {
24
+ @mixin dark-theme;
25
+ }
26
+
27
+ /* System dark mode support for sidebar - only when OS preference is enabled */
28
+ @media (prefers-color-scheme: dark) {
29
+ :root:not([data-color-scheme="light"]):not([data-color-scheme="dark"]) {
30
+ @mixin dark-theme;
31
+ }
32
+ }
@@ -0,0 +1,23 @@
1
+ @layer decorators {
2
+ xyd-layout-primary {
3
+ /* tag: Header */
4
+ header {
5
+ [part="header-content"] {
6
+ border-bottom: 1px solid var(--decorator-sketch-border-color);
7
+ border-top: 1px solid var(--decorator-sketch-border-color);
8
+ }
9
+ }
10
+
11
+ /* component: Sidebar */
12
+ xyd-sidebar {
13
+ border-radius: 0;
14
+ border-right: 0.5px solid var(--decorator-sketch-border-color);
15
+ }
16
+
17
+ /* component: SubNav */
18
+ xyd-subnav {
19
+ border-bottom: 1px solid var(--decorator-sketch-border-color);
20
+ border-radius: 0;
21
+ }
22
+ }
23
+ }
@@ -0,0 +1,11 @@
1
+ @layer themedecorator {
2
+ xyd-layout-primary[data-layout="page"] {
3
+ --xyd-sidebar-width: 0px;
4
+
5
+ [part="main"], [part="page-scroll"], [part="page-container"], [part="page-article-container"] {
6
+ margin: 0;
7
+ padding: 0;
8
+ max-width: 100%;
9
+ }
10
+ }
11
+ }