Skip to content

Commit f35be07

Browse files
committed
feat(): rebuild image switcher with light/dark toggle
1 parent 644f510 commit f35be07

File tree

7 files changed

+252
-170
lines changed

7 files changed

+252
-170
lines changed

content/pages/home/home.config.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,40 @@ import { appConfig } from '@config';
22

33
export const interactiveDemoOptions = [
44
{
5-
id: 'neutral-light',
5+
id: 'neutral',
66
color: 'neutral',
77
variant: 'filled',
8-
src: `${appConfig.basePath}assets/interactive-demo/Neutral--Lightmode--C.png`,
8+
lightSrc: `${appConfig.basePath}assets/interactive-demo/Neutral--Lightmode--C.png`,
9+
darkSrc: `${appConfig.basePath}assets/interactive-demo/Neutral--Darkmode--C.png`,
910
label: 'Neutral',
1011
},
1112
{
12-
id: 'db-light',
13+
id: 'db',
1314
icon: 'db',
1415
color: 'red',
1516
variant: 'filled',
16-
src: `${appConfig.basePath}assets/interactive-demo/DB--Lightmode--C.png`,
17+
lightSrc: `${appConfig.basePath}assets/interactive-demo/DB--Lightmode--C.png`,
18+
darkSrc: `${appConfig.basePath}assets/interactive-demo/DB--Darkmode--C.png`,
1719
label: 'Deutsche Bahn',
1820
},
1921
{
20-
id: 'sbahn-light',
22+
id: 'sbahn',
2123
icon: 's_bahn',
2224
color: 'green',
2325
variant: 'filled',
24-
src: `${appConfig.basePath}assets/interactive-demo/SB--Lightmode--C.png`,
26+
lightSrc: `${appConfig.basePath}assets/interactive-demo/SB--Lightmode--C.png`,
27+
darkSrc: `${appConfig.basePath}assets/interactive-demo/SB--Darkmode--C.png`,
2528
label: 'S-Bahn',
2629
},
2730
{
28-
id: 'ri-light',
31+
id: 'ri',
2932
icon: 'train_station',
3033
color: 'blue',
3134
variant: 'filled',
32-
src: `${appConfig.basePath}assets/interactive-demo/RI--Lightmode--C.png`,
35+
lightSrc: `${appConfig.basePath}assets/interactive-demo/RI--Lightmode--C.png`,
36+
darkSrc: `${appConfig.basePath}assets/interactive-demo/RI--Darkmode--C.png`,
3337
label: 'Station & Service',
3438
},
35-
];
39+
] as const;
3640

37-
export const interactiveDemoDefaultOptionId = 'db-light';
41+
export const interactiveDemoDefaultOptionId = 'db';

template/components/InteractiveDemo/InteractiveDemo.astro

Lines changed: 90 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,127 @@
22
import { DBButton, DBStack, DBCard } from '@db-ux/react-core-components';
33
import './InteractiveDemo.css';
44
5-
const items = Array.isArray(Astro.props.items) ? Astro.props.items : [];
6-
const initialId = Astro.props.initialId;
5+
type InteractiveDemoItem = {
6+
id: string;
7+
label: string;
8+
icon?: string;
9+
color?: string;
10+
variant?: string;
11+
lightSrc: string;
12+
darkSrc: string;
13+
alt?: string;
14+
};
15+
16+
interface Props {
17+
items: readonly InteractiveDemoItem[];
18+
initialId?: string;
19+
}
20+
21+
const props = Astro.props as Props;
22+
const items = Array.isArray(props.items) ? props.items : [];
23+
const initialId = props.initialId;
724
const initialItem = (initialId && items.find((i) => i.id === initialId)) ?? items[0] ?? null;
25+
const initialMode = 'light';
826
---
927

