diff --git a/.amazonq/rules/db-ux.md b/.amazonq/rules/db-ux.md new file mode 100644 index 0000000..e69de29 diff --git a/.env.template b/.env.template deleted file mode 100644 index 377a26c..0000000 --- a/.env.template +++ /dev/null @@ -1,7 +0,0 @@ -# It will force the user to add an e-mail for this project, before committing. -COMMIT_MAIL=my.commit@mail.com - -# Get credentials for public usage: -# https://marketingportal.extranet.deutschebahn.com/marketingportal/Design-Anwendungen/db-ux-design-system/resources/db-theme -ASSET_PASSWORD=ABC -ASSET_INIT_VECTOR=ABC diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..a34a0a7 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,103 @@ + +--- START: DB UX Copilot Instructions – do not edit below --- + +> **NOTE**: Always use "DB UX" components and variables as project's conventions +# @db-ux/core-components +## Best Practise / Common AI mistakes + +- always read this file if you use Components: `node_modules/@db-ux/core-components/agent/Best-Practise_Common-AI-Mistakes.md` + + +# @db-ux/core-foundations +## CSS + +- If you use CSS, follow these rules: + - Always reference the file `node_modules/@db-ux/core-foundations/agent/css/Variables.md` for variables like sizing, spacing, elevation, border, or container-size. This file contains the authoritative list of available variables. + - Use the examples provided in `Variables.md` to ensure correct usage like: + - `padding: var(--db-spacing-fixed-md);` + - `height: var(--db-sizing-md);` + - `width: var(--db-container-xs);` + - `color: var(--db-adaptive-on-bg-basic-emphasis-90-default);` + - `background-color: var(--db-adaptive-bg-basic-level-2-default);` + - `font: var(--db-type-body-sm);` + +## SCSS + +- If you use SCSS, follow these rules: + - Always reference the file `node_modules/@db-ux/core-foundations/agent/scss/Variables.md` for variables like sizing, spacing, elevation, border, or container-size. This file contains the authoritative list of available variables. + - Use the examples provided in `Variables.md` to ensure correct usage. + - Always use `@use` for imports: + - Variables: `@use "@db-ux/core-foundations/build/styles/variables";` + - Colors: `@use "@db-ux/core-foundations/build/styles/colors";` + - Fonts: `@use "@db-ux/core-foundations/build/styles/fonts";` + - Never use `as *` for the `@use`, use it like this: + - `padding: variables.$db-spacing-fixed-md;` + - `height: variables.$db-sizing-md;` + - `width: variables.$db-container-xs;` + - `color: colors.$db-adaptive-on-bg-basic-emphasis-90-default;` + - `background-color: colors.$db-adaptive-bg-basic-level-2-default;` + - `font: fonts.$db-type-body-sm;` + +## Tailwind + +- If you use Tailwind, follow these rules: + - Always reference the file `node_modules/@db-ux/core-foundations/agent/tailwind/Variables.md` for variables like sizing, spacing, elevation, border, or container-size. This file contains the authoritative list of available variables. + - Use the examples provided in `Variables.md` to ensure correct usage like: + - padding: `p-fix-md` + - height: `h-siz-md` + - width: `w-container-xs` + - color: `text-adaptive-on-bg-basic-emphasis-90-default` + - background-color: `bg-adaptive-bg-basic-level-2-default` + - font: `text-body-sm` + - Always stick to the variables. Don't use values like `p-4` or `m-[16px]`; use `p-fix-xs` or `m-fix-md` instead. + +## Figma MCP + +- If you use Figma MCP always generate code with project's conventions, such as using @db-ux/core-components and @db-ux/core-foundations. +- If a code snippet from Figma MCP has a font-family with "DB Neo Screen Head" use HTML headlines (`

`, `

`, `

`, `

`, `

