Skip to content

Commit 5f25529

Browse files
Feature/storybook for UI (#222)
added Storybook stories for UI elements & components
1 parent 16ea092 commit 5f25529

File tree

133 files changed

+6236
-246
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+6236
-246
lines changed

.changeset/green-gifts-fly.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@o2s/api-harmonization': patch
3+
'@o2s/framework': patch
4+
'@o2s/frontend': patch
5+
---
6+
7+
added an option to set a page-based themes via CMS config

.changeset/social-tools-wave.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@o2s/integrations.strapi-cms': patch
3+
'@o2s/blocks.category-list': patch
4+
'@o2s/integrations.mocked': patch
5+
'@o2s/blocks.quick-links': patch
6+
'@o2s/api-harmonization': patch
7+
'@o2s/framework': patch
8+
'@o2s/frontend': patch
9+
'@o2s/ui': patch
10+
---
11+
12+
added stories for UI components

.storybook/data.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,3 +208,17 @@ export const globalProviderLabels: GlobalProviderProps['labels'] = {
208208
details: 'Details',
209209
},
210210
};
211+
212+
export const globalProviderThemes: GlobalProviderProps['themes'] = {
213+
default: {
214+
name: 'default',
215+
logo: {
216+
url: 'https://raw.githubusercontent.com/o2sdev/openselfservice/refs/heads/main/packages/integrations/mocked/public/images/logo.svg',
217+
alt: 'Logo',
218+
width: 92,
219+
height: 24,
220+
},
221+
},
222+
};
223+
224+
export const globalProviderCurrentTheme: GlobalProviderProps['currentTheme'] = 'default';