1028
{
1129
items.length === 0 || !initialItem ? null : (
12-
<div data-image-toggle-root>
13-
<DBStack style={{ overflow: 'unset' }}>
14-
<div style="padding: var(--db-spacing-fixed-2xs); background: var(--db-adaptive-bg-basic-level-1-default); border-radius: var(--db-border-radius-sm); border: var(--db-border-width-3xs) solid var(--db-adaptive-on-bg-basic-emphasis-60-default); position: sticky; top: var(--db-spacing-fixed-md); width: 100%; max-width: fit-content; margin: 0 auto;">
15-
<DBStack direction="row" gap="2x-small">
16-
<DBStack direction="row" gap="2x-small">
30+
<div class="interactive-demo" data-image-toggle-root data-active-id={initialItem.id}>
31+
{/* State carrier for the script (must NOT affect theming/layout) */}
32+
<span
33+
class="interactive-demo__state"
34+
data-image-toggle-state
35+
data-mode={initialMode}
36+
hidden
37+
/>
38+
39+
<DBStack direction="column" gap="medium" class="interactive-demo__layout">
40+
<div class="interactive-demo__controls">
41+
<DBStack direction="row" gap="2x-small" justifyContent="center">
42+
<DBStack direction="row" gap="2x-small" justifyContent="center">
1743
{items.map((item) => (
1844
<DBButton
45+
type="button"
1946
icon={item.icon}
2047
variant={item.variant}
2148
data-color={item.color}
2249
data-image-toggle-button
2350
data-image-id={item.id}
24-
data-image-src={item.src}
25-
data-image-alt={item.alt ?? item.label}
26-
{...(item.id === initialItem.id ? { 'data-active': '' } : {})}
51+
{...(item.id === initialItem.id ? { 'data-active': 'true' } : {})}
2752
>
2853
{item.label}
2954
</DBButton>
3055
))}
3156
</DBStack>
57+
58+
{/* Initial state: light is active -> show only "switch to dark" (moon) */}
3259
<DBButton
60+
type="button"
3361
icon="moon"
3462
variant="ghost"
3563
noText={true}
36-
data-image-toggle-light
64+
data-image-toggle-to="dark"
3765
aria-label="Switch to dark mode"
66+
style={{ display: 'inline-flex' }}
3867
/>
3968
<DBButton
69+
type="button"
4070
icon="sun"
4171
variant="ghost"
4272
noText={true}
43-
data-image-toggle-dark
73+
data-image-toggle-to="light"
4474
aria-label="Switch to light mode"
75+
style={{ display: 'none' }}
4576
/>
4677
</DBStack>
4778
</div>
48-
<DBCard spacing="none" style={{ overflow: 'hidden' }} data-image-card>
49-
<img
50-
data-image-toggle-target
51-
src={initialItem.src}
52-
alt={initialItem.alt ?? initialItem.label}
53-
/>
54-
</DBCard>
79+
80+
<div class="interactive-demo__cards">
81+
{items.map((item) => (
82+
<>
83+
<div
84+
class="interactive-demo__card"
85+
data-image-card
86+
data-image-id={item.id}
87+
data-image-mode="light"
88+
{...(item.id === initialItem.id ? { 'data-active': 'true' } : {})}
89+
>
90+
<DBCard spacing="none" class="interactive-demo__card-inner">
91+
<img
92+
class="interactive-demo__img"
93+
src={item.lightSrc}
94+
alt={item.alt ?? item.label}
95+
loading="lazy"
96+
decoding="async"
97+
/>
98+
</DBCard>
99+
</div>
100+
101+
<div
102+
class="interactive-demo__card"
103+
data-image-card
104+
data-image-id={item.id}
105+
data-image-mode="dark"
106+
>
107+
<DBCard spacing="none" class="interactive-demo__card-inner">
108+
<img
109+
class="interactive-demo__img"
110+
src={item.darkSrc}
111+
alt={item.alt ?? item.label}
112+
loading="lazy"
113+
decoding="async"
114+
/>
115+
</DBCard>
116+
</div>
117+
</>
118+
))}
119+
</div>
55120
</DBStack>
121+
122+
<script
123+
is:inline
124+
src={`${import.meta.env.BASE_URL}assets/interactive-demo/interactiveDemo.client.js`}
125+
></script>
56126
</div>
57127
)
58-
}
59-
<script src="./interactiveDemo.client.js"></script>
128+
}
Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,37 @@
1-
/* Styles specific to InteractiveDemo component */
1+
.interactive-demo {
2+
color-scheme: light;
3+
}
24

3-
/* Active state button styling: highlights the currently selected brand/theme */
4-
[data-image-toggle-root] [data-image-toggle-button][data-active] {
5-
background: var(--db-adaptive-origin-default);
6-
color: var(--db-adaptive-on-origin-default);
5+
.interactive-demo__layout {
6+
overflow: unset;
77
}
88

9-
[data-image-toggle-root] [data-image-toggle-button][data-active]:hover {
10-
opacity: 0.88;
11-
background: var(--db-adaptive-origin-default);
12-
color: var(--db-adaptive-on-origin-default);
9+
.interactive-demo__controls {
10+
padding: var(--db-spacing-fixed-2xs);
11+
background: var(--db-adaptive-bg-basic-level-1-default);
12+
border-radius: var(--db-border-radius-sm);
13+
border: var(--db-border-width-3xs) solid var(--db-adaptive-on-bg-basic-emphasis-60-default);
14+
position: sticky;
15+
top: var(--db-spacing-fixed-md);
16+
width: 100%;
17+
max-width: fit-content;
18+
margin: 0 auto;
1319
}
1420

15-
/* Optional: focus ring for accessibility (commented out)
16-
[data-image-toggle-root] [data-image-toggle-button][data-active]:focus-visible {
17-
outline: var(--db-border-width-2xs) solid var(--db-brand-origin-default);
18-
outline-offset: var(--db-border-width-3xs);
21+
.interactive-demo__card {
22+
display: none;
1923
}
20-
*/
21-
/* Responsive Stack */
22-
@media (max-width: 767px) {
23-
.db-stack {
24-
overflow: auto;
24+
25+
.interactive-demo__card[data-active="true"] {
26+
display: block;
2527
}
28+
29+
.interactive-demo__card-inner {
30+
overflow: hidden;
31+
}
32+
33+
.interactive-demo__img {
34+
display: block;
35+
width: 100%;
36+
height: auto;
2637
}

0 commit comments

Comments
 (0)