Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(elements): add light- & dark-mode configuration #1110

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ $animation-time: 200ms;
.ino-accordion {
&:hover {
background: theme.$p-1;
/*
TODO: Switch to CSS variables for light- & dark theme support.
Replace the above line with the following once the global styles.scss file has been updated with a dark-theme import:
background: var(--inovex-elements-p-1);
*/
}
border-radius: 24px;

Expand Down Expand Up @@ -35,7 +40,7 @@ $animation-time: 200ms;
}

&--expanded {
background: theme.$p-1;
background: var(--inovex-elements-p-1); //Example for CSS variable usage
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great start for switching between light and dark theme!
The approach of using a second theme-color-pallet with the same names as the given light-theme is great, because we won't need to introduce more variables.

But i have the concern, that we won't have a dark theme-color-pallet which will perfectly match with the light-theme colors.

Because some components might work which their light-theme colors in dark mode but some might need bigger adjustments which won't perfectly fit across all other components.

If we won't find a fitting dark-theme-color-pallet I would suggest to store the component colors as variable (e.g. $ino-accordion-bg-color) which will choose, according to the selected theme, what color should be displayed. This will allow a fine granular adjustment of all colors.

Example:
ino-accordion-colors.scss(holds only accordion colors) or ino-components-colors.scss(holds colors of every component)

.inovex-elements-theme-light {
 $ino-accordion-bg-color: theme.$p-2;
 $ino-accordion-icon-color: theme.$p-5;
 $ino-accordion-text-color: theme.$n-11;
 ...
}

.inovex-elements-theme-dark {
 $ino-accordion-bg-color: theme.$n-8;
 $ino-accordion-icon-color: theme.$p-5;
 $ino-accordion-text-color: theme.$white;
 ...
}

But with smaller deviation we won't need this procedure.

Waiting for #1058 and dark-theme-pallet

}

.ino-accordion__content-wrapper {
Expand Down
27 changes: 25 additions & 2 deletions packages/elements/src/global/styles.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
@use '../components/base/typography-new';
@use '../components/base/theme';
@use '../components/base/new-theme' as new-theme;
/*
@use '../components/base/dark-theme' as dark-theme;
*/

.inovex-elements-typo {
font-family: Lato, Verdana, sans-serif;
Expand Down Expand Up @@ -91,8 +94,8 @@
@include typography-new.typo(body-s);
}
}