.storybook/main.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const env: {
99
dotenv.config({
1010
path: 'apps/frontend/.env.development',
1111
processEnv: env,
12+
quiet: true,
1213
});
1314

1415
/**
@@ -23,6 +24,7 @@ const config: StorybookConfig = {
2324
stories: [
2425
'../apps/frontend/src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
2526
'../packages/blocks/**/src/frontend/**/*.stories.@(js|jsx|mjs|ts|tsx)',
27+
'../packages/ui/**/*.stories.@(js|jsx|mjs|ts|tsx)',
2628
],
2729
addons: [
2830
getAbsolutePath('@storybook/addon-docs'),
@@ -33,6 +35,9 @@ const config: StorybookConfig = {
3335
name: getAbsolutePath('@storybook/nextjs'),
3436
options: {},
3537
},
38+
typescript: {
39+
reactDocgen: 'react-docgen-typescript',
40+
},
3641
env: (config) => ({
3742
...config,
3843
...env,

.storybook/preview.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { AppSpinner } from '@o2s/ui/components/AppSpinner';
1010
import { Toaster } from '@o2s/ui/elements/toaster';
1111
import { TooltipProvider } from '@o2s/ui/elements/tooltip';
1212

13-
import { globalProviderConfig, globalProviderLabels } from './data';
13+
import { globalProviderConfig, globalProviderCurrentTheme, globalProviderLabels, globalProviderThemes } from './data';
1414

1515
import '../apps/frontend/src/styles/global.css';
1616
import messages from '../apps/frontend/src/i18n/messages/en.json'
@@ -37,12 +37,8 @@ const preview: Preview = {
3737
}),
3838
(Story) => {
3939
return(
40-
<NextIntlClientProvider locale="en" messages={{
41-
"general": {
42-
"comingSoon": "This feature is coming soon!"
43-
}
44-
}}>
45-
<GlobalProvider config={globalProviderConfig} labels={globalProviderLabels} locale="en">
40+
<NextIntlClientProvider locale="en" messages={messages}>
41+
<GlobalProvider config={globalProviderConfig} labels={globalProviderLabels} themes={globalProviderThemes} currentTheme={globalProviderCurrentTheme} locale="en">
4642
<TooltipProvider>
4743
<Story />
4844

apps/api-harmonization/src/modules/page/page.mapper.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export const mapPage = (
3232
noFollow: page.seo.noFollow,
3333
},
3434
locales,
35+
theme: page.theme,
3536
},
3637
data: {
3738
alternativeUrls,
@@ -57,6 +58,7 @@ export const mapArticle = (
5758
noFollow: false,
5859
},
5960
locales: [mainLocale],
61+
theme: article.theme,
6062
},
6163
data: {
6264
alternativeUrls: {},
@@ -137,6 +139,7 @@ export const mapInit = (
137139
header: CMS.Model.Header.Header,
138140
footer: CMS.Model.Footer.Footer,
139141
labels: CMS.Model.AppConfig.Labels,
142+
themes: CMS.Model.AppConfig.Themes,
140143
roles: Auth.Constants.Roles[],
141144
): Init => {
142145
return {
@@ -172,5 +175,6 @@ export const mapInit = (
172175
},
173176
},
174177
labels,
178+
themes,
175179
};
176180
};

apps/api-harmonization/src/modules/page/page.model.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,12 @@ export class Init {
3131
}[];
3232
common!: PageCommon;
3333
labels!: Labels;
34+
themes!: Themes;
3435
}
3536

3637
export type Labels = CMS.Model.AppConfig.Labels;
38+
export type Themes = CMS.Model.AppConfig.Themes;
39+
3740
export class Page {
3841
data?: PageData;
3942
meta!: Metadata;
@@ -46,6 +49,7 @@ export class NotFound {
4649
export class Metadata {
4750
seo!: Models.SEO.Page;
4851
locales!: string[];
52+
theme?: string;
4953
}
5054

5155
export class Breadcrumb {

apps/api-harmonization/src/modules/page/page.service.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,14 @@ export class PageService {
6363

6464
return forkJoin([header, footer]).pipe(
6565
map(([header, footer]) => {
66-
return mapInit(appConfig.locales, header, footer, appConfig.labels, userRoles);
66+
return mapInit(
67+
appConfig.locales,
68+
header,
69+
footer,
70+
appConfig.labels,
71+
appConfig.themes,
72+
userRoles,
73+
);
6774
}),
6875
);
6976
}),

apps/frontend/src/app/[locale]/(auth)/login/page.tsx

Lines changed: 44 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -96,50 +96,52 @@ export default async function LoginPage({ params }: Readonly<Props>) {
9696
};
9797

9898
return (
99-
<GlobalProvider config={init} labels={init.labels} locale={locale}>
100-
<div className="flex flex-col min-h-dvh">
101-
<Header data={init.common.header} />
102-
<div className="flex flex-col grow">
103-
<AuthLayout>
104-
<SignInForm
105-
providers={providerMap}
106-
labels={{
107-
title: data.title,
108-
subtitle: data.subtitle,
109-
password: {
110-
label: data.password.label,
111-
placeholder: data.password.placeholder,
112-
hide: data.labels?.hide,
113-
show: data.labels?.show,
114-
errorMessages: data.password?.errorMessages,
115-
},
116-
username: {
117-
label: data.username.label,
118-
placeholder: data.username.placeholder,
119-
errorMessages: data.username?.errorMessages,
120-
},
121-
signIn: data.signIn,
122-
providers: data.providers,
123-
invalidCredentials: data.invalidCredentials,
124-
}}
125-
onSignIn={handleSignIn}
126-
/>
127-
{data.image?.url && (
128-
<Image
129-
src={data.image?.url}
130-
alt={data.image?.alt}
131-
fill={true}
132-
className="object-cover"
99+
<body>
100+
<GlobalProvider config={init} labels={init.labels} locale={locale} themes={init.themes}>
101+
<div className="flex flex-col min-h-dvh">
102+
<Header data={init.common.header} />
103+
<div className="flex flex-col grow">
104+
<AuthLayout>
105+
<SignInForm
106+
providers={providerMap}
107+
labels={{
108+
title: data.title,
109+
subtitle: data.subtitle,
110+
password: {
111+
label: data.password.label,
112+
placeholder: data.password.placeholder,
113+
hide: data.labels?.hide,
114+
show: data.labels?.show,
115+
errorMessages: data.password?.errorMessages,
116+
},
117+
username: {
118+
label: data.username.label,
119+
placeholder: data.username.placeholder,
120+
errorMessages: data.username?.errorMessages,
121+
},
122+
signIn: data.signIn,
123+
providers: data.providers,
124+
invalidCredentials: data.invalidCredentials,
125+
}}
126+
onSignIn={handleSignIn}
133127
/>
134-
)}
135-
</AuthLayout>
128+
{data.image?.url && (
129+
<Image
130+
src={data.image?.url}
131+
alt={data.image?.alt}
132+
fill={true}
133+
className="object-cover"
134+
/>
135+
)}
136+
</AuthLayout>
137+
</div>
138+
<Footer data={init.common.footer} />
139+
140+
<Toaster />
141+
<AppSpinner />
136142
</div>
137-
<Footer data={init.common.footer} />
138-
139-
<Toaster />
140-
<AppSpinner />
141-
</div>
142-
</GlobalProvider>
143+
</GlobalProvider>
144+
</body>
143145
);
144146
} catch (_error) {
145147
notFound();

apps/frontend/src/app/[locale]/[[...slug]]/page.tsx

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -103,40 +103,56 @@ export default async function Page({ params }: Props) {
103103
if (!data || !meta) {
104104
notFound();
105105
}
106+
107+
let theme = '';
108+
if (meta.theme) {
109+
theme = `theme-${meta.theme}`;
110+
}
111+
106112
return (
107-
<GlobalProvider config={init} labels={init.labels} locale={locale}>
108-
<div className="flex flex-col min-h-dvh">
109-
<Header data={init.common.header} alternativeUrls={data.alternativeUrls} />
110-
<div className="flex flex-col grow">
111-
<div className="py-6 px-4 md:px-6 ml-auto mr-auto w-full md:max-w-7xl">
112-
<main className="flex flex-col gap-6 row-start-2 items-center sm:items-start">
113-
<div className="flex flex-col gap-6 w-full">
114-
<Breadcrumbs
115-
breadcrumbs={
116-
rootBreadcrumb ? [rootBreadcrumb, ...data.breadcrumbs] : data.breadcrumbs
117-
}
118-
LinkComponent={Link}
119-
/>
120-
{!data.hasOwnTitle && (
121-
<>
122-
<Typography variant="h1" asChild>
123-
<h1>{meta.seo.title}</h1>
124-
</Typography>
125-
<Separator />
126-
</>
127-
)}
128-
</div>
129-
130-
<PageTemplate slug={slug} data={data} />
131-
</main>
113+
<body className={theme}>
114+
<GlobalProvider
115+
config={init}
116+
labels={init.labels}
117+
locale={locale}
118+
themes={init.themes}
119+
currentTheme={meta.theme}
120+
>
121+
<div className="flex flex-col min-h-dvh">
122+
<Header data={init.common.header} alternativeUrls={data.alternativeUrls} />
123+
<div className="flex flex-col grow">
124+
<div className="py-6 px-4 md:px-6 ml-auto mr-auto w-full md:max-w-7xl">
125+
<main className="flex flex-col gap-6 row-start-2 items-center sm:items-start">
126+
<div className="flex flex-col gap-6 w-full">
127+
<Breadcrumbs
128+
breadcrumbs={
129+
rootBreadcrumb
130+
? [rootBreadcrumb, ...data.breadcrumbs]
131+
: data.breadcrumbs
132+
}
133+
LinkComponent={Link}
134+
/>
135+
{!data.hasOwnTitle && (
136+
<>
137+
<Typography variant="h1" asChild>
138+
<h1>{meta.seo.title}</h1>
139+
</Typography>
140+
<Separator />
141+
</>
142+
)}
143+
</div>
144+
145+
<PageTemplate slug={slug} data={data} />
146+
</main>
147+
</div>
132148
</div>
133-
</div>
134-
<Footer data={init.common.footer} />
149+
<Footer data={init.common.footer} />
135150

136-
<Toaster />
137-
<AppSpinner />
138-
</div>
139-
</GlobalProvider>
151+
<Toaster />
152+
<AppSpinner />
153+
</div>
154+
</GlobalProvider>
155+
</body>
140156
);
141157
} catch (error) {
142158
if (

0 commit comments

Comments
 (0)