`, `
` HTML tags). +- If the headline has a `font-weight: 300;` use `data-variant="light"` additionally. +- If a code snippet has a Figma `Mode`, add it as `data-xxx`, where `xxx` is the mode in lower-case. + +### Tailwind + +If you use tailwind follow those rules as well: + +- Don't use values like `p-4` or `m-[16px]`; use `p-fix-xs` or `m-fix-md` instead. +- Never use something like `font-['DB_Neo_Screen_Head']` and `leading-[48px]` instead use `text-head-xx` class, where `-xx` can be a t-shirt size from `3xs` to `3xl`; If it has a `font-wight:300;` use `text-head-light-xx` instead. + + +# @db-ux/react-core-components +- Use "@db-ux/react-core-components" as import for components: + - use for `DBDrawer` or `Drawer` the file node_modules/@db-ux/react-core-components/agent/Drawer.md + - use for `DBTooltip` or `Tooltip` the file node_modules/@db-ux/react-core-components/agent/Tooltip.md + - use for `DBTextarea` or `Textarea` the file node_modules/@db-ux/react-core-components/agent/Textarea.md + - use for `DBTag` or `Tag` the file node_modules/@db-ux/react-core-components/agent/Tag.md + - use for `DBTabs` or `Tabs` the file node_modules/@db-ux/react-core-components/agent/Tabs.md + - use for `DBTabItem` or `TabItem` the file node_modules/@db-ux/react-core-components/agent/TabItem.md + - use for `DBSwitch` or `Switch` the file node_modules/@db-ux/react-core-components/agent/Switch.md + - use for `DBStack` or `Stack` the file node_modules/@db-ux/react-core-components/agent/Stack.md + - use for `DBSelect` or `Select` the file node_modules/@db-ux/react-core-components/agent/Select.md + - use for `DBSection` or `Section` the file node_modules/@db-ux/react-core-components/agent/Section.md + - use for `DBRadio` or `Radio` the file node_modules/@db-ux/react-core-components/agent/Radio.md + - use for `DBPopover` or `Popover` the file node_modules/@db-ux/react-core-components/agent/Popover.md + - use for `DBPage` or `Page` the file node_modules/@db-ux/react-core-components/agent/Page.md + - use for `DBNotification` or `Notification` the file node_modules/@db-ux/react-core-components/agent/Notification.md + - use for `DBNavigationItem` or `NavigationItem` the file node_modules/@db-ux/react-core-components/agent/NavigationItem.md + - use for `DBNavigation` or `Navigation` the file node_modules/@db-ux/react-core-components/agent/Navigation.md + - use for `DBLink` or `Link` the file node_modules/@db-ux/react-core-components/agent/Link.md + - use for `DBInput` or `Input` the file node_modules/@db-ux/react-core-components/agent/Input.md + - use for `DBInfotext` or `Infotext` the file node_modules/@db-ux/react-core-components/agent/Infotext.md + - use for `DBIcon` or `Icon` the file node_modules/@db-ux/react-core-components/agent/Icon.md + - use for `DBHeader` or `Header` the file node_modules/@db-ux/react-core-components/agent/Header.md + - use for `DBDivider` or `Divider` the file node_modules/@db-ux/react-core-components/agent/Divider.md + - use for `DBCustomSelect` or `CustomSelect` the file node_modules/@db-ux/react-core-components/agent/CustomSelect.md + - use for `DBCheckbox` or `Checkbox` the file node_modules/@db-ux/react-core-components/agent/Checkbox.md + - use for `DBCard` or `Card` the file node_modules/@db-ux/react-core-components/agent/Card.md + - use for `DBButton` or `Button` the file node_modules/@db-ux/react-core-components/agent/Button.md + - use for `DBBrand` or `Brand` the file node_modules/@db-ux/react-core-components/agent/Brand.md + - use for `DBBadge` or `Badge` the file node_modules/@db-ux/react-core-components/agent/Badge.md + - use for `DBAccordionItem` or `AccordionItem` the file node_modules/@db-ux/react-core-components/agent/AccordionItem.md + - use for `DBAccordion` or `Accordion` the file node_modules/@db-ux/react-core-components/agent/Accordion.md + +--- END: DB UX Copilot Instructions – do not edit above --- + \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..1d6915c --- /dev/null +++ b/.prettierrc @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/prettierrc", + "singleQuote": true, + "trailingComma": "all", + "printWidth": 100, + "tabWidth": 2, + "semi": true, + "plugins": ["prettier-plugin-astro"], + "overrides": [ + { + "files": "*.astro", + "options": { + "parser": "astro" + } + }, + { + "files": "*.mdx", + "options": { + "parser": "mdx" + } + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index d830cd4..40dd093 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ iconTrailing: "arrow_right" Below is an explanation of each field: | Property | Type | Default | Description | -| --------------------- | --------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +|-----------------------|-----------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **`layout`** | `string` | required | Always use `@template/layouts/default` for standard pages. | | **`title`** | `string` | — | The name shown in the navigation and as the page headline. | | **`hidePage`** | `boolean` | `false` | If set to `true`, this page will **not** be directly visible in the navigation and users will be redirected to the first visible child page instead. Useful for sections that act as folders rather than actual pages. | @@ -87,4 +87,37 @@ Below is an explanation of each field: * Use `order` values like `1, 2, 3…` for clarity. * Avoid duplicate titles in the same folder level. * For “section overview” pages that should not have content themselves, set `hidePage: true` and place the actual content in child pages. -* Only set `isSubNavigation: true` on parent pages that have multiple related subpages. \ No newline at end of file +* Only set `isSubNavigation: true` on parent pages that have multiple related subpages. +\n+## 🎨 TextImage Bildmasken +\n+Der `TextImage` Komponenten-Prop `mask` erlaubt weiche Ausblendungen (Fades) an einer oder zwei Kanten – ähnlich wie bei linear.app. +\n+### Verwendung +\n+```astro + + Beschreibungstext … + +``` +\n+### Unterstützte Werte +\n+Einzelne Richtungen: +* `fade-right` +* `fade-left` +* `fade-top` +* `fade-bottom` +\n+Ecken (Kombination aus zwei Fades): +* `fade-bottom-right` +* `fade-bottom-left` +* `fade-top-right` +* `fade-top-left` +\n+### Technische Umsetzung +* Realisiert über CSS `mask-image` bzw. `-webkit-mask-image` mit zwei linearen Gradients bei Eck-Varianten. +* Die Gradients werden via `mask-composite: intersect` (WebKit: `-webkit-mask-composite: source-in`) kombiniert. +* Fallback: Browser ohne Mask-Unterstützung zeigen das Bild unverändert (keine zusätzliche Logik nötig). +\n+### Hinweise & Anpassung +* Die Intensität (z.B. 20% → 100%) kann bei Bedarf zentral in der CSS Datei (`TextImage.css`) angepasst werden. +* Für individuelle Projekte können weitere Varianten über zusätzliche `data-mask` Selektoren ergänzt werden. +\n+### Barrierefreiheit +* Die Maskierung beeinflusst nur die visuelle Darstellung, nicht den Alternativtext – `alt` sollte weiterhin aussagekräftig bleiben. \ No newline at end of file diff --git a/app.config.ts b/app.config.ts index 027063e..5a9162a 100644 --- a/app.config.ts +++ b/app.config.ts @@ -1,7 +1,7 @@ export const appConfig: AppConfig = { - title: "Design System", - hostname: "https://db-ux-design-system.github.io", - basePath: "/one-platform/", + title: 'Design System', + hostname: 'https://db-ux-design-system.github.io', + basePath: '/one-platform/', sitemapBlacklist: [], - language: "en", + language: 'en', }; diff --git a/app.navigation.ts b/app.navigation.ts index 1c040cd..f859b6b 100644 --- a/app.navigation.ts +++ b/app.navigation.ts @@ -1,3 +1,3 @@ -import { buildAppNavigationFromContent } from "@template/utils/content-navigation"; +import { buildAppNavigationFromContent } from '@template/utils/content-navigation'; export const appNavigation: AppNavigation = buildAppNavigationFromContent(); diff --git a/astro.config.mjs b/astro.config.mjs index 08a774b..ee1f838 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,11 +1,11 @@ // @ts-check -import { defineConfig } from "astro/config"; -import { appConfig } from "./app.config"; -import react from "@astrojs/react"; -import mdx from "@astrojs/mdx"; -import sitemap from "@astrojs/sitemap"; -import { filterSitemapBlacklist } from "./template/integrations/sitemap"; -import orama from "@orama/plugin-astro"; +import { defineConfig } from 'astro/config'; +import { appConfig } from './app.config'; +import react from '@astrojs/react'; +import mdx from '@astrojs/mdx'; +import sitemap from '@astrojs/sitemap'; +import { filterSitemapBlacklist } from './template/integrations/sitemap'; +import orama from '@orama/plugin-astro'; // https://astro.build/config export default defineConfig({ @@ -20,22 +20,30 @@ export default defineConfig({ orama({ pages: { pathMatcher: /\/.+\//, - language: "english", + language: 'english', }, }), ], - srcDir: "./content", - outDir: "./public", - publicDir: "./static", + srcDir: './content', + outDir: './public', + publicDir: './static', vite: { ssr: { - noExternal: ["@db-ux/react-core-components"], + noExternal: ['@db-ux/react-core-components'], + }, + resolve: { + alias: { + '@components': new URL('./template/components', import.meta.url).pathname, + '@template': new URL('./template', import.meta.url).pathname, + '@content': new URL('./content', import.meta.url).pathname, + '@config': new URL('./app.config.ts', import.meta.url).pathname, + }, }, }, devToolbar: { enabled: false, }, build: { - inlineStylesheets: "always", + inlineStylesheets: 'always', }, }); diff --git a/content/pages/about-us/_components/AvatarSection.astro b/content/pages/about-us/_components/AvatarSection.astro new file mode 100644 index 0000000..a671469 --- /dev/null +++ b/content/pages/about-us/_components/AvatarSection.astro @@ -0,0 +1,96 @@ +--- +import { appConfig } from '@config'; +import { DBSection, DBStack } from '@db-ux/react-core-components'; +import { Avatar } from '@components'; +--- + + + + + + + + + +
+

+ DB is home to many exceptional product teams. Our role is to create the conditions in which + their work can thrive, scale, and continuously improve. +

+

+ The DB UX Design System Team works on the core content and framework of the design system, + advancing it both strategically and operationally. Our aim remains the same: to make the + system accessible to all DB employees and meaningfully support their daily work. +

+

+ We empower designers and engineers across DB to actively shape the system. With guidance, + shared standards, and clear contribution paths, the system grows through the expertise of + those who use it every day. This collective approach strengthens coherence, accelerates + delivery, and establishes the Design System as a shared asset for the entire organization. +

+
+ + + Signature Tobias Oberpaul + Signature Lea Perchermeier + + + Signature Maximilian Franzke + Signature Luis Schroff + + +
+
+ + diff --git a/content/pages/about-us/_components/CtaSection.astro b/content/pages/about-us/_components/CtaSection.astro new file mode 100644 index 0000000..644482e --- /dev/null +++ b/content/pages/about-us/_components/CtaSection.astro @@ -0,0 +1,16 @@ +--- +import { DBSection } from '@db-ux/react-core-components'; +import { CTA } from '@components'; +--- + + + + diff --git a/content/pages/about-us/index.mdx b/content/pages/about-us/index.mdx new file mode 100644 index 0000000..5f10ee4 --- /dev/null +++ b/content/pages/about-us/index.mdx @@ -0,0 +1,13 @@ +--- +order: 2 +layout: "@template/layouts/default" +title: "Our Vision" +headline: "An ideal environment for creating outstanding digital solutions." +--- + +import AvatarSection from './_components/AvatarSection.astro'; +import CtaSection from './_components/CtaSection.astro'; + + + + \ No newline at end of file diff --git a/content/pages/documentation/get-started/index.mdx b/content/pages/documentation/get-started/index.mdx new file mode 100644 index 0000000..05f3d2c --- /dev/null +++ b/content/pages/documentation/get-started/index.mdx @@ -0,0 +1,9 @@ +--- +order: 4 +layout: "@template/layouts/default" +title: "Get Started" +headline: "Work in progress" +description: "Content is being prepared." +heroImage: "/one-platform/assets/In-Progress--Lightmode--C.png" +heroImageAlt: "For Developer Visual" +--- \ No newline at end of file diff --git a/content/pages/resources/documentation/index.md b/content/pages/documentation/index.md similarity index 75% rename from content/pages/resources/documentation/index.md rename to content/pages/documentation/index.md index ad23786..c9c2f12 100644 --- a/content/pages/resources/documentation/index.md +++ b/content/pages/documentation/index.md @@ -1,8 +1,8 @@ --- +order: 3 layout: "@template/layouts/default" title: "Documentation" hidePage: true isSubNavigation: true +isMenuItemDisabled: true --- - -XXX \ No newline at end of file diff --git a/content/pages/home/_components/DesignedForSection.astro b/content/pages/home/_components/DesignedForSection.astro new file mode 100644 index 0000000..4a6eb38 --- /dev/null +++ b/content/pages/home/_components/DesignedForSection.astro @@ -0,0 +1,92 @@ +--- +import { appConfig } from '@config'; +import { DBButton, DBCard, DBSection, DBStack } from '@db-ux/react-core-components'; +import { SectionTitle, TextImage } from '@components'; +--- + + + + + diff --git a/content/pages/home/_components/InteractiveDemoSection.astro b/content/pages/home/_components/InteractiveDemoSection.astro new file mode 100644 index 0000000..7c3251b --- /dev/null +++ b/content/pages/home/_components/InteractiveDemoSection.astro @@ -0,0 +1,9 @@ +--- +import { DBSection } from '@db-ux/react-core-components'; +import InteractiveDemo from '@template/components/InteractiveDemo/InteractiveDemo.astro'; +import { interactiveDemoOptions, interactiveDemoDefaultOptionId } from '../home.config.ts'; +--- + + + + diff --git a/content/pages/home/_components/PackagesSection.astro b/content/pages/home/_components/PackagesSection.astro new file mode 100644 index 0000000..2ff64e1 --- /dev/null +++ b/content/pages/home/_components/PackagesSection.astro @@ -0,0 +1,102 @@ +--- +import { appConfig } from '@config'; +import { DBCard, DBSection, DBStack } from '@db-ux/react-core-components'; +import { SectionTitle, TextImage, DisabledWrapper } from '@components'; +--- + + + + + + + + Shared base tokens and modes provide a stable foundation for clear and coherent + interfaces. + + + + + + + Core components ensure predictable interactions across products. + + + + + + + Contextual standards that build on the core system to support domain-specific needs. + + + + + + + + Provide reusable interaction models that guide consistent behavior across products. + + + + + + + Offer structured starting points that speed up page creation and enforce coherent + layouts. + + + + + + diff --git a/content/pages/home/_components/PageHeroSection.astro b/content/pages/home/_components/PageHeroSection.astro new file mode 100644 index 0000000..68729fd --- /dev/null +++ b/content/pages/home/_components/PageHeroSection.astro @@ -0,0 +1,13 @@ +--- +import { DBSection } from '@db-ux/react-core-components'; +import PageHero from '@template/components/PageHero/PageHero.astro'; +--- + + + + diff --git a/content/pages/home/_components/SharedStandardsSection.astro b/content/pages/home/_components/SharedStandardsSection.astro new file mode 100644 index 0000000..36048c2 --- /dev/null +++ b/content/pages/home/_components/SharedStandardsSection.astro @@ -0,0 +1,15 @@ +--- +import { DBSection } from '@db-ux/react-core-components'; +import { CTA } from '@components'; +--- + + + + diff --git a/content/pages/home/_components/TestimonialsSection.astro b/content/pages/home/_components/TestimonialsSection.astro new file mode 100644 index 0000000..e49c7a7 --- /dev/null +++ b/content/pages/home/_components/TestimonialsSection.astro @@ -0,0 +1,60 @@ +--- +import { appConfig } from '@config'; +import { DBCard, DBSection } from '@db-ux/react-core-components'; +import { Carousel, TextImage } from '@components'; +--- + + + + + + Finn Hoffmeister
+ Product Owner @ DB Systel +
+
+ + + Patrick Weber
+ Design Lead @ DB Fernverkehr +
+
+ + + Danny Koppenhagen
+ Frontend Architect @ DB Systel +
+
+
+
diff --git a/content/pages/home/home.config.ts b/content/pages/home/home.config.ts new file mode 100644 index 0000000..e24ccfb --- /dev/null +++ b/content/pages/home/home.config.ts @@ -0,0 +1,37 @@ +import { appConfig } from '@config'; + +export const interactiveDemoOptions = [ + { + id: 'neutral-light', + color: 'neutral', + variant: 'filled', + src: `${appConfig.basePath}assets/interactive-demo/Neutral--Lightmode--C.png`, + label: 'Neutral', + }, + { + id: 'db-light', + icon: 'db', + color: 'red', + variant: 'filled', + src: `${appConfig.basePath}assets/interactive-demo/DB--Lightmode--C.png`, + label: 'Deutsche Bahn', + }, + { + id: 'sbahn-light', + icon: 's_bahn', + color: 'green', + variant: 'filled', + src: `${appConfig.basePath}assets/interactive-demo/SB--Lightmode--C.png`, + label: 'S-Bahn', + }, + { + id: 'ri-light', + icon: 'train_station', + color: 'blue', + variant: 'filled', + src: `${appConfig.basePath}assets/interactive-demo/RI--Lightmode--C.png`, + label: 'Station & Service', + }, +]; + +export const interactiveDemoDefaultOptionId = 'db-light'; diff --git a/content/pages/home/index.mdx b/content/pages/home/index.mdx new file mode 100644 index 0000000..2d37293 --- /dev/null +++ b/content/pages/home/index.mdx @@ -0,0 +1,23 @@ +--- +layout: "@template/layouts/default" +nav: false +--- + +import PageHeroSection from './_components/PageHeroSection.astro'; +import InteractiveDemoSection from './_components/InteractiveDemoSection.astro'; +import PackagesSection from './_components/PackagesSection.astro'; +import DesignedForSection from './_components/DesignedForSection.astro'; +import TestimonialsSection from './_components/TestimonialsSection.astro'; +import SharedStandardsSection from './_components/SharedStandardsSection.astro'; + + + + + + + + + + + + \ No newline at end of file diff --git a/content/pages/index.mdx b/content/pages/index.mdx index 7c2ad19..0eee773 100644 --- a/content/pages/index.mdx +++ b/content/pages/index.mdx @@ -1,17 +1,3 @@ ---- -layout: "@template/layouts/default" -toc: false ---- +import HomePage from "./home/index.mdx"; -import { appConfig } from "../../app.config"; - -# Das Design System für Customer und Enterprise. One Single Source for all. - -Starte jetzt – und bringe Konsistenz, Effizienz und Qualität in jedes Projekt - - - Start now - - - Contact - + \ No newline at end of file diff --git a/content/pages/products-and-services/components-and-patterns/index.md b/content/pages/products-and-services/components-and-patterns/index.md deleted file mode 100644 index ea98384..0000000 --- a/content/pages/products-and-services/components-and-patterns/index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: "@template/layouts/default" -title: "Components & Patterns" ---- - -XXX \ No newline at end of file diff --git a/content/pages/products-and-services/components/_components/ConfigurableSection.astro b/content/pages/products-and-services/components/_components/ConfigurableSection.astro new file mode 100644 index 0000000..b0ba7ef --- /dev/null +++ b/content/pages/products-and-services/components/_components/ConfigurableSection.astro @@ -0,0 +1,17 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Variants, sizes, and content adapt to product needs without altering structure. + + diff --git a/content/pages/products-and-services/components/_components/MaintenanceSection.astro b/content/pages/products-and-services/components/_components/MaintenanceSection.astro new file mode 100644 index 0000000..d9804c3 --- /dev/null +++ b/content/pages/products-and-services/components/_components/MaintenanceSection.astro @@ -0,0 +1,16 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Regular updates improve stability and support long-term use. + + diff --git a/content/pages/products-and-services/components/_components/PracticalGuidanceSection.astro b/content/pages/products-and-services/components/_components/PracticalGuidanceSection.astro new file mode 100644 index 0000000..5e39fc2 --- /dev/null +++ b/content/pages/products-and-services/components/_components/PracticalGuidanceSection.astro @@ -0,0 +1,16 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Usage recommendations support clear decisions and coherent user experiences. + + diff --git a/content/pages/products-and-services/components/_components/SharedSourceSection.astro b/content/pages/products-and-services/components/_components/SharedSourceSection.astro new file mode 100644 index 0000000..5aa4f98 --- /dev/null +++ b/content/pages/products-and-services/components/_components/SharedSourceSection.astro @@ -0,0 +1,17 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Design and code rely on the same underlying logic for aligned implementation. + + diff --git a/content/pages/products-and-services/components/_components/TestedAndVerifiedSection.astro b/content/pages/products-and-services/components/_components/TestedAndVerifiedSection.astro new file mode 100644 index 0000000..36551eb --- /dev/null +++ b/content/pages/products-and-services/components/_components/TestedAndVerifiedSection.astro @@ -0,0 +1,21 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Components meet accessibility and reliability requirements. + + diff --git a/content/pages/products-and-services/components/index.mdx b/content/pages/products-and-services/components/index.mdx new file mode 100644 index 0000000..e4bc537 --- /dev/null +++ b/content/pages/products-and-services/components/index.mdx @@ -0,0 +1,28 @@ +--- +order: 2 +layout: "@template/layouts/default" +title: "Components" +headline: "Build consistent interfaces" +description: "Core components ensure predictable interactions across products." +heroImage: "/one-platform/assets/components/Components--C.png" +heroImageAlt: "Components Visual" +--- + +import TestedAndVerifiedSection from './_components/TestedAndVerifiedSection.astro'; +import ConfigurableSection from './_components/ConfigurableSection.astro'; +import MaintenanceSection from './_components/MaintenanceSection.astro'; +import SharedSourceSection from './_components/SharedSourceSection.astro'; +import PracticalGuidanceSection from './_components/PracticalGuidanceSection.astro'; +import { ContactUsSection } from '@components'; + + + + + + + + + + + + \ No newline at end of file diff --git a/content/pages/products-and-services/extensions/_components/ExtensionsSection.astro b/content/pages/products-and-services/extensions/_components/ExtensionsSection.astro new file mode 100644 index 0000000..4f4430e --- /dev/null +++ b/content/pages/products-and-services/extensions/_components/ExtensionsSection.astro @@ -0,0 +1,87 @@ +--- +import { appConfig } from '@config'; +import { DBCard, DBSection, DBStack } from '@db-ux/react-core-components'; +import { DisabledWrapper, TextImage } from '@components'; +--- + + + + + + + + Deliver reliable traveler information. + + + + + + + Enable clear visualization of complex data. + + + + + + + + + + Display large datasets in a consistent format. + + + + + + + + + Support consistent communication across channels. + + + + + + + diff --git a/content/pages/products-and-services/extensions/index.md b/content/pages/products-and-services/extensions/index.md deleted file mode 100644 index 11689ad..0000000 --- a/content/pages/products-and-services/extensions/index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: "@template/layouts/default" -title: "Extensions" ---- - -XXX \ No newline at end of file diff --git a/content/pages/products-and-services/extensions/index.mdx b/content/pages/products-and-services/extensions/index.mdx new file mode 100644 index 0000000..1a16c42 --- /dev/null +++ b/content/pages/products-and-services/extensions/index.mdx @@ -0,0 +1,16 @@ +--- +order: 5 +layout: "@template/layouts/default" +title: "Extensions" +headline: "Extend with purpose" +description: "Contextual standards that build on the core system to support domain-specific needs." +heroImage: "/one-platform/assets/extensions/Extensions--C.png" +heroImageAlt: "Components Visual" +--- + +import ExtensionsSections from './_components/ExtensionsSection.astro'; +import { ContactUsSection } from '@components'; + + + + \ No newline at end of file diff --git a/content/pages/products-and-services/for-designer/_components/ConsistentResultsSection.astro b/content/pages/products-and-services/for-designer/_components/ConsistentResultsSection.astro new file mode 100644 index 0000000..0421b57 --- /dev/null +++ b/content/pages/products-and-services/for-designer/_components/ConsistentResultsSection.astro @@ -0,0 +1,21 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Ensure a shared visual language and predictable outcomes across products and devices. + + diff --git a/content/pages/products-and-services/for-designer/_components/FlexibleChoicesSection.astro b/content/pages/products-and-services/for-designer/_components/FlexibleChoicesSection.astro new file mode 100644 index 0000000..e77b1d5 --- /dev/null +++ b/content/pages/products-and-services/for-designer/_components/FlexibleChoicesSection.astro @@ -0,0 +1,17 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Adapt components and tokens to fit context without losing alignment. + + diff --git a/content/pages/products-and-services/for-designer/_components/ReliableQualitySection.astro b/content/pages/products-and-services/for-designer/_components/ReliableQualitySection.astro new file mode 100644 index 0000000..57abb9f --- /dev/null +++ b/content/pages/products-and-services/for-designer/_components/ReliableQualitySection.astro @@ -0,0 +1,16 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Use tested patterns that reduce errors and rework. + + diff --git a/content/pages/products-and-services/for-designer/_components/SmoothHandoffSection.astro b/content/pages/products-and-services/for-designer/_components/SmoothHandoffSection.astro new file mode 100644 index 0000000..e1ff3d7 --- /dev/null +++ b/content/pages/products-and-services/for-designer/_components/SmoothHandoffSection.astro @@ -0,0 +1,17 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Rely on clear specs and shared foundations for efficient collaboration with developers. + + diff --git a/content/pages/products-and-services/for-designer/index.mdx b/content/pages/products-and-services/for-designer/index.mdx new file mode 100644 index 0000000..6d48013 --- /dev/null +++ b/content/pages/products-and-services/for-designer/index.mdx @@ -0,0 +1,25 @@ +--- +order: 6 +layout: "@template/layouts/default" +title: "For Designer" +headline: "Design with confidence" +description: "A shared system that supports clear decisions and consistent interfaces across teams." +heroImage: "/one-platform/assets/for-designer/For-Designer--C.png" +heroImageAlt: "For Designer Visual" +--- + +import ConsistentResultsSection from './_components/ConsistentResultsSection.astro'; +import FlexibleChoicesSection from './_components/FlexibleChoicesSection.astro'; +import ReliableQualitySection from './_components/ReliableQualitySection.astro'; +import SmoothHandoffSection from './_components/SmoothHandoffSection.astro'; +import { ContactUsSection } from '@components'; + + + + + + + + + + \ No newline at end of file diff --git a/content/pages/products-and-services/for-developer/_components/EfficientWorkflowsSection.astro b/content/pages/products-and-services/for-developer/_components/EfficientWorkflowsSection.astro new file mode 100644 index 0000000..419d575 --- /dev/null +++ b/content/pages/products-and-services/for-developer/_components/EfficientWorkflowsSection.astro @@ -0,0 +1,21 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Re-use stable components to reduce repetitive implementation effort. + + diff --git a/content/pages/products-and-services/for-developer/_components/FlexibleIntegrationSection.astro b/content/pages/products-and-services/for-developer/_components/FlexibleIntegrationSection.astro new file mode 100644 index 0000000..298480c --- /dev/null +++ b/content/pages/products-and-services/for-developer/_components/FlexibleIntegrationSection.astro @@ -0,0 +1,17 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Adjust variants and tokens to meet product needs without diverging from the system. + + diff --git a/content/pages/products-and-services/for-developer/_components/PredictableMaintenanceSection.astro b/content/pages/products-and-services/for-developer/_components/PredictableMaintenanceSection.astro new file mode 100644 index 0000000..3f027c3 --- /dev/null +++ b/content/pages/products-and-services/for-developer/_components/PredictableMaintenanceSection.astro @@ -0,0 +1,16 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Rely on scheduled updates and stable versioning to plan changes confidently. + + diff --git a/content/pages/products-and-services/for-developer/_components/SmoothHandoffSection.astro b/content/pages/products-and-services/for-developer/_components/SmoothHandoffSection.astro new file mode 100644 index 0000000..5488be2 --- /dev/null +++ b/content/pages/products-and-services/for-developer/_components/SmoothHandoffSection.astro @@ -0,0 +1,17 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Use aligned specifications and shared models to reduce ambiguity between design and development. + + diff --git a/content/pages/products-and-services/for-developer/index.mdx b/content/pages/products-and-services/for-developer/index.mdx new file mode 100644 index 0000000..4ad9d70 --- /dev/null +++ b/content/pages/products-and-services/for-developer/index.mdx @@ -0,0 +1,25 @@ +--- +order: 7 +layout: "@template/layouts/default" +title: "For Developer" +headline: "Build with consistency" +description: "A shared component system that streamlines implementation and reduces decision overhead." +heroImage: "/one-platform/assets/for-developer/For-Developer--C.png" +heroImageAlt: "For Developer Visual" +--- + +import EfficientWorkflowsSection from './_components/EfficientWorkflowsSection.astro'; +import FlexibleIntegrationSection from './_components/FlexibleIntegrationSection.astro'; +import PredictableMaintenanceSection from './_components/PredictableMaintenanceSection.astro'; +import SmoothHandoffSection from './_components/SmoothHandoffSection.astro'; +import { ContactUsSection } from '@components'; + + + + + + + + + + \ No newline at end of file diff --git a/content/pages/products-and-services/for-productmanagement/_components/EfficientDeliverySection.astro b/content/pages/products-and-services/for-productmanagement/_components/EfficientDeliverySection.astro new file mode 100644 index 0000000..6ae17e8 --- /dev/null +++ b/content/pages/products-and-services/for-productmanagement/_components/EfficientDeliverySection.astro @@ -0,0 +1,21 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Reduce time spent on repeated design and implementation decisions. + + diff --git a/content/pages/products-and-services/for-productmanagement/_components/LowerRiskSection.astro b/content/pages/products-and-services/for-productmanagement/_components/LowerRiskSection.astro new file mode 100644 index 0000000..18cab5a --- /dev/null +++ b/content/pages/products-and-services/for-productmanagement/_components/LowerRiskSection.astro @@ -0,0 +1,17 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Rely on accessible, brand-aligned, and tested patterns to prevent avoidable rework. + + diff --git a/content/pages/products-and-services/for-productmanagement/_components/ScalableApproachSection.astro b/content/pages/products-and-services/for-productmanagement/_components/ScalableApproachSection.astro new file mode 100644 index 0000000..b56dd78 --- /dev/null +++ b/content/pages/products-and-services/for-productmanagement/_components/ScalableApproachSection.astro @@ -0,0 +1,16 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Support multiple teams and products with standards that grow over time. + + diff --git a/content/pages/products-and-services/for-productmanagement/index.mdx b/content/pages/products-and-services/for-productmanagement/index.mdx new file mode 100644 index 0000000..1f990cb --- /dev/null +++ b/content/pages/products-and-services/for-productmanagement/index.mdx @@ -0,0 +1,22 @@ +--- +order: 8 +layout: "@template/layouts/default" +title: "For Product Management" +headline: "Align for impact" +description: "A shared system that supports consistent decision-making and efficient product delivery across teams." +heroImage: "/one-platform/assets/for-productmanagement/For-Productmanagement--C.png" +heroImageAlt: "For Product Management Visual" +--- + +import EfficientDeliverySection from './_components/EfficientDeliverySection.astro'; +import LowerRiskSection from './_components/LowerRiskSection.astro'; +import ScalableApproachSection from './_components/ScalableApproachSection.astro'; +import { ContactUsSection } from '@components'; + + + + + + + + \ No newline at end of file diff --git a/content/pages/products-and-services/foundations/_components/AdaptiveColorsSection.astro b/content/pages/products-and-services/foundations/_components/AdaptiveColorsSection.astro new file mode 100644 index 0000000..9ef5fcd --- /dev/null +++ b/content/pages/products-and-services/foundations/_components/AdaptiveColorsSection.astro @@ -0,0 +1,17 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Maintain consistent contrast and tone across different color modes and contexts. + + diff --git a/content/pages/products-and-services/foundations/_components/BaseTokensSection.astro b/content/pages/products-and-services/foundations/_components/BaseTokensSection.astro new file mode 100644 index 0000000..d536ce9 --- /dev/null +++ b/content/pages/products-and-services/foundations/_components/BaseTokensSection.astro @@ -0,0 +1,17 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Define reusable design values applied consistently across the system. + + diff --git a/content/pages/products-and-services/foundations/_components/DarkmodeSection.astro b/content/pages/products-and-services/foundations/_components/DarkmodeSection.astro new file mode 100644 index 0000000..4fb6b88 --- /dev/null +++ b/content/pages/products-and-services/foundations/_components/DarkmodeSection.astro @@ -0,0 +1,17 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Support comfortable and readable interfaces across different luminance environments. + + diff --git a/content/pages/products-and-services/foundations/_components/MaterialsSection.astro b/content/pages/products-and-services/foundations/_components/MaterialsSection.astro new file mode 100644 index 0000000..ccee6df --- /dev/null +++ b/content/pages/products-and-services/foundations/_components/MaterialsSection.astro @@ -0,0 +1,16 @@ +--- +import { appConfig } from '@config'; +import { DBSection } from '@db-ux/react-core-components'; +import { TextImage } from '@components'; +--- + + + + Create visual hierarchy through variations in borders, opacity, and fill. + + diff --git a/content/pages/products-and-services/foundations/index.md b/content/pages/products-and-services/foundations/index.md deleted file mode 100644 index a458657..0000000 --- a/content/pages/products-and-services/foundations/index.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: "@template/layouts/default" -title: "Foundations" ---- - -XXX \ No newline at end of file diff --git a/content/pages/products-and-services/foundations/index.mdx b/content/pages/products-and-services/foundations/index.mdx new file mode 100644 index 0000000..4e7b53e --- /dev/null +++ b/content/pages/products-and-services/foundations/index.mdx @@ -0,0 +1,25 @@ +--- +order: 1 +layout: "@template/layouts/default" +title: "Foundation" +headline: "Start with clarity" +description: "Shared base tokens and modes provide a stable foundation for clear and coherent interfaces." +heroImage: "/one-platform/assets/foundations/Foundations--C.png" +heroImageAlt: "Foundations Visual" +--- + +import BaseTokensSection from './_components/BaseTokensSection.astro'; +import AdaptiveColorsSection from './_components/AdaptiveColorsSection.astro'; +import MaterialsSection from './_components/MaterialsSection.astro'; +import DarkModeSection from './_components/DarkModeSection.astro'; +import { ContactUsSection } from '@components'; + + + + + + + + + + \ No newline at end of file diff --git a/content/pages/products-and-services/index.md b/content/pages/products-and-services/index.md index 0546271..6e4222f 100644 --- a/content/pages/products-and-services/index.md +++ b/content/pages/products-and-services/index.md @@ -1,5 +1,5 @@ --- -title: "Products and Services" +title: "Products & Services" hidePage: true order: 1 --- \ No newline at end of file diff --git a/content/pages/community/index.md b/content/pages/products-and-services/pattern/index.mdx similarity index 52% rename from content/pages/community/index.md rename to content/pages/products-and-services/pattern/index.mdx index ff4b6ae..ec69ec2 100644 --- a/content/pages/community/index.md +++ b/content/pages/products-and-services/pattern/index.mdx @@ -1,6 +1,6 @@ --- -layout: "@template/layouts/default" -title: "Community" -iconTrailing: "lock_closed" order: 3 +isMenuItemDisabled: true +layout: "@template/layouts/default" +title: "Pattern" --- \ No newline at end of file diff --git a/content/pages/products-and-services/templates/index.md b/content/pages/products-and-services/templates/index.mdx similarity index 61% rename from content/pages/products-and-services/templates/index.md rename to content/pages/products-and-services/templates/index.mdx index 767029f..27af8a3 100644 --- a/content/pages/products-and-services/templates/index.md +++ b/content/pages/products-and-services/templates/index.mdx @@ -1,6 +1,6 @@ --- +order: 4 +isMenuItemDisabled: true layout: "@template/layouts/default" title: "Templates" ---- - -XXX \ No newline at end of file +--- \ No newline at end of file diff --git a/content/pages/resources/documentation/foundations/index.md b/content/pages/resources/documentation/foundations/index.md deleted file mode 100644 index 4469131..0000000 --- a/content/pages/resources/documentation/foundations/index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -layout: "@template/layouts/default" -title: "Foundations" -order: 2 ---- - -XXX \ No newline at end of file diff --git a/content/pages/resources/documentation/getting-started/index.md b/content/pages/resources/documentation/getting-started/index.md deleted file mode 100644 index 1905ed6..0000000 --- a/content/pages/resources/documentation/getting-started/index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -layout: "@template/layouts/default" -title: "Getting Started" -order: 1 ---- - -XXX \ No newline at end of file diff --git a/content/pages/resources/index.md b/content/pages/resources/index.md deleted file mode 100644 index 14edfcd..0000000 --- a/content/pages/resources/index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Resources" -hidePage: true -order: 2 ---- \ No newline at end of file diff --git a/static/assets/Components-Teaser--C.png b/static/assets/Components-Teaser--C.png new file mode 100644 index 0000000..6fab186 Binary files /dev/null and b/static/assets/Components-Teaser--C.png differ diff --git a/static/assets/Design-System--C.png b/static/assets/Design-System--C.png new file mode 100644 index 0000000..415ba3c Binary files /dev/null and b/static/assets/Design-System--C.png differ diff --git a/static/assets/Extensions-Teaser--C.png b/static/assets/Extensions-Teaser--C.png new file mode 100644 index 0000000..2a41627 Binary files /dev/null and b/static/assets/Extensions-Teaser--C.png differ diff --git a/static/assets/Foundations-Teaser--C.png b/static/assets/Foundations-Teaser--C.png new file mode 100644 index 0000000..5c4099d Binary files /dev/null and b/static/assets/Foundations-Teaser--C.png differ diff --git a/static/assets/Image--C.jpg b/static/assets/Image--C.jpg new file mode 100644 index 0000000..7704542 Binary files /dev/null and b/static/assets/Image--C.jpg differ diff --git a/static/assets/In-Progress--Darkmode--C.png b/static/assets/In-Progress--Darkmode--C.png new file mode 100644 index 0000000..9b7e38c Binary files /dev/null and b/static/assets/In-Progress--Darkmode--C.png differ diff --git a/static/assets/In-Progress--Lightmode--C.png b/static/assets/In-Progress--Lightmode--C.png new file mode 100644 index 0000000..dd98566 Binary files /dev/null and b/static/assets/In-Progress--Lightmode--C.png differ diff --git a/static/assets/Patterns-Teaser--C.png b/static/assets/Patterns-Teaser--C.png new file mode 100644 index 0000000..82ca11e Binary files /dev/null and b/static/assets/Patterns-Teaser--C.png differ diff --git a/static/assets/Templates-Teaser--C.png b/static/assets/Templates-Teaser--C.png new file mode 100644 index 0000000..fce92b2 Binary files /dev/null and b/static/assets/Templates-Teaser--C.png differ diff --git a/static/assets/components/Components--C.png b/static/assets/components/Components--C.png new file mode 100644 index 0000000..2359144 Binary files /dev/null and b/static/assets/components/Components--C.png differ diff --git a/static/assets/components/Configurable--Darkmode--C.png b/static/assets/components/Configurable--Darkmode--C.png new file mode 100644 index 0000000..b58b440 Binary files /dev/null and b/static/assets/components/Configurable--Darkmode--C.png differ diff --git a/static/assets/components/Configurable--Lightmode--C.png b/static/assets/components/Configurable--Lightmode--C.png new file mode 100644 index 0000000..2af0782 Binary files /dev/null and b/static/assets/components/Configurable--Lightmode--C.png differ diff --git a/static/assets/components/Ongoing-Maintenance--Darkmode--C.png b/static/assets/components/Ongoing-Maintenance--Darkmode--C.png new file mode 100644 index 0000000..1cc38c0 Binary files /dev/null and b/static/assets/components/Ongoing-Maintenance--Darkmode--C.png differ diff --git a/static/assets/components/Ongoing-Maintenance--Lightmode--C.png b/static/assets/components/Ongoing-Maintenance--Lightmode--C.png new file mode 100644 index 0000000..429b0b1 Binary files /dev/null and b/static/assets/components/Ongoing-Maintenance--Lightmode--C.png differ diff --git a/static/assets/components/Practical-Guidance--Darkmode--C.png b/static/assets/components/Practical-Guidance--Darkmode--C.png new file mode 100644 index 0000000..70f2870 Binary files /dev/null and b/static/assets/components/Practical-Guidance--Darkmode--C.png differ diff --git a/static/assets/components/Practical-Guidance--Lightmode--C.png b/static/assets/components/Practical-Guidance--Lightmode--C.png new file mode 100644 index 0000000..e669be6 Binary files /dev/null and b/static/assets/components/Practical-Guidance--Lightmode--C.png differ diff --git a/static/assets/components/Shared-Source--Darkmode--C.png b/static/assets/components/Shared-Source--Darkmode--C.png new file mode 100644 index 0000000..b3ae2ba Binary files /dev/null and b/static/assets/components/Shared-Source--Darkmode--C.png differ diff --git a/static/assets/components/Shared-Source--Lightmode--C.png b/static/assets/components/Shared-Source--Lightmode--C.png new file mode 100644 index 0000000..df76925 Binary files /dev/null and b/static/assets/components/Shared-Source--Lightmode--C.png differ diff --git a/static/assets/components/Tested--Darkmode--C.png b/static/assets/components/Tested--Darkmode--C.png new file mode 100644 index 0000000..2d81bf2 Binary files /dev/null and b/static/assets/components/Tested--Darkmode--C.png differ diff --git a/static/assets/components/Tested--Lightmode--C.png b/static/assets/components/Tested--Lightmode--C.png new file mode 100644 index 0000000..e8a1cf8 Binary files /dev/null and b/static/assets/components/Tested--Lightmode--C.png differ diff --git a/static/assets/extensions/Content--Darkmode--C.png b/static/assets/extensions/Content--Darkmode--C.png new file mode 100644 index 0000000..feb3ffd Binary files /dev/null and b/static/assets/extensions/Content--Darkmode--C.png differ diff --git a/static/assets/extensions/Content--Lightmode--C.png b/static/assets/extensions/Content--Lightmode--C.png new file mode 100644 index 0000000..892019d Binary files /dev/null and b/static/assets/extensions/Content--Lightmode--C.png differ diff --git a/static/assets/extensions/DataViz--Darkmode--C.png b/static/assets/extensions/DataViz--Darkmode--C.png new file mode 100644 index 0000000..55173da Binary files /dev/null and b/static/assets/extensions/DataViz--Darkmode--C.png differ diff --git a/static/assets/extensions/DataViz--Lightmode--C.png b/static/assets/extensions/DataViz--Lightmode--C.png new file mode 100644 index 0000000..c25e8a1 Binary files /dev/null and b/static/assets/extensions/DataViz--Lightmode--C.png differ diff --git a/static/assets/extensions/Extensions--C.png b/static/assets/extensions/Extensions--C.png new file mode 100644 index 0000000..c0d50c0 Binary files /dev/null and b/static/assets/extensions/Extensions--C.png differ diff --git a/static/assets/extensions/RI--Darkmode--C.png b/static/assets/extensions/RI--Darkmode--C.png new file mode 100644 index 0000000..d3806ff Binary files /dev/null and b/static/assets/extensions/RI--Darkmode--C.png differ diff --git a/static/assets/extensions/RI--Lightmode--C.png b/static/assets/extensions/RI--Lightmode--C.png new file mode 100644 index 0000000..61a900f Binary files /dev/null and b/static/assets/extensions/RI--Lightmode--C.png differ diff --git a/static/assets/extensions/Table--Darkmode--C.png b/static/assets/extensions/Table--Darkmode--C.png new file mode 100644 index 0000000..27752a7 Binary files /dev/null and b/static/assets/extensions/Table--Darkmode--C.png differ diff --git a/static/assets/extensions/Table--Lightmode--C.png b/static/assets/extensions/Table--Lightmode--C.png new file mode 100644 index 0000000..5bd2794 Binary files /dev/null and b/static/assets/extensions/Table--Lightmode--C.png differ diff --git a/static/assets/for-designer/Consistent-Results--Darkmode--C.png b/static/assets/for-designer/Consistent-Results--Darkmode--C.png new file mode 100644 index 0000000..01a2f51 Binary files /dev/null and b/static/assets/for-designer/Consistent-Results--Darkmode--C.png differ diff --git a/static/assets/for-designer/Consistent-Results--Lightmode--C.png b/static/assets/for-designer/Consistent-Results--Lightmode--C.png new file mode 100644 index 0000000..a871623 Binary files /dev/null and b/static/assets/for-designer/Consistent-Results--Lightmode--C.png differ diff --git a/static/assets/for-designer/Flexible-Choices--Darkmode--C.png b/static/assets/for-designer/Flexible-Choices--Darkmode--C.png new file mode 100644 index 0000000..add150c Binary files /dev/null and b/static/assets/for-designer/Flexible-Choices--Darkmode--C.png differ diff --git a/static/assets/for-designer/Flexible-Choices--Lightmode--C.png b/static/assets/for-designer/Flexible-Choices--Lightmode--C.png new file mode 100644 index 0000000..223ba7b Binary files /dev/null and b/static/assets/for-designer/Flexible-Choices--Lightmode--C.png differ diff --git a/static/assets/for-designer/For-Designer--C.png b/static/assets/for-designer/For-Designer--C.png new file mode 100644 index 0000000..abfebfe Binary files /dev/null and b/static/assets/for-designer/For-Designer--C.png differ diff --git a/static/assets/for-designer/Reliable-Quality--Darkmode--C.png b/static/assets/for-designer/Reliable-Quality--Darkmode--C.png new file mode 100644 index 0000000..2d81bf2 Binary files /dev/null and b/static/assets/for-designer/Reliable-Quality--Darkmode--C.png differ diff --git a/static/assets/for-designer/Reliable-Quality--Lightmode--C.png b/static/assets/for-designer/Reliable-Quality--Lightmode--C.png new file mode 100644 index 0000000..2601133 Binary files /dev/null and b/static/assets/for-designer/Reliable-Quality--Lightmode--C.png differ diff --git a/static/assets/for-designer/Smooth-Handoff--Darkmode--C.png b/static/assets/for-designer/Smooth-Handoff--Darkmode--C.png new file mode 100644 index 0000000..4925ab1 Binary files /dev/null and b/static/assets/for-designer/Smooth-Handoff--Darkmode--C.png differ diff --git a/static/assets/for-designer/Smooth-Handoff--Lightmode--C.png b/static/assets/for-designer/Smooth-Handoff--Lightmode--C.png new file mode 100644 index 0000000..fd3559a Binary files /dev/null and b/static/assets/for-designer/Smooth-Handoff--Lightmode--C.png differ diff --git a/static/assets/for-developer/Efficient-Workflows--Darkmode--C.png b/static/assets/for-developer/Efficient-Workflows--Darkmode--C.png new file mode 100644 index 0000000..d7f9ddd Binary files /dev/null and b/static/assets/for-developer/Efficient-Workflows--Darkmode--C.png differ diff --git a/static/assets/for-developer/Efficient-Workflows--Lightmode--C.png b/static/assets/for-developer/Efficient-Workflows--Lightmode--C.png new file mode 100644 index 0000000..5c7dffb Binary files /dev/null and b/static/assets/for-developer/Efficient-Workflows--Lightmode--C.png differ diff --git a/static/assets/for-developer/Flexible-Integration--Darkmode--C.png b/static/assets/for-developer/Flexible-Integration--Darkmode--C.png new file mode 100644 index 0000000..a73a1dc Binary files /dev/null and b/static/assets/for-developer/Flexible-Integration--Darkmode--C.png differ diff --git a/static/assets/for-developer/Flexible-Integration--Lightmode--C.png b/static/assets/for-developer/Flexible-Integration--Lightmode--C.png new file mode 100644 index 0000000..4454bd8 Binary files /dev/null and b/static/assets/for-developer/Flexible-Integration--Lightmode--C.png differ diff --git a/static/assets/for-developer/For-Developer--C.png b/static/assets/for-developer/For-Developer--C.png new file mode 100644 index 0000000..4bb9772 Binary files /dev/null and b/static/assets/for-developer/For-Developer--C.png differ diff --git a/static/assets/for-developer/Predictable-Maintenance--Darkmode--C.png b/static/assets/for-developer/Predictable-Maintenance--Darkmode--C.png new file mode 100644 index 0000000..03b493c Binary files /dev/null and b/static/assets/for-developer/Predictable-Maintenance--Darkmode--C.png differ diff --git a/static/assets/for-developer/Predictable-Maintenance--Lightmode--C.png b/static/assets/for-developer/Predictable-Maintenance--Lightmode--C.png new file mode 100644 index 0000000..80e1522 Binary files /dev/null and b/static/assets/for-developer/Predictable-Maintenance--Lightmode--C.png differ diff --git a/static/assets/for-developer/Smooth-Handoff--Darkmode--C.png b/static/assets/for-developer/Smooth-Handoff--Darkmode--C.png new file mode 100644 index 0000000..4925ab1 Binary files /dev/null and b/static/assets/for-developer/Smooth-Handoff--Darkmode--C.png differ diff --git a/static/assets/for-developer/Smooth-Handoff--Lightmode--C.png b/static/assets/for-developer/Smooth-Handoff--Lightmode--C.png new file mode 100644 index 0000000..fd3559a Binary files /dev/null and b/static/assets/for-developer/Smooth-Handoff--Lightmode--C.png differ diff --git a/static/assets/for-productmanagement/Efficient-Delivery--Darkmode--C.png b/static/assets/for-productmanagement/Efficient-Delivery--Darkmode--C.png new file mode 100644 index 0000000..14c8ca2 Binary files /dev/null and b/static/assets/for-productmanagement/Efficient-Delivery--Darkmode--C.png differ diff --git a/static/assets/for-productmanagement/Efficient-Delivery--Lightmode--C.png b/static/assets/for-productmanagement/Efficient-Delivery--Lightmode--C.png new file mode 100644 index 0000000..c4ccdd8 Binary files /dev/null and b/static/assets/for-productmanagement/Efficient-Delivery--Lightmode--C.png differ diff --git a/static/assets/for-productmanagement/For-Productmanagement--C.png b/static/assets/for-productmanagement/For-Productmanagement--C.png new file mode 100644 index 0000000..d603157 Binary files /dev/null and b/static/assets/for-productmanagement/For-Productmanagement--C.png differ diff --git a/static/assets/for-productmanagement/Lower-Risk--Darkmode--C.png b/static/assets/for-productmanagement/Lower-Risk--Darkmode--C.png new file mode 100644 index 0000000..2d81bf2 Binary files /dev/null and b/static/assets/for-productmanagement/Lower-Risk--Darkmode--C.png differ diff --git a/static/assets/for-productmanagement/Lower-Risk--Lightmode--C.png b/static/assets/for-productmanagement/Lower-Risk--Lightmode--C.png new file mode 100644 index 0000000..a0190b5 Binary files /dev/null and b/static/assets/for-productmanagement/Lower-Risk--Lightmode--C.png differ diff --git a/static/assets/for-productmanagement/Scalable-Approach--Darkmode--C.png b/static/assets/for-productmanagement/Scalable-Approach--Darkmode--C.png new file mode 100644 index 0000000..54f64a8 Binary files /dev/null and b/static/assets/for-productmanagement/Scalable-Approach--Darkmode--C.png differ diff --git a/static/assets/for-productmanagement/Scalable-Approach--Lightmode--C.png b/static/assets/for-productmanagement/Scalable-Approach--Lightmode--C.png new file mode 100644 index 0000000..5a1200c Binary files /dev/null and b/static/assets/for-productmanagement/Scalable-Approach--Lightmode--C.png differ diff --git a/static/assets/foundations/Adaptive-Colors--Darkmode--C.png b/static/assets/foundations/Adaptive-Colors--Darkmode--C.png new file mode 100644 index 0000000..9b1e055 Binary files /dev/null and b/static/assets/foundations/Adaptive-Colors--Darkmode--C.png differ diff --git a/static/assets/foundations/Adaptive-Colors--Lightmode--C.png b/static/assets/foundations/Adaptive-Colors--Lightmode--C.png new file mode 100644 index 0000000..7ad032b Binary files /dev/null and b/static/assets/foundations/Adaptive-Colors--Lightmode--C.png differ diff --git a/static/assets/foundations/Base-Tokens--Darkmode--C.png b/static/assets/foundations/Base-Tokens--Darkmode--C.png new file mode 100644 index 0000000..229772e Binary files /dev/null and b/static/assets/foundations/Base-Tokens--Darkmode--C.png differ diff --git a/static/assets/foundations/Base-Tokens--Lightmode--C.png b/static/assets/foundations/Base-Tokens--Lightmode--C.png new file mode 100644 index 0000000..b7f6848 Binary files /dev/null and b/static/assets/foundations/Base-Tokens--Lightmode--C.png differ diff --git a/static/assets/foundations/Darkmode--Darkmode--C.png b/static/assets/foundations/Darkmode--Darkmode--C.png new file mode 100644 index 0000000..512385c Binary files /dev/null and b/static/assets/foundations/Darkmode--Darkmode--C.png differ diff --git a/static/assets/foundations/Darkmode--Lightmode--C.png b/static/assets/foundations/Darkmode--Lightmode--C.png new file mode 100644 index 0000000..512385c Binary files /dev/null and b/static/assets/foundations/Darkmode--Lightmode--C.png differ diff --git a/static/assets/foundations/Foundations--C.png b/static/assets/foundations/Foundations--C.png new file mode 100644 index 0000000..b698cd6 Binary files /dev/null and b/static/assets/foundations/Foundations--C.png differ diff --git a/static/assets/foundations/Materials--Darkmode--C.png b/static/assets/foundations/Materials--Darkmode--C.png new file mode 100644 index 0000000..96a502f Binary files /dev/null and b/static/assets/foundations/Materials--Darkmode--C.png differ diff --git a/static/assets/foundations/Materials--Lightmode--C.png b/static/assets/foundations/Materials--Lightmode--C.png new file mode 100644 index 0000000..e161b89 Binary files /dev/null and b/static/assets/foundations/Materials--Lightmode--C.png differ diff --git a/static/assets/interactive-demo/DB--Darkmode--C.png b/static/assets/interactive-demo/DB--Darkmode--C.png new file mode 100644 index 0000000..c7757c0 Binary files /dev/null and b/static/assets/interactive-demo/DB--Darkmode--C.png differ diff --git a/static/assets/interactive-demo/DB--Lightmode--C.png b/static/assets/interactive-demo/DB--Lightmode--C.png new file mode 100644 index 0000000..661c067 Binary files /dev/null and b/static/assets/interactive-demo/DB--Lightmode--C.png differ diff --git a/static/assets/interactive-demo/Neutral--Darkmode--C.png b/static/assets/interactive-demo/Neutral--Darkmode--C.png new file mode 100644 index 0000000..675e89e Binary files /dev/null and b/static/assets/interactive-demo/Neutral--Darkmode--C.png differ diff --git a/static/assets/interactive-demo/Neutral--Lightmode--C.png b/static/assets/interactive-demo/Neutral--Lightmode--C.png new file mode 100644 index 0000000..d77c1eb Binary files /dev/null and b/static/assets/interactive-demo/Neutral--Lightmode--C.png differ diff --git a/static/assets/interactive-demo/RI--Darkmode--C.png b/static/assets/interactive-demo/RI--Darkmode--C.png new file mode 100644 index 0000000..6a3ba07 Binary files /dev/null and b/static/assets/interactive-demo/RI--Darkmode--C.png differ diff --git a/static/assets/interactive-demo/RI--Lightmode--C.png b/static/assets/interactive-demo/RI--Lightmode--C.png new file mode 100644 index 0000000..2e0861a Binary files /dev/null and b/static/assets/interactive-demo/RI--Lightmode--C.png differ diff --git a/static/assets/interactive-demo/SB--Darkmode--C.png b/static/assets/interactive-demo/SB--Darkmode--C.png new file mode 100644 index 0000000..3999d2f Binary files /dev/null and b/static/assets/interactive-demo/SB--Darkmode--C.png differ diff --git a/static/assets/interactive-demo/SB--Lightmode--C.png b/static/assets/interactive-demo/SB--Lightmode--C.png new file mode 100644 index 0000000..0b2576d Binary files /dev/null and b/static/assets/interactive-demo/SB--Lightmode--C.png differ diff --git a/static/assets/people/Avatar-2--C.glb b/static/assets/people/Avatar-2--C.glb new file mode 100644 index 0000000..0afad95 Binary files /dev/null and b/static/assets/people/Avatar-2--C.glb differ diff --git a/static/assets/people/Avatar.glb b/static/assets/people/Avatar.glb new file mode 100644 index 0000000..93074bb Binary files /dev/null and b/static/assets/people/Avatar.glb differ diff --git a/static/assets/people/Danny-Koppenhagen--C.jpg b/static/assets/people/Danny-Koppenhagen--C.jpg new file mode 100644 index 0000000..7450ba0 Binary files /dev/null and b/static/assets/people/Danny-Koppenhagen--C.jpg differ diff --git a/static/assets/people/Finn-Hoffmeister--C.jpg b/static/assets/people/Finn-Hoffmeister--C.jpg new file mode 100644 index 0000000..5ac1b29 Binary files /dev/null and b/static/assets/people/Finn-Hoffmeister--C.jpg differ diff --git a/static/assets/people/Lea-Perchermeier--Avatar-1--C.glb b/static/assets/people/Lea-Perchermeier--Avatar-1--C.glb new file mode 100644 index 0000000..bc560bd Binary files /dev/null and b/static/assets/people/Lea-Perchermeier--Avatar-1--C.glb differ diff --git a/static/assets/people/Lea-Perchermeier--Avatar-2--C.glb b/static/assets/people/Lea-Perchermeier--Avatar-2--C.glb new file mode 100644 index 0000000..b225b5e Binary files /dev/null and b/static/assets/people/Lea-Perchermeier--Avatar-2--C.glb differ diff --git a/static/assets/people/Luis-Schroff--Avatar-1--C.glb b/static/assets/people/Luis-Schroff--Avatar-1--C.glb new file mode 100644 index 0000000..812046f Binary files /dev/null and b/static/assets/people/Luis-Schroff--Avatar-1--C.glb differ diff --git a/static/assets/people/Luis-Schroff--Avatar-2--C.glb b/static/assets/people/Luis-Schroff--Avatar-2--C.glb new file mode 100644 index 0000000..95688b0 Binary files /dev/null and b/static/assets/people/Luis-Schroff--Avatar-2--C.glb differ diff --git a/static/assets/people/Maximilian-Franzke--Avatar-1--C.glb b/static/assets/people/Maximilian-Franzke--Avatar-1--C.glb new file mode 100644 index 0000000..f5b6230 Binary files /dev/null and b/static/assets/people/Maximilian-Franzke--Avatar-1--C.glb differ diff --git a/static/assets/people/Maximilian-Franzke--Avatar-2--C.glb b/static/assets/people/Maximilian-Franzke--Avatar-2--C.glb new file mode 100644 index 0000000..4e8ff78 Binary files /dev/null and b/static/assets/people/Maximilian-Franzke--Avatar-2--C.glb differ diff --git a/static/assets/people/Patrick-Weber--C.jpg b/static/assets/people/Patrick-Weber--C.jpg new file mode 100644 index 0000000..7ae6d43 Binary files /dev/null and b/static/assets/people/Patrick-Weber--C.jpg differ diff --git a/static/assets/people/Tobias-Oberpaul--Avatar-1--C.glb b/static/assets/people/Tobias-Oberpaul--Avatar-1--C.glb new file mode 100644 index 0000000..0da8d29 Binary files /dev/null and b/static/assets/people/Tobias-Oberpaul--Avatar-1--C.glb differ diff --git a/static/assets/people/Tobias-Oberpaul--Avatar-2--C.glb b/static/assets/people/Tobias-Oberpaul--Avatar-2--C.glb new file mode 100644 index 0000000..d931a9a Binary files /dev/null and b/static/assets/people/Tobias-Oberpaul--Avatar-2--C.glb differ diff --git a/static/assets/people/Tobias-Oberpaul--C.jpg b/static/assets/people/Tobias-Oberpaul--C.jpg new file mode 100644 index 0000000..eb7af2f Binary files /dev/null and b/static/assets/people/Tobias-Oberpaul--C.jpg differ diff --git a/static/assets/signatures/Lea-Perchermeier--Signature--C.png b/static/assets/signatures/Lea-Perchermeier--Signature--C.png new file mode 100644 index 0000000..35a0875 Binary files /dev/null and b/static/assets/signatures/Lea-Perchermeier--Signature--C.png differ diff --git a/static/assets/signatures/Luis-Schroff--Signature--C.png b/static/assets/signatures/Luis-Schroff--Signature--C.png new file mode 100644 index 0000000..c6fa6ee Binary files /dev/null and b/static/assets/signatures/Luis-Schroff--Signature--C.png differ diff --git a/static/assets/signatures/Maximilian-Franzke--Signature--C.png b/static/assets/signatures/Maximilian-Franzke--Signature--C.png new file mode 100644 index 0000000..2cbb0bc Binary files /dev/null and b/static/assets/signatures/Maximilian-Franzke--Signature--C.png differ diff --git a/static/assets/signatures/Tobias-Oberpaul--Signature--C.png b/static/assets/signatures/Tobias-Oberpaul--Signature--C.png new file mode 100644 index 0000000..55bb380 Binary files /dev/null and b/static/assets/signatures/Tobias-Oberpaul--Signature--C.png differ diff --git a/template/components/Avatar/Avatar.astro b/template/components/Avatar/Avatar.astro new file mode 100644 index 0000000..a180b05 --- /dev/null +++ b/template/components/Avatar/Avatar.astro @@ -0,0 +1,96 @@ +--- +import { DBCard, DBStack } from '@db-ux/react-core-components'; +import './Avatar.css'; + +export interface Props { + src: string; + alt?: string; + ariaLabel?: string; + name?: string; + position?: string; + hoverSrc?: string; // alternative animation/model to use on hover + cameraTarget?: string; // e.g. "0m 1.4m 0m" + cameraOrbit?: string; // e.g. "-30deg 90deg 3m" + hoverCameraTarget?: string; // separate target for hover variant + hoverCameraOrbit?: string; // separate orbit for hover variant +} + +const { + src, + alt = 'Avatar', + ariaLabel = 'Avatar viewer', + name = 'Name', + position = 'Position', + hoverSrc, + cameraTarget = '0m 1.4m 0m', + cameraOrbit = '-30deg 85deg 3m', + hoverCameraTarget = '0m 1m 0m', + hoverCameraOrbit = '0deg 90deg 15m', +} = Astro.props as Props; +--- + + + +
+ + { + hoverSrc && ( + + ) + } +
+
+
+
{name}
+

{position}

+
+
+ + diff --git a/template/components/Avatar/Avatar.css b/template/components/Avatar/Avatar.css new file mode 100644 index 0000000..149dda9 --- /dev/null +++ b/template/components/Avatar/Avatar.css @@ -0,0 +1,61 @@ +.avatar-meta { + display: flex; + flex-direction: column; +} + +/* Heading inside avatar meta */ +.avatar-meta > h6 { + margin: 0; + font: var(--db-type-headline-3xs); + text-align: center; +} + +/* Paragraph inside avatar meta */ +.avatar-meta > p { + margin: 0; + text-align: center; + color: var(--db-adaptive-on-bg-basic-emphasis-70-default); + font: var(--db-type-body-xs); + white-space: pre-line; +} + +/* Viewer layering for hover swap */ +.avatar-viewer { + position: relative; + width: 100%; + height: 240px; +} +.avatar-viewer model-viewer { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} + +@media (max-width: 767px) { + .avatar-viewer { + height: 160px; /* Mobile reduced height */ + } +} + +.viewer-base { + opacity: 1; + transition: opacity 10ms ease; +} + +.viewer-hover { + opacity: 0; + transition: opacity 10ms ease; +} + +.avatar-viewer:hover .viewer-base { + opacity: 0; +} + +.avatar-viewer:hover .viewer-hover { + opacity: 1; +} + +model-viewer::part(default-progress-bar) { + display: none; +} \ No newline at end of file diff --git a/template/components/CTA/CTA.astro b/template/components/CTA/CTA.astro new file mode 100644 index 0000000..da8b0ac --- /dev/null +++ b/template/components/CTA/CTA.astro @@ -0,0 +1,43 @@ +--- +import './CTA.css'; +import { DBButton, DBCard } from '@db-ux/react-core-components'; + +interface Action { + label: string; + href: string; + variant?: 'brand' | 'outlined' | 'filled' | 'danger'; +} + +interface Props { + title?: string; + text?: string; + primaryAction: Action; + secondaryAction?: Action; + align?: 'center' | 'start' | 'end'; +} + +const { title, text, primaryAction, secondaryAction, align = 'center' } = Astro.props as Props; +--- + +{ + primaryAction && ( + +
+ {title &&

{title}

} + {text &&

{text}

} + +
+
+ ) +} diff --git a/template/components/CTA/CTA.css b/template/components/CTA/CTA.css new file mode 100644 index 0000000..1df6975 --- /dev/null +++ b/template/components/CTA/CTA.css @@ -0,0 +1,62 @@ +.cta { + background: var(--db-brand-origin-default); + color: var(--db-brand-on-origin-default); + border-radius: var(--db-border-radius-sm); +} +.cta__content { + display: flex; + flex-direction: column; + gap: var(--db-spacing-fixed-lg); + padding: var(--db-spacing-fixed-xl) 0; +} + +.cta__content[data-align="start"] { align-items: flex-start; text-align: left; } +.cta__content[data-align="end"] { align-items: flex-end; text-align: right; } + +.cta__title { max-width: 480px; text-align: center; margin: 0 auto; } +.cta__text { max-width: 60ch; text-align: center; margin: 0 auto; } + +.cta__actions { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: var(--db-spacing-fixed-sm); +} + +.cta__action { text-decoration: none; } + +/* Inverted primary action button (white with brand text) */ +.cta :is(.db-button)[data-variant="brand"], +.cta :is(.db-button--brand) { + background: var(--db-brand-on-origin-default); + color: var(--db-brand-origin-default); + border: var(--db-border-width-3xs) solid var(--db-brand-origin-default); +} +.cta :is(.db-button)[data-variant="outlined"], +.cta :is(.db-button--outlined) { + background: transparent; + color: var(--db-brand-on-origin-default); + border: var(--db-border-width-3xs) solid var(--db-brand-on-origin-default); +} + +.cta :is(.db-button)[data-variant="brand"]:hover, +.cta :is(.db-button--brand):hover { + opacity: 0.88; + background: var(--db-brand-on-origin-default); + color: var(--db-brand-origin-default); + border: var(--db-border-width-3xs) solid var(--db-brand-origin-default); +} + +.cta :is(.db-button)[data-variant="outlined"]:hover, +.cta :is(.db-button--outlined):hover { + background: rgba(255,255,255,0.24); + color: var(--db-brand-on-origin-default); + border: var(--db-border-width-3xs) solid var(--db-brand-on-origin-default); +} + +@media (max-width: 767px) { + .cta { + padding: var(--db-spacing-fixed-xl) var(--db-spacing-fixed-lg); + gap: var(--db-spacing-fixed-lg); + } +} diff --git a/template/components/Carousel/Carousel.astro b/template/components/Carousel/Carousel.astro new file mode 100644 index 0000000..f71c772 --- /dev/null +++ b/template/components/Carousel/Carousel.astro @@ -0,0 +1,16 @@ +--- +interface Props { + ariaLabel?: string; +} +const { ariaLabel } = Astro.props as Props; +--- + + + + diff --git a/template/components/Carousel/Carousel.css b/template/components/Carousel/Carousel.css new file mode 100644 index 0000000..06bbad3 --- /dev/null +++ b/template/components/Carousel/Carousel.css @@ -0,0 +1,38 @@ +/* Local styles for Carousel (horizontal scroll wrapper) */ +.carousel { + width: 100%; + display: flex; + gap: var(--db-spacing-fixed-lg); + overflow-x: auto; + overflow-y: hidden; + -webkit-overflow-scrolling: touch; + scroll-snap-type: x mandatory; + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE/Edge legacy */ + padding: 0 var(--db-spacing-fixed-xl); +} +.carousel > * { + flex: 0 0 auto; + scroll-snap-align: center; +} +.carousel > .db-card { + width: 80%; +} +.carousel .text-image__image img { + height: 100%; + object-fit: cover; +} +/* WebKit */ +.carousel::-webkit-scrollbar { + width: 0; + height: 0; +} +.fadeout-horizontal { + mask-image: linear-gradient( + to right, + transparent, + black var(--db-spacing-fixed-xl), + black calc(100% - var(--db-spacing-fixed-xl)), + transparent + ); +} \ No newline at end of file diff --git a/template/components/Carousel/Carousel.tsx b/template/components/Carousel/Carousel.tsx new file mode 100644 index 0000000..2c41d02 --- /dev/null +++ b/template/components/Carousel/Carousel.tsx @@ -0,0 +1,39 @@ +import React, { useMemo, useState } from 'react'; +import { DBButton, DBStack } from '@db-ux/react-core-components'; + +type CarouselProps = { + children: React.ReactNode[] | React.ReactNode; + ariaLabel?: string; +}; + +export const Carousel: React.FC = ({ children, ariaLabel }) => { + const items = useMemo(() => (Array.isArray(children) ? children : [children]), [children]); + const [index, setIndex] = useState(0); + + const count = items.length; + const goPrev = () => setIndex((i) => (i - 1 + count) % count); + const goNext = () => setIndex((i) => (i + 1) % count); + + return ( +
+ {/* viewport */} +
+ {items.map((item, i) => ( +
+ {item as React.ReactNode} +
+ ))} +
+ {/* controls */} + + + + +
+ ); +}; diff --git a/template/components/ContactUsSection/ContactUsSection.astro b/template/components/ContactUsSection/ContactUsSection.astro new file mode 100644 index 0000000..dc36820 --- /dev/null +++ b/template/components/ContactUsSection/ContactUsSection.astro @@ -0,0 +1,15 @@ +--- +import { DBSection } from '@db-ux/react-core-components'; +import { CTA } from '@components'; +--- + + + + diff --git a/template/components/DisabledWrapper/DisabledWrapper.astro b/template/components/DisabledWrapper/DisabledWrapper.astro new file mode 100644 index 0000000..33c2344 --- /dev/null +++ b/template/components/DisabledWrapper/DisabledWrapper.astro @@ -0,0 +1,33 @@ +--- +import './DisabledWrapper.css'; +import { DBBadge } from '@db-ux/react-core-components'; + +interface Props { + label: string; + disabled?: boolean; + emphasis?: 'strong' | 'weak' | 'default'; + size?: 'small' | 'medium'; + ariaLabel?: string; +} + +const { label, disabled = true, emphasis, size = 'medium', ariaLabel } = Astro.props as Props; +--- + +
+
+ +
+ { + disabled && ( +
+ + {label} + +
+ ) + } +
diff --git a/template/components/DisabledWrapper/DisabledWrapper.css b/template/components/DisabledWrapper/DisabledWrapper.css new file mode 100644 index 0000000..3c3dc73 --- /dev/null +++ b/template/components/DisabledWrapper/DisabledWrapper.css @@ -0,0 +1,33 @@ +/* DisabledWrapper styles - follows DB UX design tokens */ +.disabled-wrapper { + position: relative; + display: block; +} + +/* Content wrapper: styles applied via data-disabled selector below */ +.disabled-wrapper[data-disabled="true"] .disabled-wrapper__content { + opacity: 0.4; + pointer-events: none; +} + +.disabled-wrapper__overlay { + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; /* overlay should not block scroll; badge itself remains visible */ + /* spacing (none); container keeps card layout underneath */ +} + +/* Make sure the badge remains readable above blurred/dimmed content */ +.disabled-wrapper__overlay .db-badge { + z-index: 1; +} + +/* Optional: ensure a minimum tap target size when used on small cards */ +@media (hover: none) and (pointer: coarse) { + .disabled-wrapper__overlay .db-badge { + min-height: var(--db-sizing-sm); + } +} diff --git a/template/components/ImageToggle/ImageToggle.astro b/template/components/ImageToggle/ImageToggle.astro new file mode 100644 index 0000000..2adc458 --- /dev/null +++ b/template/components/ImageToggle/ImageToggle.astro @@ -0,0 +1,85 @@ +--- +import { DBButton } from '@db-ux/react-core-components'; + +const items = Array.isArray(Astro.props.items) ? Astro.props.items : []; +const initialId = Astro.props.initialId; +const initialItem = (initialId && items.find((i) => i.id === initialId)) ?? items[0] ?? null; +--- + +{ + items.length === 0 || !initialItem ? null : ( +
+ {items.map((item) => { + return ( + + {item.label} + + ); + })} + + {initialItem.alt +
+ ) +} + + diff --git a/template/components/InteractiveDemo/InteractiveDemo.astro b/template/components/InteractiveDemo/InteractiveDemo.astro new file mode 100644 index 0000000..fdce461 --- /dev/null +++ b/template/components/InteractiveDemo/InteractiveDemo.astro @@ -0,0 +1,206 @@ +--- +import { DBButton, DBStack, DBCard } from '@db-ux/react-core-components'; +import './InteractiveDemo.css'; + +const items = Array.isArray(Astro.props.items) ? Astro.props.items : []; +const initialId = Astro.props.initialId; +const initialItem = (initialId && items.find((i) => i.id === initialId)) ?? items[0] ?? null; +--- + +{ + items.length === 0 || !initialItem ? null : ( +
+ +
+ + + {items.map((item) => ( + + {item.label} + + ))} + + + + +
+ + {initialItem.alt + +
+
+ ) +} + + diff --git a/template/components/InteractiveDemo/InteractiveDemo.css b/template/components/InteractiveDemo/InteractiveDemo.css new file mode 100644 index 0000000..184047e --- /dev/null +++ b/template/components/InteractiveDemo/InteractiveDemo.css @@ -0,0 +1,26 @@ +/* Styles specific to InteractiveDemo component */ + +/* Active state button styling: highlights the currently selected brand/theme */ +[data-image-toggle-root] [data-image-toggle-button][data-active] { + background: var(--db-adaptive-origin-default); + color: var(--db-adaptive-on-origin-default); +} + +[data-image-toggle-root] [data-image-toggle-button][data-active]:hover { + opacity: 0.88; + background: var(--db-adaptive-origin-default); + color: var(--db-adaptive-on-origin-default); +} + +/* Optional: focus ring for accessibility (commented out) +[data-image-toggle-root] [data-image-toggle-button][data-active]:focus-visible { + outline: var(--db-border-width-2xs) solid var(--db-brand-origin-default); + outline-offset: var(--db-border-width-3xs); +} +*/ +/* Responsive Stack */ +@media (max-width: 767px) { +.db-stack { + overflow: auto; +} +} \ No newline at end of file diff --git a/template/components/PageHero/PageHero.astro b/template/components/PageHero/PageHero.astro new file mode 100644 index 0000000..188efc6 --- /dev/null +++ b/template/components/PageHero/PageHero.astro @@ -0,0 +1,67 @@ +--- +import './PageHero.css'; + +interface Props { + title?: string; + headline?: string; + description?: string; + imageSrc?: string; + imageAlt?: string; + align?: 'start' | 'center' | 'end'; + layout?: 'stack' | 'split'; + imageSide?: 'left' | 'right'; + headlineLevel?: 1 | 2 | 3 | 4 | 5 | 6; +} + +type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6; +type HeadingTagName = `h${HeadingLevel}`; + +const { + title, + headline, + description, + imageSrc, + imageAlt, + align = 'center', + layout = 'stack', + imageSide = 'right', + headlineLevel = 2, +} = Astro.props as Props; + +const safeHeadlineLevel = Math.min(Math.max(headlineLevel, 1), 6) as HeadingLevel; +const HeadingTag = `h${safeHeadlineLevel}` as HeadingTagName; +--- + +{ + (title || headline || description || imageSrc) && ( +
+ {layout === 'split' && imageSrc && imageSide === 'left' && ( +
+ {imageAlt +
+ )} +
+ {title &&

{title}

} + {headline && {headline}} +
+ {layout === 'split' && imageSrc && imageSide === 'right' && ( +
+ {imageAlt +
+ )} + {layout === 'stack' && imageSrc && ( +
+ {imageAlt +
+ )} +
+ ) +} diff --git a/template/components/PageHero/PageHero.css b/template/components/PageHero/PageHero.css new file mode 100644 index 0000000..677eef8 --- /dev/null +++ b/template/components/PageHero/PageHero.css @@ -0,0 +1,138 @@ +/* PageHero Component Styles */ + +.page-hero { + display: flex; + flex-direction: column; + align-items: center; /* Default center */ + text-align: center; +} + +/* Split Layout */ +.page-hero[data-layout="split"] { + display: grid; + /* 66/33 Verteilung bei imageSide=right (Content breiter) */ + grid-template-columns: 2fr 1fr; + align-items: center; + gap: var(--db-spacing-fixed-2xl); + text-align: left; /* Content left aligned by default in split */ +} +.page-hero[data-layout="split"] .page-hero__content { + align-items: flex-start; + max-width: 100%; +} +.page-hero[data-layout="split"][data-image-side="left"] { + direction: ltr; +} +.page-hero[data-layout="split"][data-image-side="right"] { + direction: ltr; +} +.page-hero[data-layout="split"][data-image-side="left"] { + grid-template-columns: 1fr 2fr; /* Bild schmal (33%), Content breit (66%) */ +} + +.page-hero__content { + display: flex; + gap: var(--db-spacing-fixed-lg); + flex-direction: column; + align-items: center; + max-width: 720px; + width: 100%; +} + +.page-hero__title { + margin: 0; +} + +.page-hero__headline { + margin: 0; +} + +.page-hero__description { + margin: 0; + max-width: 480px; + opacity: 0.75; + font: var(--db-type-body-md); +} + +.page-hero__underline { + display: block; + width: 4rem; /* kann aus Token ersetzt werden falls vorhanden */ + height: .5rem; + border-radius: var(--db-border-radius-xs); + background: var(--db-brand-origin-default); +} + +.page-hero__media { + margin-top: var(--db-spacing-fixed-2xl); + display: flex; + justify-content: center; + width: 100%; +} +.page-hero[data-layout="split"] .page-hero__media { + margin-top: 0; + justify-content: center; /* default if no side specified */ +} +/* Desktop: Bild rechts ausrichten wenn imageSide=right */ +.page-hero[data-layout="split"][data-image-side="right"] .page-hero__media { justify-content: flex-end; } +/* Desktop: Bild links ausrichten wenn imageSide=left */ +.page-hero[data-layout="split"][data-image-side="left"] .page-hero__media { justify-content: flex-start; } +.page-hero__media img { + display: block; + max-height: 320px; + width: auto; + height: auto; +} + +/* Zentrierter Variant (z.B. Landing Pages) */ +/* Alignment Variants */ +.page-hero[data-align="start"] { + text-align: left; + align-items: flex-start; +} +.page-hero[data-align="start"] .page-hero__content { align-items: flex-start; } +.page-hero[data-align="start"] .page-hero__media { justify-content: flex-start; } + +.page-hero[data-align="end"] { + text-align: right; + align-items: flex-end; +} +.page-hero[data-align="end"] .page-hero__content { align-items: flex-end; } +.page-hero[data-align="end"] .page-hero__media { justify-content: flex-end; } + +/* Mobile Anpassungen */ +@media (max-width: 767px) { + .page-hero { + gap: var(--db-spacing-fixed-md); + margin-block-end: var(--db-spacing-fixed-xl); + } + .page-hero[data-layout="split"] { + display: flex; + flex-direction: column; + text-align: center; + } + .page-hero[data-layout="split"] .page-hero__content { + align-items: center; + } + .page-hero[data-layout="split"] .page-hero__media { + margin-top: var(--db-spacing-fixed-lg); + justify-content: center; /* Mobile immer zentriert */ + } + /* Mobile: Immer Medienbereich zentrieren, auch bei stack + align=start/end */ + .page-hero .page-hero__media { justify-content: center !important; } + .page-hero[data-align="start"] .page-hero__media, + .page-hero[data-align="end"] .page-hero__media { justify-content: center !important; } + + .page-hero__headline { + line-height: 1.2; + } + + .page-hero__underline { + margin-top: var(--db-spacing-fixed-md); + width: 3.5rem; + height: .5rem; + } + + .page-hero__media { + margin-top: var(--db-spacing-fixed-lg); + } +} diff --git a/template/components/SectionTitle/SectionTitle.astro b/template/components/SectionTitle/SectionTitle.astro new file mode 100644 index 0000000..5135017 --- /dev/null +++ b/template/components/SectionTitle/SectionTitle.astro @@ -0,0 +1,33 @@ +--- +import './SectionTitle.css'; + +interface Props { + title: string; + description?: string; + layout?: 'split' | 'stack'; +} + +const { title, description, layout = 'split' } = Astro.props as Props; +--- + +
+ { + layout === 'split' ? ( + <> +
+

{title}

+
+ {description && ( +
+

{description}

+
+ )} + + ) : ( + <> +

{title}

+ {description &&

{description}

} + + ) + } +
diff --git a/template/components/SectionTitle/SectionTitle.css b/template/components/SectionTitle/SectionTitle.css new file mode 100644 index 0000000..e960358 --- /dev/null +++ b/template/components/SectionTitle/SectionTitle.css @@ -0,0 +1,42 @@ +/* SectionTitle Styles */ +.section-title { + display: flex; + flex-direction: column; + gap: var(--db-spacing-fixed-lg); + align-items: flex-start; + margin-bottom: var(--db-spacing-responsive-sm); +} + +/* Split: Headline 33%, Description 66% */ +.section-title[data-layout="split"] { + display: grid; + grid-template-columns: 1fr 2fr; /* 33/66 */ + align-items: center; + gap: var(--db-spacing-fixed-lg); +} +.section-title[data-layout="split"] .section-title__col--headline { align-self: start; } +.section-title[data-layout="split"] .section-title__col--description { align-self: center; } + +.section-title__headline { + margin: 0; + line-height: 1.2; +} + +.section-title__description { + margin: 0; + max-width: 65ch; + opacity: 0.75; + font: var(--db-type-body-md); +} + +/* Alignment variants */ + +/* Mobile: Stack */ +@media (max-width: 767px) { + .section-title[data-layout="split"] { + display: flex; + flex-direction: column; + gap: var(--db-spacing-fixed-md); + } + .section-title[data-layout="split"] .section-title__col--description { align-self: start; } +} diff --git a/template/components/TextImage/TextImage.astro b/template/components/TextImage/TextImage.astro new file mode 100644 index 0000000..e201535 --- /dev/null +++ b/template/components/TextImage/TextImage.astro @@ -0,0 +1,131 @@ +--- +import './TextImage.css'; +import { DBTag } from '@db-ux/react-core-components'; + +interface Props { + title?: string; + imageSrc: string; + imageAlt: string; + imageSrcDark?: string; + reversed?: boolean; + contentAlign?: 'start' | 'center' | 'end'; + headlineLevel?: 1 | 2 | 3 | 4 | 5 | 6; + imageWidth?: '50' | '33' | '66'; + layout?: 'horizontal' | 'vertical'; + imagePosition?: 'top' | 'bottom' | 'left' | 'right'; + mask?: + | 'fade-right' + | 'fade-left' + | 'fade-top' + | 'fade-bottom' + | 'fade-bottom-right' + | 'fade-bottom-left' + | 'fade-top-right' + | 'fade-top-left'; + rounded?: boolean; + textGap?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl'; + tag?: { label: string; emphasis?: 'strong' | 'weak' | 'default' }; +} + +const { + title, + imageSrc, + imageAlt, + imageSrcDark, + imagePosition = 'right', + contentAlign = 'center', + imageWidth = '66', + mask, + rounded = false, + textGap = 'sm', + headlineLevel = 4, + tag, +} = Astro.props as Props; + +// Headline stets h6 – Typografie kommt aus globalen Styles +--- + +
+
+ { + tag && ( +
+ + {tag.label} + +
+ ) + } + { + title && + (headlineLevel === 1 ? ( +

{title}

+ ) : headlineLevel === 2 ? ( +

{title}

+ ) : headlineLevel === 3 ? ( +

{title}

+ ) : headlineLevel === 4 ? ( +

{title}

+ ) : headlineLevel === 5 ? ( +
{title}
+ ) : ( +
{title}
+ )) + } +
+ +
+
+
+ {imageAlt} +
+
+ diff --git a/template/components/TextImage/TextImage.css b/template/components/TextImage/TextImage.css new file mode 100644 index 0000000..511e1e8 --- /dev/null +++ b/template/components/TextImage/TextImage.css @@ -0,0 +1,175 @@ +/* TextImage Component Styles (Figma-konform) */ + +.text-image { + display: flex; + flex-direction: row; + gap: var(--db-spacing-fixed-3xl); + height: 100%; +} + +/* Image Position */ +.text-image[data-image-position="top"], .text-image[data-image-position="bottom"] { + flex-direction: column; + gap: var(--db-spacing-fixed-xl); +} + +.text-image[data-image-position="top"] .text-image__image, .text-image[data-image-position="left"] .text-image__image { order: 1; width: 100%; } +.text-image[data-image-position="top"] .text-image__content , .text-image[data-image-position="left"] .text-image__content { order: 2; } + +.text-image[data-image-position="bottom"] .text-image__image, .text-image[data-image-position="right"] .text-image__image { order: 2; width: 100%; } +.text-image[data-image-position="bottom"] .text-image__content , .text-image[data-image-position="right"] .text-image__content { order: 1; } + +/* Content Column */ +.text-image__content { + display: flex; + flex-direction: column; + justify-content: center; + gap: var(--db-spacing-fixed-sm); /* 12px spacing zwischen Title und Body */ + flex: 1 0 0; /* Default 50% in flex context */ + min-width: 0; /* verhindert overflow issues */ +} + +/* Body push bottom variant (slot/text wird nach unten gedrückt) */ +/* Text Gap Variants */ +.text-image[data-text-gap="sm"] .text-image__content { gap: var(--db-spacing-fixed-sm); } +.text-image[data-text-gap="md"] .text-image__content { gap: var(--db-spacing-fixed-md); } +.text-image[data-text-gap="lg"] .text-image__content { gap: var(--db-spacing-fixed-lg); } +.text-image[data-text-gap="xl"] .text-image__content { gap: var(--db-spacing-fixed-xl); } +.text-image[data-text-gap="2xl"] .text-image__content { gap: var(--db-spacing-fixed-2xl); } +.text-image[data-text-gap="3xl"] .text-image__content { gap: var(--db-spacing-fixed-3xl); } + + +/* Paragraph Spacing nur innerhalb der Komponente */ +.text-image__text > p { + margin: 0; + max-width: 480px; +} + +.text-image__text > p + p { + margin-top: var(--db-spacing-fixed-md); +} + +/* Remove default first/last paragraph margins to avoid extra top/bottom spacing */ +.text-image__text > p:first-child { margin-top: 0; } +.text-image__text > p:last-child { margin-bottom: 0; } + +/* Bildcontainer */ +.text-image__image { + flex: 1 0 0; /* Default 50% */ + position: relative; + min-width: 0; +} + +.text-image__image img { + width: 100%; + height: auto; + display: block; +} + +/* Rounded image opt-in */ +.text-image__image img[data-rounded] { + border-radius: var(--db-border-radius-xs); + overflow: hidden; +} + +/* ============================= */ +/* Image Mask Variants */ +/* ============================= */ +/* Basis Farb-Stopps über CSS Variablen für Wiederverwendbarkeit */ +/* Sichtbarer Bereich -> voll opaque; Ausblendung -> transparent */ +:root { + --ti-mask-visible: rgba(0,0,0,1); + --ti-mask-invisible: rgba(0,0,0,0); +} + +/* Single direction fades */ +img[data-mask="fade-right"] { + -webkit-mask-image: linear-gradient(to right, var(--ti-mask-visible) 20%, var(--ti-mask-invisible) 100%); + mask-image: linear-gradient(to right, var(--ti-mask-visible) 20%, var(--ti-mask-invisible) 100%); +} +img[data-mask="fade-left"] { + -webkit-mask-image: linear-gradient(to left, var(--ti-mask-visible) 20%, var(--ti-mask-invisible) 100%); + mask-image: linear-gradient(to left, var(--ti-mask-visible) 20%, var(--ti-mask-invisible) 100%); +} +img[data-mask="fade-top"] { + -webkit-mask-image: linear-gradient(to top, var(--ti-mask-visible) 20%, var(--ti-mask-invisible) 100%); + mask-image: linear-gradient(to top, var(--ti-mask-visible) 20%, var(--ti-mask-invisible) 100%); +} +img[data-mask="fade-bottom"] { + -webkit-mask-image: linear-gradient(to bottom, var(--ti-mask-visible) 50%, var(--ti-mask-invisible) 100%); + mask-image: linear-gradient(to bottom, var(--ti-mask-visible) 50%, var(--ti-mask-invisible) 100%); +} + +/* Combined corner fades (two gradients) */ +/* Bottom-Right */ +img[data-mask="fade-bottom-right"] { + --_ti-mask-bottom: linear-gradient(to bottom, var(--ti-mask-visible) 50%, var(--ti-mask-invisible) 100%); + --_ti-mask-right: linear-gradient(to right, var(--ti-mask-visible) 20%, var(--ti-mask-invisible) 100%); + -webkit-mask-image: var(--_ti-mask-bottom), var(--_ti-mask-right); + mask-image: var(--_ti-mask-bottom), var(--_ti-mask-right); + -webkit-mask-composite: source-in; + mask-composite: intersect; +} +/* Bottom-Left */ +img[data-mask="fade-bottom-left"] { + --_ti-mask-bottom: linear-gradient(to bottom, var(--ti-mask-visible) 50%, var(--ti-mask-invisible) 100%); + --_ti-mask-left: linear-gradient(to left, var(--ti-mask-visible) 20%, var(--ti-mask-invisible) 100%); + -webkit-mask-image: var(--_ti-mask-bottom), var(--_ti-mask-left); + mask-image: var(--_ti-mask-bottom), var(--_ti-mask-left); + -webkit-mask-composite: source-in; + mask-composite: intersect; +} +/* Top-Right */ +img[data-mask="fade-top-right"] { + --_ti-mask-top: linear-gradient(to top, var(--ti-mask-visible) 50%, var(--ti-mask-invisible) 100%); + --_ti-mask-right: linear-gradient(to right, var(--ti-mask-visible) 20%, var(--ti-mask-invisible) 100%); + -webkit-mask-image: var(--_ti-mask-top), var(--_ti-mask-right); + mask-image: var(--_ti-mask-top), var(--_ti-mask-right); + -webkit-mask-composite: source-in; + mask-composite: intersect; +} +/* Top-Left */ +img[data-mask="fade-top-left"] { + --_ti-mask-top: linear-gradient(to top, var(--ti-mask-visible) 50%, var(--ti-mask-invisible) 100%); + --_ti-mask-left: linear-gradient(to left, var(--ti-mask-visible) 20%, var(--ti-mask-invisible) 100%); + -webkit-mask-image: var(--_ti-mask-top), var(--_ti-mask-left); + mask-image: var(--_ti-mask-top), var(--_ti-mask-left); + -webkit-mask-composite: source-in; + mask-composite: intersect; +} + +/* Ensure images with masks don't overflow their container visually */ +img[data-mask] { + overflow: hidden; +} + +/* Layout Ratio Variants */ +/* 66/33: Text breiter */ +.text-image[data-image-width="33"] .text-image__content { flex: 2 1 0; } +.text-image[data-image-width="33"] .text-image__image { flex: 1 1 0; } + +.text-image[data-image-width="66"] .text-image__content { flex: 1 1 0; } +.text-image[data-image-width="66"] .text-image__image { flex: 2 1 0; } + +/* Align Varianten (optional) */ +.text-image[data-content-align="start"] .text-image__content { justify-content: start; } +.text-image[data-content-align="center"] .text-image__content { justify-content: center; } +.text-image[data-content-align="end"] .text-image__content { justify-content: end; } + +/* Typographie entfernt – globale Styles sollen greifen */ +.text-image__title { margin: 0; } + +/* Responsive Stack */ +@media (max-width: 767px) { + .text-image { + flex-direction: column; + gap: var(--db-spacing-fixed-lg); + } + + .text-image[data-image-position="left"] .text-image__image, .text-image[data-image-position="right"] .text-image__image { order: 2 !important; flex: 1 1 0 !important; } + .text-image[data-image-position="left"] .text-image__content, .text-image[data-image-position="right"] .text-image__content { order: 1 !important; flex: 2 1 0 !important; } + + /* Mobile: textGap stets sm, egal welche Variante gewählt wurde */ + .text-image .text-image__content { gap: var(--db-spacing-fixed-sm) !important; } + +} diff --git a/template/components/color-mode-switch/ColorModeSwitch.tsx b/template/components/color-mode-switch/ColorModeSwitch.tsx index e80d10f..f9a2345 100644 --- a/template/components/color-mode-switch/ColorModeSwitch.tsx +++ b/template/components/color-mode-switch/ColorModeSwitch.tsx @@ -1,24 +1,23 @@ -import { DBSwitch, DBTooltip } from "@db-ux/react-core-components"; -import { useColorMode } from "@template/context/color-mode-context.tsx"; +import { DBSwitch, DBTooltip } from '@db-ux/react-core-components'; +import { useColorMode } from '@template/context/color-mode-context.tsx'; const ColorModeSwitch = () => { - const { colorMode, toggleColorMode } = useColorMode(); - const isDark = colorMode === "dark"; + const { colorMode, toggleColorMode } = useColorMode(); + const isDark = colorMode === 'dark'; - return ( - - - Switch color scheme (light/dark) - - Switch color scheme (light/dark) - - ); + return ( + + Switch color scheme (light/dark) + Switch color scheme (light/dark) + + ); }; -export default ColorModeSwitch; \ No newline at end of file +export default ColorModeSwitch; diff --git a/template/components/index.astro b/template/components/index.astro new file mode 100644 index 0000000..9997353 --- /dev/null +++ b/template/components/index.astro @@ -0,0 +1,21 @@ +--- +import TextImage from './TextImage/TextImage.astro'; +import CTA from './CTA/CTA.astro'; +import PageHero from './PageHero/PageHero.astro'; +import SectionTitle from './SectionTitle/SectionTitle.astro'; +import Carousel from './Carousel/Carousel.astro'; +import DisabledWrapper from './DisabledWrapper/DisabledWrapper.astro'; +import InteractiveDemo from './InteractiveDemo/InteractiveDemo.astro'; +import ContactUsSection from './ContactUsSection/ContactUsSection.astro'; + +export { + TextImage, + CTA, + PageHero, + SectionTitle, + DisabledWrapper, + Carousel, + InteractiveDemo, + ContactUsSection, +}; +--- diff --git a/template/components/index.ts b/template/components/index.ts new file mode 100644 index 0000000..7339feb --- /dev/null +++ b/template/components/index.ts @@ -0,0 +1,10 @@ +export { default as TextImage } from './TextImage/TextImage.astro'; +export { default as CTA } from './CTA/CTA.astro'; +export { default as PageHero } from './PageHero/PageHero.astro'; +export { default as SectionTitle } from './SectionTitle/SectionTitle.astro'; +export { default as Carousel } from './Carousel/Carousel.astro'; +export { default as Avatar } from './Avatar/Avatar.astro'; +export { default as ImageToggle } from './ImageToggle/ImageToggle.astro'; +export { default as DisabledWrapper } from './DisabledWrapper/DisabledWrapper.astro'; +export { default as InteractiveDemo } from './InteractiveDemo/InteractiveDemo.astro'; +export { default as ContactUsSection } from './ContactUsSection/ContactUsSection.astro'; diff --git a/template/context/color-mode-context.tsx b/template/context/color-mode-context.tsx index 1a7e929..a8397f4 100644 --- a/template/context/color-mode-context.tsx +++ b/template/context/color-mode-context.tsx @@ -1,66 +1,60 @@ -import { - createContext, - useContext, - useState, - useEffect, - type ReactNode, -} from "react"; +import { createContext, useContext, useState, useEffect, type ReactNode } from 'react'; -type ColorMode = "light" | "dark"; +type ColorMode = 'light' | 'dark'; interface ColorModeContextValue { - colorMode: ColorMode; - setColorMode: (colorMode: ColorMode) => void; - toggleColorMode: () => void; + colorMode: ColorMode; + setColorMode: (colorMode: ColorMode) => void; + toggleColorMode: () => void; } -const STORAGE_KEY = "db-ux-mode"; -const SHELL_SELECTOR = ".db-shell"; +const STORAGE_KEY = 'db-ux-mode'; +const SHELL_SELECTOR = '.db-shell'; const ColorModeContext = createContext(undefined); function getInitialColorMode(): ColorMode { - if (typeof window === "undefined") { - return "light"; - } + if (typeof window === 'undefined') { + return 'light'; + } - const stored = window.localStorage.getItem(STORAGE_KEY); - if (stored === "light" || stored === "dark") { - return stored; - } + const stored = window.localStorage.getItem(STORAGE_KEY); + if (stored === 'light' || stored === 'dark') { + return stored; + } - return "light"; + return 'light'; } export const ColorModeProvider = ({ children }: { children: ReactNode }) => { - const [colorMode, setColorMode] = useState(getInitialColorMode); + const [colorMode, setColorMode] = useState(getInitialColorMode); - useEffect(() => { - window.localStorage.setItem("db-ux-mode", colorMode); + useEffect(() => { + window.localStorage.setItem('db-ux-mode', colorMode); - const shell = document.querySelector(SHELL_SELECTOR); - if (shell instanceof HTMLElement) { - shell.setAttribute("data-mode", colorMode); - } - }, [colorMode]); + const shell = document.querySelector(SHELL_SELECTOR); + if (shell instanceof HTMLElement) { + shell.setAttribute('data-mode', colorMode); + } + }, [colorMode]); - const setMode = (next: ColorMode) => { - setColorMode(next); - }; + const setMode = (next: ColorMode) => { + setColorMode(next); + }; - const toggleColorMode = () => { - setColorMode((prev) => (prev === "light" ? "dark" : "light")); - }; + const toggleColorMode = () => { + setColorMode((prev) => (prev === 'light' ? 'dark' : 'light')); + }; - const value: ColorModeContextValue = { colorMode, setColorMode: setMode, toggleColorMode }; + const value: ColorModeContextValue = { colorMode, setColorMode: setMode, toggleColorMode }; - return {children}; + return {children}; }; export const useColorMode = (): ColorModeContextValue => { - const ctx = useContext(ColorModeContext); - if (!ctx) { - throw new Error("useColorMode must be used inside a ColorModeProvider"); - } - return ctx; -}; \ No newline at end of file + const ctx = useContext(ColorModeContext); + if (!ctx) { + throw new Error('useColorMode must be used inside a ColorModeProvider'); + } + return ctx; +}; diff --git a/template/hooks/debounce.tsx b/template/hooks/debounce.tsx index a1d389b..2c870f6 100644 --- a/template/hooks/debounce.tsx +++ b/template/hooks/debounce.tsx @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect } from 'react'; /** * Debounce hook for inputs to prevent too many requests against a database, server etc. diff --git a/template/integrations/sitemap.ts b/template/integrations/sitemap.ts index f5d25a1..7e2ce91 100644 --- a/template/integrations/sitemap.ts +++ b/template/integrations/sitemap.ts @@ -1,4 +1,4 @@ -import { appConfig } from "../../app.config"; +import { appConfig } from '../../app.config'; /** * Filters out pages that are blacklisted from the sitemap. @@ -9,15 +9,12 @@ export function filterSitemapBlacklist(page: string): boolean { for (const blacklistedPage of appConfig.sitemapBlacklist) { let fullBlacklistedPage = `${appConfig.hostname}${appConfig.basePath}${blacklistedPage}`; // Make sure that trailing slashes match - if (page.endsWith("/") && !fullBlacklistedPage.endsWith("/")) { - fullBlacklistedPage = fullBlacklistedPage + "/"; - } else if (fullBlacklistedPage.endsWith("/") && !page.endsWith("/")) { - page = page + "/"; + if (page.endsWith('/') && !fullBlacklistedPage.endsWith('/')) { + fullBlacklistedPage = fullBlacklistedPage + '/'; + } else if (fullBlacklistedPage.endsWith('/') && !page.endsWith('/')) { + page = page + '/'; } if (fullBlacklistedPage === page) { - console.log( - `${page} is blacklisted and will not be included into the sitemap.`, - ); return false; } } diff --git a/template/layouts/default/DefaultLayout.astro b/template/layouts/default/DefaultLayout.astro index 8fa8a54..10bbc8f 100644 --- a/template/layouts/default/DefaultLayout.astro +++ b/template/layouts/default/DefaultLayout.astro @@ -1,10 +1,10 @@ --- -import type { MarkdownHeading } from "astro"; -import "../../styles/global.css"; -import HtmlHead from "./html-head"; -import MainContent from "./main-content"; -import { appConfig } from "@root/app.config.ts"; -import { Shell } from "./shell"; +import type { MarkdownHeading } from 'astro'; +import '../../styles/global.css'; +import HtmlHead from './html-head'; +import MainContent from './main-content'; +import { appConfig } from '@root/app.config.ts'; +import { Shell } from './shell'; const { headings, frontmatter } = Astro.props as { headings: MarkdownHeading[]; @@ -13,7 +13,7 @@ const { headings, frontmatter } = Astro.props as { --- - + diff --git a/template/layouts/default/html-head/HtmlHead.astro b/template/layouts/default/html-head/HtmlHead.astro index f846fec..2b0f37c 100644 --- a/template/layouts/default/html-head/HtmlHead.astro +++ b/template/layouts/default/html-head/HtmlHead.astro @@ -1,6 +1,6 @@ --- -import { appConfig } from "@root/app.config"; -import { ClientRouter } from "astro:transitions"; +import { appConfig } from '@root/app.config'; +import { ClientRouter } from 'astro:transitions'; const { title } = Astro.props as { title: string; @@ -14,4 +14,5 @@ const { title } = Astro.props as { {title} + diff --git a/template/layouts/default/main-content/MainContent.astro b/template/layouts/default/main-content/MainContent.astro index ff3e959..1af2e29 100644 --- a/template/layouts/default/main-content/MainContent.astro +++ b/template/layouts/default/main-content/MainContent.astro @@ -2,6 +2,8 @@ import type { MarkdownHeading } from "astro"; import { TableOfContents } from "./toc"; import { FooterNav } from "./footer-nav"; +import { DBSection } from '@db-ux/react-core-components'; +import { PageHero } from '@components'; const { headings, frontmatter } = Astro.props as { headings: MarkdownHeading[]; @@ -14,14 +16,18 @@ const toc = (headings?.length ?? 0) > 0 && frontmatter.toc === true; {toc && }
- { - frontmatter.title && ( - <> -

{frontmatter.title}

-
diff --git a/template/layouts/default/main-content/footer-nav/FooterNav.tsx b/template/layouts/default/main-content/footer-nav/FooterNav.tsx index bd3c3de..7354b3e 100644 --- a/template/layouts/default/main-content/footer-nav/FooterNav.tsx +++ b/template/layouts/default/main-content/footer-nav/FooterNav.tsx @@ -1,8 +1,8 @@ -import { DBButton, DBIcon } from "@db-ux/react-core-components"; -import { appConfig } from "@root/app.config"; -import { getCurrentPathname } from "@root/template/utils/app.utils"; -import { getNavigationItemParent } from "@root/template/utils/navigation.utils"; -import type { ReactElement } from "react"; +import { DBButton, DBIcon } from '@db-ux/react-core-components'; +import { appConfig } from '@root/app.config'; +import { getCurrentPathname } from '@root/template/utils/app.utils'; +import { getNavigationItemParent } from '@root/template/utils/navigation.utils'; +import type { ReactElement } from 'react'; export function FooterNav(): ReactElement | null { const currentPathname = getCurrentPathname(); @@ -10,7 +10,7 @@ export function FooterNav(): ReactElement | null { const siblings = parent?.children; const getCurrentIndex = (): number => { return parent?.children?.findIndex((item) => { - const fullPath = `${appConfig.basePath}${item.path}`.replace(/\/+$/, ""); + const fullPath = `${appConfig.basePath}${item.path}`.replace(/\/+$/, ''); return fullPath === currentPathname; })!; }; @@ -23,9 +23,7 @@ export function FooterNav(): ReactElement | null { const previousNavItem = getPreviousNavItem(); const getNextNavItem = (): NavigationItem | undefined => { - return currentIndex < siblings?.length - 1 - ? siblings[currentIndex + 1] - : undefined; + return currentIndex < siblings?.length - 1 ? siblings[currentIndex + 1] : undefined; }; const nextNavItem = getNextNavItem(); diff --git a/template/layouts/default/main-content/toc/TableOfContents.tsx b/template/layouts/default/main-content/toc/TableOfContents.tsx index 99fffac..a533361 100644 --- a/template/layouts/default/main-content/toc/TableOfContents.tsx +++ b/template/layouts/default/main-content/toc/TableOfContents.tsx @@ -1,6 +1,6 @@ -import { getCurrentPathname } from "@root/template/utils/app.utils"; -import type { AstroGlobal, MarkdownHeading } from "astro"; -import { useEffect, useRef, useState, type ReactElement } from "react"; +import { getCurrentPathname } from '@root/template/utils/app.utils'; +import type { AstroGlobal, MarkdownHeading } from 'astro'; +import { useEffect, useRef, useState, type ReactElement } from 'react'; interface Props { astro: AstroGlobal; @@ -12,9 +12,9 @@ export function TableOfContents(props: Props): ReactElement | null { const slugs = headings.map((h) => h.slug); const currentPath = getCurrentPathname(props.astro); const toc = useRef(null); - const [currentID, setCurrentID] = useState(""); + const [currentID, setCurrentID] = useState(''); const activeIDs = useRef(new Set()); - const onThisPageID = "on-this-page-heading"; + const onThisPageID = 'on-this-page-heading'; useEffect(() => { if (!toc.current) return; @@ -23,9 +23,7 @@ export function TableOfContents(props: Props): ReactElement | null { for (const entry of entries) { const { id } = entry.target; if (id === onThisPageID) continue; - entry.isIntersecting - ? activeIDs.current.add(id) - : activeIDs.current.delete(id); + entry.isIntersecting ? activeIDs.current.add(id) : activeIDs.current.delete(id); highlightFirstActive(id); } }; @@ -34,19 +32,14 @@ export function TableOfContents(props: Props): ReactElement | null { // Negative top margin accounts for `scroll-margin`. // Negative bottom margin means heading needs to be towards top of viewport to trigger intersection. root: null, - rootMargin: "-96px 0px 0px 0px", + rootMargin: '-96px 0px 0px 0px', threshold: 1, }; - const headingsObserver = new IntersectionObserver( - setCurrent, - observerOptions, - ); + const headingsObserver = new IntersectionObserver(setCurrent, observerOptions); // Observe all the headings in the main page content. - const allHeadings = document.querySelectorAll( - "h2[id], h3[id], h4[id], h5[id], h6[id]", - ); + const allHeadings = document.querySelectorAll('h2[id], h3[id], h4[id], h5[id], h6[id]'); allHeadings.forEach((h) => headingsObserver.observe(h)); // Stop observing when the component is unmounted. @@ -64,9 +57,9 @@ export function TableOfContents(props: Props): ReactElement | null { const handleLinkClick = (e: any) => { e.preventDefault(); - const id = e.target.getAttribute("href").split("#")[1]; + const id = e.target.getAttribute('href').split('#')[1]; const hashId = `#${id}`; - history?.pushState(null, "", `${currentPath}${hashId}`); + history?.pushState(null, '', `${currentPath}${hashId}`); document.querySelector(hashId)?.scrollIntoView(); setTimeout(() => setCurrentID(id), 100); }; diff --git a/template/layouts/default/shell/control-panel/brand.tsx b/template/layouts/default/shell/control-panel/brand.tsx index aba0b30..725a931 100644 --- a/template/layouts/default/shell/control-panel/brand.tsx +++ b/template/layouts/default/shell/control-panel/brand.tsx @@ -1,13 +1,9 @@ -import { DBControlPanelBrand } from "@db-ux/react-core-components"; -import { appConfig } from "@root/app.config.ts"; +import { DBControlPanelBrand } from '@db-ux/react-core-components'; +import { appConfig } from '@root/app.config.ts'; const Brand = () => ( - - {appConfig.title} - + {appConfig.title} ); diff --git a/template/layouts/default/shell/control-panel/main-navigation.tsx b/template/layouts/default/shell/control-panel/main-navigation.tsx index 431a1a4..8deeea2 100644 --- a/template/layouts/default/shell/control-panel/main-navigation.tsx +++ b/template/layouts/default/shell/control-panel/main-navigation.tsx @@ -1,12 +1,9 @@ -import { DBNavigation } from "@db-ux/react-core-components"; -import { appNavigation } from "@root/app.navigation.ts"; -import NavItem from "@template/layouts/default/shell/control-panel/nav-item.tsx"; +import { DBNavigation } from '@db-ux/react-core-components'; +import { appNavigation } from '@root/app.navigation.ts'; +import NavItem from '@template/layouts/default/shell/control-panel/nav-item.tsx'; const MainNavigation = ({ mobile }: { mobile?: boolean }) => ( - + {appNavigation.map((navigationItem: NavigationItem) => ( ))} diff --git a/template/layouts/default/shell/control-panel/nav-item.tsx b/template/layouts/default/shell/control-panel/nav-item.tsx index 555bb78..660d357 100644 --- a/template/layouts/default/shell/control-panel/nav-item.tsx +++ b/template/layouts/default/shell/control-panel/nav-item.tsx @@ -1,43 +1,72 @@ -import { DBNavigationItem, DBNavigationItemGroup } from "@db-ux/react-core-components"; -import { getAriaCurrent } from "@template/utils/client.utils.ts"; -import { covers, getFirstChildPath } from "@template/utils/navigation.utils.ts"; +import { DBNavigationItem, DBNavigationItemGroup } from '@db-ux/react-core-components'; +import { getAriaCurrent } from '@template/utils/client.utils.ts'; +import { covers, getFirstChildPath } from '@template/utils/navigation.utils.ts'; -const NavItem = ({ path, title, icon, iconTrailing, children, isSubNavigation }: NavigationItem) => { - // if sub-navigation node, do not render children here - if (isSubNavigation) { - const target = path ?? getFirstChildPath(children); - const isActive = - typeof window !== "undefined" && - covers({ path, title, icon, iconTrailing, children, isSubNavigation }, window.location.pathname); +const NavItem = ({ + path, + title, + icon, + iconTrailing, + children, + isSubNavigation, + disabled, +}: NavigationItem) => { + // if sub-navigation node, do not render children here + if (isSubNavigation) { + const target = path ?? getFirstChildPath(children); + const isActive = + typeof window !== 'undefined' && + covers( + { path, title, icon, iconTrailing, children, isSubNavigation }, + window.location.pathname, + ); - return ( - - - {title} - - - ); - } - - // node with children - if (children && children.length > 0) { - return ( - - {children.map((sub) => ( - - ))} - - ); - } + return ( + + + {title} + + + ); + } - // leaf-node, no children + // node with children + if (children && children.length > 0) { return ( - - - {title} - - + + {children.map((sub) => ( + + ))} + ); + } + + // leaf-node, no children + return ( + + + {title} + + + ); }; export default NavItem; diff --git a/template/layouts/default/shell/control-panel/primary-actions.tsx b/template/layouts/default/shell/control-panel/primary-actions.tsx index f915785..40c817e 100644 --- a/template/layouts/default/shell/control-panel/primary-actions.tsx +++ b/template/layouts/default/shell/control-panel/primary-actions.tsx @@ -1,16 +1,19 @@ -import { DBControlPanelPrimaryActions } from "@db-ux/react-core-components"; -import { appConfig } from "@root/app.config.ts"; -import { Search } from "@template/layouts/default/shell/search"; -import ColorModeSwitch from "@template/components/color-mode-switch/ColorModeSwitch.tsx"; +import { DBControlPanelPrimaryActions } from '@db-ux/react-core-components'; +import { appConfig } from '@root/app.config.ts'; +import ColorModeSwitch from '@template/components/color-mode-switch/ColorModeSwitch.tsx'; const PrimaryActions = () => ( - - - - - Start now - - + + + {/* */} + + Start now + + ); export default PrimaryActions; diff --git a/template/layouts/default/shell/control-panel/secondary-actions.tsx b/template/layouts/default/shell/control-panel/secondary-actions.tsx index 4752881..7ca1478 100644 --- a/template/layouts/default/shell/control-panel/secondary-actions.tsx +++ b/template/layouts/default/shell/control-panel/secondary-actions.tsx @@ -1,8 +1,5 @@ -import { DBControlPanelSecondaryActions } from "@db-ux/react-core-components"; +import { DBControlPanelSecondaryActions } from '@db-ux/react-core-components'; -const SecondaryActions = () => ( - - -); +const SecondaryActions = () => ; export default SecondaryActions; diff --git a/template/layouts/default/shell/control-panel/sub-navigation.tsx b/template/layouts/default/shell/control-panel/sub-navigation.tsx index 7f47feb..c2738ee 100644 --- a/template/layouts/default/shell/control-panel/sub-navigation.tsx +++ b/template/layouts/default/shell/control-panel/sub-navigation.tsx @@ -1,18 +1,14 @@ -import { - DBNavigation, - DBShellSubNavigation, -} from "@db-ux/react-core-components"; -import NavItem from "@template/layouts/default/shell/control-panel/nav-item.tsx"; +import { DBNavigation, DBShellSubNavigation } from '@db-ux/react-core-components'; +import NavItem from '@template/layouts/default/shell/control-panel/nav-item.tsx'; -const SubNavigation = ({ - navigationItems, -}: { - navigationItems: NavigationItem[]; -}) => ( +const SubNavigation = ({ navigationItems }: { navigationItems: NavigationItem[] }) => ( {navigationItems.map((navigationItem: NavigationItem) => ( - + ))} diff --git a/template/layouts/default/shell/search/Search.tsx b/template/layouts/default/shell/search/Search.tsx index feb95b2..beefe53 100644 --- a/template/layouts/default/shell/search/Search.tsx +++ b/template/layouts/default/shell/search/Search.tsx @@ -1,21 +1,8 @@ -import { - DBButton, - DBCard, - DBDrawer, - DBInput, - DBTooltip, -} from "@db-ux/react-core-components"; -import React, { type ReactElement, useEffect, useState } from "react"; -import { - type AnyOrama, - create, - load, - type RawData, - type Results, - search, -} from "@orama/orama"; -import useDebounce from "@root/template/hooks/debounce"; -import { getMarkedContent } from "@template/utils/app.utils.ts"; +import { DBButton, DBCard, DBDrawer, DBInput, DBTooltip } from '@db-ux/react-core-components'; +import React, { type ReactElement, useEffect, useState } from 'react'; +import { type AnyOrama, create, load, type RawData, type Results, search } from '@orama/orama'; +import useDebounce from '@root/template/hooks/debounce'; +import { getMarkedContent } from '@template/utils/app.utils.ts'; type PageSchema = { path: string; @@ -33,16 +20,14 @@ export function Search(): ReactElement { const [searchOpen, setSearchOpen] = useState(false); const [pagesDb, setPagesDb] = useState(); const [searchResults, setSearchResults] = useState>(); - const [query, setQuery] = useState(""); + const [query, setQuery] = useState(''); const debouncedQuery = useDebounce(query, 200); useEffect(() => { const run = async () => { - const db = create({ schema: { _: "string" } }); + const db = create({ schema: { _: 'string' } }); - const dbResponse = await fetch( - `${import.meta.env.BASE_URL}assets/oramaDB_pages.json` - ); + const dbResponse = await fetch(`${import.meta.env.BASE_URL}assets/oramaDB_pages.json`); if (dbResponse.ok) { const dbData = (await dbResponse.json()) as RawData; @@ -56,22 +41,16 @@ export function Search(): ReactElement { useEffect(() => { if (pagesDb && debouncedQuery) { - const results: Results | Promise> = - search(pagesDb, { - term: debouncedQuery, - }); + const results: Results | Promise> = search(pagesDb, { + term: debouncedQuery, + }); setSearchResults(results as Results); } }, [debouncedQuery, pagesDb]); return (
- setSearchOpen(true)} - > + setSearchOpen(true)}> Open Search Open Search @@ -82,29 +61,22 @@ export function Search(): ReactElement { placeholder="Search" icon="magnifying_glass" variant="floating" - onChange={(event: React.ChangeEvent) => - setQuery(event.target.value) - } + onChange={(event: React.ChangeEvent) => setQuery(event.target.value)} /> {(searchResults?.hits?.length || 0) > 0 ? ( searchResults?.hits.map((hit) => { - const content = hit.document.content.replace(hit.document.h1, ""); - const { start, termIndex, end } = getMarkedContent( - content, - query, - ); + const content = hit.document.content.replace(hit.document.h1, ''); + const { start, termIndex, end } = getMarkedContent(content, query); return ( {hit.document.h1} {content.substring(start, termIndex)} - - {content.substring(termIndex, termIndex + query.length)} - + {content.substring(termIndex, termIndex + query.length)} {content.substring(termIndex + query.length, end)} diff --git a/template/styles/db-ux-overrides.css b/template/styles/db-ux-overrides.css index 5c0c571..7e8855c 100644 --- a/template/styles/db-ux-overrides.css +++ b/template/styles/db-ux-overrides.css @@ -6,3 +6,70 @@ } } } + +/* Equal-height card rows */ +.cards-row { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: var(--db-spacing-fixed-lg); + align-items: stretch; +} +.cards-row > a, +.cards-row > a > .db-card, +.cards-row > .db-card { + height: 100%; + display: flex; + flex-direction: column; +} +.cards-row .text-image { flex: 1 1 auto; } +.cards-row .text-image__content { flex: 1 1 auto; } + +/* Fixed 3 columns -> 1 column (no 2-col intermediate) */ +.cards-row-fixed { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: var(--db-spacing-fixed-lg); + align-items: stretch; +} +.cards-row-fixed > * { min-width: 0; } +.cards-row-fixed > a { display: block; width: 100%; } +.cards-row-fixed > a, +.cards-row-fixed > a > .db-card, +.cards-row-fixed > .db-card { height: 100%; display: flex; flex-direction: column; } +.cards-row-fixed .text-image { flex: 1 1 auto; } +.cards-row-fixed .text-image__content { flex: 1 1 auto; } +@media (max-width: 767px) { + .cards-row-fixed { grid-template-columns: 1fr; } +} + +.cards-row-fixed .db-card a.db-link { text-decoration: underline; } +.cards-row-fixed .db-card a { text-decoration: none; } + +/* Dark blue image tint for signatures or other images */ +.img--tint-dark-blue { + /* Using filter chain to approximate dark DB brand blue while preserving alpha */ + filter: saturate(0) brightness(0.4) sepia(1) hue-rotate(190deg) saturate(4) brightness(0.8); +} + +/* Dark mode: render these signature images white for contrast */ +@media (prefers-color-scheme: dark) { + .img--tint-dark-blue { + /* Turn image white: remove hue influence, boost brightness, invert if needed */ + filter: brightness(0) invert(1) sepia(0) saturate(0) contrast(1.1); + } +} + +/* Attribute-based mode hook (e.g., ) */ +[data-mode="dark"] .img--tint-dark-blue { + filter: brightness(0) invert(1) sepia(0) saturate(0) contrast(1.1); +} + +.db-stack > a > .db-card { + /* Ensure cards in stacks stretch to full width */ + height: 100%; + box-sizing: border-box; +} + +.db-stack { + overflow: visible; +} diff --git a/template/styles/global.css b/template/styles/global.css index 5e7f102..662b49a 100644 --- a/template/styles/global.css +++ b/template/styles/global.css @@ -23,3 +23,4 @@ html { scroll-padding-top: var(--header-height); } + diff --git a/template/styles/layout.css b/template/styles/layout.css index df019f9..637681f 100644 --- a/template/styles/layout.css +++ b/template/styles/layout.css @@ -25,7 +25,8 @@ } .dba-main-content { - padding: var(--db-spacing-fixed-3xl); + padding: 0; + max-width: 100vw; } .dba-main-footer-nav { @@ -53,7 +54,6 @@ background-color: var(--db-brand-origin-default); height: 0.5rem; width: 4rem; - margin-bottom: 2rem; } .dba-footer { @@ -70,7 +70,7 @@ p { margin: 0; - margin-block: auto; + /* Entfernt margin-block:auto – verhinderte erwartete vertikale Spacing außerhalb des Footer-Kontexts */ white-space: pre; } diff --git a/template/types/global.d.ts b/template/types/global.d.ts index dd8ef2f..1fdf867 100644 --- a/template/types/global.d.ts +++ b/template/types/global.d.ts @@ -14,6 +14,22 @@ declare interface FrontMatter { * The description of the page. */ description?: string; + /** + * Main headline for hero section. + */ + headline?: string; + /** + * Optional semantic heading level (1-6) for hero headline. + */ + headlineLevel?: 1 | 2 | 3 | 4 | 5 | 6; + /** + * Optional hero image URL. + */ + heroImage?: string; + /** + * Alt text for the hero image. + */ + heroImageAlt?: string; /** * The creation date of the page. */ @@ -82,6 +98,11 @@ declare interface NavigationItem { * The order of the navigation item. Lower numbers will appear first. */ order?: number; + + /** + * If true, the navigation item will be rendered as disabled. + */ + disabled?: boolean; } /** @@ -113,3 +134,9 @@ declare interface AppConfig { */ language: string; } + +// Allow importing .astro files in TypeScript contexts (e.g., barrel index.ts) +declare module '*.astro' { + const Component: any; + export default Component; +} diff --git a/template/utils/app.utils.ts b/template/utils/app.utils.ts index 11d2d84..86842b7 100644 --- a/template/utils/app.utils.ts +++ b/template/utils/app.utils.ts @@ -1,4 +1,4 @@ -import type { AstroGlobal } from "astro"; +import type { AstroGlobal } from 'astro'; /** * Attempts to retrieve the current pathname from the `astro` or the `window` global. @@ -6,13 +6,15 @@ import type { AstroGlobal } from "astro"; * @returns The current pathname. */ export function getCurrentPathname(astro?: AstroGlobal): string { - if (astro && astro.url) { - return astro.url.pathname.replace(/\/+$/, ""); - } else if (window && window.location) { - return window.location.pathname.replace(/\/+$/, ""); - } else { - throw new Error("Unable to retrieve current path."); + if (astro?.url) { + return astro.url.pathname.replace(/\/+$/, '') || '/'; } + + if (typeof window !== 'undefined' && window.location) { + return window.location.pathname.replace(/\/+$/, '') || '/'; + } + + return '/'; } /** @@ -21,7 +23,12 @@ export function getCurrentPathname(astro?: AstroGlobal): string { * @param ms */ export const delay = (fn: () => void, ms: number) => - new Promise(() => setTimeout(fn, ms)); + new Promise((resolve) => { + setTimeout(() => { + fn(); + resolve(); + }, ms); + }); /** * Get a start and end index of a content string based on a search term diff --git a/template/utils/client.utils.ts b/template/utils/client.utils.ts index 4cb5404..5d54fb7 100644 --- a/template/utils/client.utils.ts +++ b/template/utils/client.utils.ts @@ -1,13 +1,15 @@ -import { appConfig } from "@root/app.config"; +import { appConfig } from '@root/app.config'; /** * Get the aria-current attribute for the given path. * @param path - The path to check against the current URL. * @returns The aria-current attribute value if the path matches the current URL, otherwise undefined. */ -export function getAriaCurrent(path?: string): "page" | undefined { +export function getAriaCurrent(path?: string): 'page' | undefined { + if (typeof window === 'undefined' || !path) return undefined; + const { basePath } = appConfig; - const pathname = window.location.pathname.replace(/\/+$/, ""); - const fullPath = `${basePath}${path}`.replace(/\/+$/, ""); - return pathname === fullPath ? "page" : undefined; + const pathname = window.location.pathname.replace(/\/+$/, ''); + const fullPath = `${basePath}${path}`.replace(/\/+$/, ''); + return pathname === fullPath ? 'page' : undefined; } diff --git a/template/utils/content-navigation.ts b/template/utils/content-navigation.ts index 22f75f7..3f84b5c 100644 --- a/template/utils/content-navigation.ts +++ b/template/utils/content-navigation.ts @@ -1,4 +1,13 @@ -type MdModule = { frontmatter: FrontMatter }; +type NavigationFrontmatter = FrontMatter & { + hidePage?: boolean; + isSubNavigation?: boolean; + iconTrailing?: string; + isMenuItemDisabled?: boolean; + order?: number; + nav?: boolean | { order?: number }; +}; + +type MdModule = { frontmatter: NavigationFrontmatter }; type Modules = Record; /** @@ -8,9 +17,9 @@ type Modules = Record; * @returns A normalized relative path without a leading slash ("" for root). */ function strip(path: string): string { - const unix = path.replace(/\\/g, "/"); - const withoutPrefix = unix.replace(/^.*content\/pages\//, ""); - return withoutPrefix.replace(/(?:\/index\.(md|mdx)|^index\.(md|mdx))$/, ""); + const unix = path.replace(/\\/g, '/'); + const withoutPrefix = unix.replace(/^.*content\/pages\//, ''); + return withoutPrefix.replace(/(?:\/index\.(md|mdx)|^index\.(md|mdx))$/, ''); } /** @@ -20,10 +29,10 @@ function strip(path: string): string { * @returns A human-friendly title string. */ function toTitleFromSegment(segment: string): string { - return segment - .split("-") - .map((s) => s.charAt(0).toUpperCase() + s.slice(1)) - .join(" "); + return segment + .split('-') + .map((s) => s.charAt(0).toUpperCase() + s.slice(1)) + .join(' '); } /** @@ -33,9 +42,9 @@ function toTitleFromSegment(segment: string): string { * @param child - The child item to add if missing. */ function ensureChild(parent: NavigationItem, child: NavigationItem) { - parent.children = parent.children ?? []; - const exists = parent.children.find((c) => c.path === child.path); - if (!exists) parent.children.push(child); + parent.children = parent.children ?? []; + const exists = parent.children.find((c) => c.path === child.path); + if (!exists) parent.children.push(child); } /** @@ -44,9 +53,9 @@ function ensureChild(parent: NavigationItem, child: NavigationItem) { * @param fm - The frontmatter object. * @returns A number representing the sort order, or `undefined` if not set. */ -function getOrder(fm: any): number | undefined { - if (typeof fm?.order === "number") return fm.order; - return undefined; +function getOrder(fm: NavigationFrontmatter): number | undefined { + if (typeof fm?.order === 'number') return fm.order; + return undefined; } /** @@ -57,10 +66,10 @@ function getOrder(fm: any): number | undefined { * @returns -1, 0, or 1 depending on order. */ function compareNav(a: NavigationItem, b: NavigationItem) { - const ao = (a as any).order ?? Number.MAX_SAFE_INTEGER; - const bo = (b as any).order ?? Number.MAX_SAFE_INTEGER; - if (ao !== bo) return ao - bo; - return (a.title || "").localeCompare(b.title || ""); + const ao = a.order ?? Number.MAX_SAFE_INTEGER; + const bo = b.order ?? Number.MAX_SAFE_INTEGER; + if (ao !== bo) return ao - bo; + return (a.title || '').localeCompare(b.title || ''); } /** @@ -70,10 +79,10 @@ function compareNav(a: NavigationItem, b: NavigationItem) { * @param node - Root or intermediate node of the navigation tree. */ function sortTree(node: NavigationItem) { - if (node.children?.length) { - node.children.sort(compareNav); - node.children.forEach(sortTree); - } + if (node.children?.length) { + node.children.sort(compareNav); + node.children.forEach(sortTree); + } } /** @@ -84,63 +93,66 @@ function sortTree(node: NavigationItem) { * @returns A fully structured and sorted `AppNavigation` tree. */ export function buildAppNavigationFromContent(): AppNavigation { - const mods = import.meta.glob("../../content/pages/**/index.{md,mdx}", { - eager: true, - }) as Modules; - const nodes = new Map(); - - for (const [key, mod] of Object.entries(mods)) { - const rel = strip(key); - const segments = rel.split("/").filter(Boolean); - const fm = (mod.frontmatter ?? {}) as any; - - if (rel === "") continue; - if (fm.nav === false) continue; - - const title = fm.title || (segments.length ? toTitleFromSegment(segments[segments.length - 1]) : "Home"); - const hidePage = fm.hidePage === true; - const isSubNavigation = fm.isSubNavigation ?? fm.isSubnavigation ?? false; - const iconTrailing = fm.iconTrailing; - const order = getOrder(fm); - - const node: NavigationItem = { - title, - path: hidePage ? undefined : rel, - isSubNavigation, - iconTrailing, - children: [], + const mods = import.meta.glob('../../content/pages/**/index.{md,mdx}', { + eager: true, + }) as Modules; + const nodes = new Map(); + + for (const [key, mod] of Object.entries(mods)) { + const rel = strip(key); + const segments = rel.split('/').filter(Boolean); + const fm: NavigationFrontmatter = mod.frontmatter ?? ({} as NavigationFrontmatter); + + if (rel === '') continue; + if (fm.nav === false) continue; + + const title = + fm.title || (segments.length ? toTitleFromSegment(segments[segments.length - 1]) : 'Home'); + const hidePage = fm.hidePage === true; + const isSubNavigation = fm.isSubNavigation ?? false; + const iconTrailing = fm.iconTrailing; + const disabled = fm.isMenuItemDisabled === true; + const order = getOrder(fm); + + const node: NavigationItem = { + title, + path: hidePage ? undefined : rel, + isSubNavigation, + iconTrailing, + children: [], + disabled, + order, + }; + + nodes.set(rel, node); + + for (let i = 1; i < segments.length; i++) { + const parentKey = segments.slice(0, i).join('/'); + if (!nodes.has(parentKey)) { + const parentNode: NavigationItem = { + title: toTitleFromSegment(segments[i - 1]), + path: parentKey, + children: [], }; - (node as any).order = order; - - nodes.set(rel, node); - - for (let i = 1; i < segments.length; i++) { - const parentKey = segments.slice(0, i).join("/"); - if (!nodes.has(parentKey)) { - const parentNode: NavigationItem = { - title: toTitleFromSegment(segments[i - 1]), - path: parentKey, - children: [], - }; - nodes.set(parentKey, parentNode); - } - } + nodes.set(parentKey, parentNode); + } } - - const roots: Record = {}; - for (const [rel, node] of nodes) { - const segments = rel.split("/").filter(Boolean); - if (segments.length <= 1) { - roots[rel] = roots[rel] ?? node; - } else { - const parentKey = segments.slice(0, segments.length - 1).join("/"); - const parent = nodes.get(parentKey); - if (parent) ensureChild(parent, node); - } + } + + const roots: Record = {}; + for (const [rel, node] of nodes) { + const segments = rel.split('/').filter(Boolean); + if (segments.length <= 1) { + roots[rel] = roots[rel] ?? node; + } else { + const parentKey = segments.slice(0, segments.length - 1).join('/'); + const parent = nodes.get(parentKey); + if (parent) ensureChild(parent, node); } + } - const appNav: AppNavigation = Object.values(roots).sort(compareNav); - appNav.forEach(sortTree); + const appNav: AppNavigation = Object.values(roots).sort(compareNav); + appNav.forEach(sortTree); - return appNav; -} \ No newline at end of file + return appNav; +} diff --git a/template/utils/navigation.utils.ts b/template/utils/navigation.utils.ts index 7c50e69..e32735e 100644 --- a/template/utils/navigation.utils.ts +++ b/template/utils/navigation.utils.ts @@ -1,5 +1,5 @@ -import { appConfig } from "@root/app.config"; -import { appNavigation } from "@root/app.navigation"; +import { appConfig } from '@root/app.config'; +import { appNavigation } from '@root/app.navigation'; /** * Normalizes a path by removing trailing slashes. @@ -7,7 +7,7 @@ import { appNavigation } from "@root/app.navigation"; * @param path - The path to normalize * @returns The normalized path without trailing slashes */ -const norm = (path: string) => path.replace(/\/+$/, ""); +const norm = (path: string) => path.replace(/\/+$/, ''); /** * Prepends the base path to a relative path and normalizes the result. @@ -16,8 +16,8 @@ const norm = (path: string) => path.replace(/\/+$/, ""); * @returns The normalized absolute path including the base path */ function withBase(relPath: string) { - const base = norm(appConfig.basePath || "/"); - const rel = relPath.startsWith("/") ? relPath : `/${relPath}`; + const base = norm(appConfig.basePath || '/'); + const rel = relPath.startsWith('/') ? relPath : `/${relPath}`; return norm(`${base}${rel}`); } @@ -41,7 +41,7 @@ export function getFirstChildPath(children?: NavigationItem[]): string | undefin export function covers(item: NavigationItem, currentPath: string): boolean { if (item.path) { const full = withBase(item.path); - if (currentPath === full || currentPath.startsWith(full + "/")) return true; + if (currentPath === full || currentPath.startsWith(full + '/')) return true; } for (const child of item.children ?? []) { if (covers(child, currentPath)) return true; @@ -71,20 +71,20 @@ export function findSubNavigation(currentPathname: string): NavigationItem[] | u } /** -* Finds the parent navigation item for a given pathname. -* -* @param pathname - The pathname to find the parent for -* @returns The parent navigation item if found, undefined otherwise -*/ + * Finds the parent navigation item for a given pathname. + * + * @param pathname - The pathname to find the parent for + * @returns The parent navigation item if found, undefined otherwise + */ export function getNavigationItemParent(pathname: string): NavigationItem | undefined { const { basePath } = appConfig; - const norm = (p: string) => p.replace(/\/+$/, ""); + const norm = (p: string) => p.replace(/\/+$/, ''); const _pathname = norm(pathname); const withBase = (relPath?: string) => { if (!relPath) return undefined; - const base = norm(basePath || "/"); - const rel = relPath.startsWith("/") ? relPath : `/${relPath}`; + const base = norm(basePath || '/'); + const rel = relPath.startsWith('/') ? relPath : `/${relPath}`; return norm(`${base}${rel}`); }; diff --git a/tsconfig.json b/tsconfig.json index 0fe56b4..ccde54e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,14 +4,18 @@ "./content", "./template", "./app.config.ts", - "./app.navigation.ts" + "./app.navigation.ts", + "./components" ], "compilerOptions": { "baseUrl": ".", "paths": { "@root/*": ["./*"], "@content/*": ["content/*"], - "@template/*": ["template/*"] + "@template/*": ["template/*"], + "@components": ["template/components/index.ts"], + "@components/*": ["template/components/*"], + "@config": ["app.config.ts"] } } }