.inovex-elements-theme {
// Light Theme Variables (Default)
.inovex-elements-theme/*-light*/ {
--inovex-elements-white: #{new-theme.$white};
--inovex-elements-black: #{new-theme.$black};
--inovex-elements-transparent: #{new-theme.$transparent};
Expand Down Expand Up @@ -138,3 +141,23 @@
--inovex-elements-warning: #{new-theme.$warning};
--inovex-elements-warning-light: #{new-theme.$warning-light};
}

// Dark Theme Variables
.inovex-elements-theme-dark {
--inovex-elements-p-1: #48ec4a;
// ...

/*
TODO:
Continue defining dark theme colors for other categories.
*/

/* Theme Switching Documentation
* -----------------------------
* The elements package is designed to be theme-aware, supporting light and dark themes.
* The actual theme switching should be implemented in the application using this library (our next.js landingpage or storybook).
* The application can switch themes at runtime by toggling between the
* '.inovex-elements-theme-light' and '.inovex-elements-theme-dark' classes on a high-level element (like 'body').
* This allows for dynamic theme changes without the need to reload or recompile the application.
*/
}
4 changes: 3 additions & 1 deletion packages/landingpage/components/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import styles from './layout.module.scss';
import Footer from './layout/footer/footer';
import Header from './layout/header/header';
import { UiContext, UiContextType } from '../utils/context/UiContext';
import { useTheme } from '../utils/context/ThemeContext';

export default function Layout({ children }: { children: ReactNode }) {
const { isFooterHidden } = useContext(UiContext) as UiContextType;
const { theme } = useTheme();

return (
<div className="inovex-elements-typo inovex-elements-theme">
<div className={`inovex-elements-typo ${theme}`}>
<Head>
<meta
name="viewport"
Expand Down
13 changes: 12 additions & 1 deletion packages/landingpage/components/layout/header/desktop/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ import { useRouter } from 'next/router';
import styles from './navbar.module.scss';
import { Routes } from '../../../../utils/routes';
import LinkItem from '../../linkItem';
import { InoPopover } from '@elements';
import { InoPopover, InoSwitch } from '@elements';
import useTranslation from 'utils/hooks/useTranslation';
import { ContactButton } from '../../../shared/contactButton';
import { useTheme } from 'utils/context/ThemeContext';
import { inDevEnvironment } from 'utils/in-dev-mode';

const POPOVER_OFFSET = 10;

export default function Navbar() {
const router = useRouter();
const { t } = useTranslation();
const { theme, toggleTheme } = useTheme();
const isDarkMode = theme === 'inovex-elements-theme-dark';

function isRouteActive(mainRouteUrl: string, mainRouteName: string) {
const pathSplit = router.pathname.split('/');
Expand Down Expand Up @@ -59,6 +63,13 @@ export default function Navbar() {
</div>
))}
<ContactButton />
{/* TODO: add a toggle Icon with Sun & Moon icons for light and dark mode toggle */}
{inDevEnvironment && (
<InoSwitch
checked={isDarkMode}
onCheckedChange={toggleTheme}
></InoSwitch>
)}
</nav>
);
}
9 changes: 6 additions & 3 deletions packages/landingpage/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import useDefaultLocale from '../translations/useDefaultLocale';
import { useMount } from 'react-use';
import UiContextProvider from '../utils/context/UiContext';
import { VersionProvider } from '../utils/context/VersionContext';
import { ThemeProvider } from 'utils/context/ThemeContext';

function MyApp({ Component, pageProps }: AppProps) {
useEffect(() => {
Expand All @@ -28,9 +29,11 @@ function MyApp({ Component, pageProps }: AppProps) {
<UiContextProvider>
<LanguageProvider localization={pageProps.localization}>
<VersionProvider>
<Layout>
<Component {...pageProps} />
</Layout>
<ThemeProvider>
<Layout>
<Component {...pageProps} />
</Layout>
</ThemeProvider>
</VersionProvider>
</LanguageProvider>
</UiContextProvider>
Expand Down
29 changes: 29 additions & 0 deletions packages/landingpage/utils/context/ThemeContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { ReactNode, createContext, useContext, useState } from 'react';
import { inDevEnvironment } from 'utils/in-dev-mode';

const ThemeContext = createContext({
theme: 'inovex-elements-theme',
toggleTheme: () => {},
});

export const useTheme = () => useContext(ThemeContext);

export const ThemeProvider = ({ children }: { children: ReactNode }) => {
const [theme, setTheme] = useState('inovex-elements-theme');

const toggleTheme = () => {
if (!inDevEnvironment) return;

setTheme((current) =>
current === 'inovex-elements-theme'
? 'inovex-elements-theme-dark'
: 'inovex-elements-theme',
);
};

return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
1 change: 1 addition & 0 deletions packages/storybook/config/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ module.exports = {
addons: [
'@storybook/addon-essentials',
'@pxtrn/storybook-addon-docs-stencil',
'storybook-addon-themes',
],
managerEntries: ['./addons/post-current-story'],
typescript: {
Expand Down
12 changes: 12 additions & 0 deletions packages/storybook/config/preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ setStencilDocJson(docsJson);

applyPolyfills().then(() => defineCustomElements(window));

const isInDevEnvironment = process && process.env.NODE_ENV === 'development';

// Explicit order for the docs section
export const parameters = {
viewMode: 'docs',
Expand Down Expand Up @@ -58,4 +60,14 @@ export const parameters = {
],
},
},
// using storybook-addon-themes https://storybook.js.org/addons/storybook-addon-themes
...(isInDevEnvironment && {
themes: {
default: 'light',
list: [
{ name: 'light', class: 'inovex-elements-theme', color: '#ffffff' },
{ name: 'dark', class: 'inovex-elements-theme-dark', color: '#000000' },
],
},
}),
};
1 change: 1 addition & 0 deletions packages/storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"sass": "^1.49.7",
"sass-loader": "^12.6.0",
"story-description-loader": "^1.0.0",
"storybook-addon-themes": "^6.1.0",
"typescript": "^4.5.5",
"webpack": "^5.0.0"
},
Expand Down
28 changes: 16 additions & 12 deletions packages/storybook/src/stories/ino-chip/ino-chip.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,14 @@ const templateFilter = new TemplateGenerator<Components.InoChip>(
return html`
<div class="ino-chip-story">
${values.map(
(value) => html` <ino-chip
value="${value}"
selectable
@chipClicked="${(ev) => handleClick(ev.target)}"
>${value}
</ino-chip>`,
(value) => html`
<ino-chip
value="${value}"
selectable
@chipClicked="${(ev) => handleClick(ev.target)}"
>${value}
</ino-chip>
`,
)}
</div>
`;
Expand All @@ -137,12 +139,14 @@ const templateRemove = new TemplateGenerator<Components.InoChip>(
return html`
<div class="ino-chip-story">
${chips.map(
(value, index) => html` <ino-chip
value="${value}"
removable="${index !== 0}"
@chipRemoved="${(ev) => handleClick(ev.target)}"
>${value}
</ino-chip>`,
(value, index) => html`
<ino-chip
value="${value}"
removable="${index !== 0}"
@chipRemoved="${(ev) => handleClick(ev.target)}"
>${value}
</ino-chip>
`,
)}
</div>
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ export default {
},
} as Meta;

const exampleImg = html` <ino-img
slot="leading"
src="https://cdn-images-1.medium.com/max/1600/1*HP8l7LMMt7Sh5UoO1T-yLQ.png"
ratio-width="1"
ratio-height="1"
></ino-img>`;
const exampleImg = html`
<ino-img
slot="leading"
src="https://cdn-images-1.medium.com/max/1600/1*HP8l7LMMt7Sh5UoO1T-yLQ.png"
ratio-width="1"
ratio-height="1"
></ino-img>
`;

const template = new TemplateGenerator<Components.InoListItem>(
'ino-list-item',
Expand Down Expand Up @@ -95,9 +97,10 @@ const templateGraphicAndMeta = new TemplateGenerator<InoListVariants>(
<ino-list>
<ino-list-item text="Lorem ipsum dolor sit">
${args.avatar && exampleImg}
${args.checkbox && html` <ino-checkbox slot="leading"></ino-checkbox>`}
${args.meta && html`<p slot="trailing">$10.00</p>`}
${args.radio && html` <ino-radio slot="leading" selection></ino-radio>`}
${args.checkbox && html` <ino-checkbox slot="leading"></ino-checkbox> `}
${args.meta && html` <p slot="trailing">$10.00</p> `}
${args.radio &&
html` <ino-radio slot="leading" selection></ino-radio> `}
</ino-list-item>
</ino-list>
`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type InoNavItemExtended = Components.InoNavItem & {
icon: boolean;
};

const icon = html`<ino-icon icon="onboarding"></ino-icon>`; // eslint-disable-next-line no-unexpected-multiline
const icon = html` <ino-icon icon="onboarding"></ino-icon> `; // eslint-disable-next-line no-unexpected-multiline

const template = new TemplateGenerator<InoNavItemExtended>(
'ino-nav-item',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,12 @@ const templateColors = new TemplateGenerator<InoPopoverExtended>(
const idDark = 'popover-dark';
const idPrimary = 'popover-primary';

const content = html`<p style="padding: 0.5rem">
Lorem ipsum do lor sit amet, con sete tur amet ipsum do, con sete tur amet
ipsum do.
</p>`;
const content = html`
<p style="padding: 0.5rem">
Lorem ipsum do lor sit amet, con sete tur amet ipsum do, con sete tur
amet ipsum do.
</p>
`;

return html`
<ino-button id="${idLight}">Light</ino-button>
Expand Down
20 changes: 12 additions & 8 deletions packages/storybook/src/stories/ino-table/ino-table.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export default {
},
};

const tableContent = html`<tr slot="header-row"></tr>
const tableContent = html`
<tr slot="header-row"></tr>
<ino-table-header-cell
column-id="id"
sort-start="asc"
Expand Down Expand Up @@ -144,7 +145,8 @@ const tableContent = html`<tr slot="header-row"></tr>
<td>95%</td>
<td>Some information</td>
<td>Some information</td>
</tr> `;
</tr>
`;

const template = new TemplateGenerator<Components.InoTable>(
'ino-table',
Expand All @@ -157,12 +159,14 @@ const template = new TemplateGenerator<Components.InoTable>(
sticky-header="${args.stickyHeader}"
>
${args.loading
? html`<ino-progress-bar
slot="loading-indicator"
indeterminate
debounce="200"
active
></ino-progress-bar>`
? html`
<ino-progress-bar
slot="loading-indicator"
indeterminate
debounce="200"
active
></ino-progress-bar>
`
: html``}
${tableContent}
</ino-table>
Expand Down
2 changes: 1 addition & 1 deletion packages/storybook/src/stories/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export const decorateStoryWithClass = (
story: () => StoryFnHtmlReturnType,
className?: string,
): StoryFnHtmlReturnType => {
return html`<div class="${className ?? ''}">${story()}</div>`;
return html` <div class="${className ?? ''}">${story()}</div> `;
};

export const showSnackbar = (message: string) => {
Expand Down
Loading
Loading