💥(frontend) upgrade to ui-kit v2

Upgrade Docs to Ui-Kit v2 and apply new color
scheme from LaSuite design system.
This commit will probably create breaking changes if
user has custom styles applied to their docs.
This commit is contained in:
Anthony LC
2025-11-26 11:30:49 +01:00
parent 785c9b21cf
commit 29104dfe2d
110 changed files with 9537 additions and 3249 deletions

View File

@@ -1,6 +1,6 @@
import { expect, test } from '@playwright/test';
import { createDoc } from './utils-common';
import { createDoc, goToGridDoc, verifyDocName } from './utils-common';
test.describe('Left panel desktop', () => {
test.beforeEach(async ({ page }) => {
@@ -10,8 +10,12 @@ test.describe('Left panel desktop', () => {
test('checks all the elements are visible', async ({ page }) => {
await expect(page.getByTestId('left-panel-desktop')).toBeVisible();
await expect(page.getByTestId('left-panel-mobile')).toBeHidden();
await expect(page.getByTestId('home-button')).toBeVisible();
await expect(page.getByTestId('home-button')).toBeHidden();
await expect(page.getByTestId('new-doc-button')).toBeVisible();
await goToGridDoc(page);
await expect(page.getByTestId('home-button')).toBeVisible();
});
test('checks resize handle is present and functional on document page', async ({
@@ -88,6 +92,9 @@ test.describe('Left panel mobile', () => {
await expect(languageButton).not.toBeInViewport();
await expect(logoutButton).not.toBeInViewport();
const title = await goToGridDoc(page);
await verifyDocName(page, title);
await header.getByLabel('Open the header menu').click();
await expect(page.getByTestId('left-panel-mobile')).toBeInViewport();

View File

@@ -1,57 +1,25 @@
import { cunninghamConfig as tokens } from '@gouvfr-lasuite/ui-kit';
import { defaultTokens } from '@openfun/cunningham-react';
import merge from 'lodash/merge';
const customColors = {
'primary-action': '#1212FF',
'primary-bg': '#FAFAFA',
'primary-focus': '#0A76F6',
'secondary-icon': 'var(--c--theme--colors--primary-text)',
'blue-400': '#7AB1E8',
'blue-500': '#417DC4',
'blue-600': '#3558A2',
'brown-400': '#E6BE92',
'brown-500': '#BD987A',
'brown-600': '#745B47',
'cyan-400': '#34BAB5',
'cyan-500': '#009099',
'cyan-600': '#006A6F',
'gold-400': '#FFCA00',
'gold-500': '#C3992A',
'gold-600': '#695240',
'green-400': '#34CB6A',
'green-500': '#00A95F',
'green-600': '#297254',
'olive-400': '#99C221',
'olive-500': '#68A532',
'olive-600': '#447049',
'orange-400': '#FF732C',
'orange-500': '#E4794A',
'orange-600': '#755348',
'pink-400': '#FFB7AE',
'pink-500': '#E18B76',
'pink-600': '#8D533E',
'purple-400': '#CE70CC',
'purple-500': '#A558A0',
'purple-600': '#6E445A',
'yellow-400': '#D8C634',
'yellow-500': '#B7A73F',
'yellow-600': '#66673D',
// Uikit does not provide the full list of tokens.
// To be able to override correctly, we need to merge with the default tokens.
let mergedColors = merge(
defaultTokens.globals.colors,
tokens.themes.default.globals.colors,
);
mergedColors = {
...mergedColors,
'logo-1': '#2845C1',
};
tokens.themes.default.theme = {
...tokens.themes.default.theme,
tokens.themes.default.globals = {
...tokens.themes.default.globals,
...{
logo: {
src: '',
alt: '',
widthHeader: '',
widthFooter: '',
},
colors: {
...tokens.themes.default.theme.colors,
...customColors,
},
colors: mergedColors,
font: {
...tokens.themes.default.theme.font,
...tokens.themes.default.globals.font,
families: {
base: 'sans-serif',
accent: 'sans-serif',
@@ -63,39 +31,24 @@ tokens.themes.default.theme = {
tokens.themes.default.components = {
...tokens.themes.default.components,
...{
logo: {
src: '',
alt: '',
widthHeader: '',
widthFooter: '',
},
'la-gaufre': false,
'home-proconnect': false,
'image-system-filter': '',
favicon: {
ico: '/assets/favicon-light.ico',
'png-light': '/assets/favicon-light.png',
'png-dark': '/assets/favicon-dark.png',
},
button: {
...tokens.themes.default.components.button,
primary: {
...tokens.themes.default.components.button.primary,
...{
'background--disabled': 'var(--c--theme--colors--greyscale-100)',
},
disabled: 'var(--c--theme--colors--greyscale-400)',
},
},
},
};
const dsfrTheme = {
dsfr: {
theme: {
colors: {
'secondary-icon': '#C9191E',
},
logo: {
src: '/assets/logo-gouv.svg',
widthHeader: '110px',
widthFooter: '220px',
alt: 'Gouvernement Logo',
},
globals: {
font: {
families: {
base: 'Marianne, Inter, Roboto Flex Variable, sans-serif',
@@ -104,6 +57,12 @@ const dsfrTheme = {
},
},
components: {
logo: {
src: '/assets/logo-gouv.svg',
widthHeader: '110px',
widthFooter: '220px',
alt: 'Gouvernement Logo',
},
'la-gaufre': true,
'home-proconnect': true,
favicon: {
@@ -117,131 +76,296 @@ const dsfrTheme = {
const genericTheme = {
generic: {
theme: {
globals: {
colors: {
'primary-action': '#206EBD',
'primary-focus': '#1E64BF',
'primary-text': '#2E2C28',
'primary-050': '#F8F8F7',
'primary-100': '#F0EFEC',
'primary-150': '#F4F4FD',
'primary-200': '#E8E7E4',
'primary-300': '#CFCDC9',
'primary-400': '#979592',
'primary-500': '#82807D',
'primary-600': '#3F3D39',
'primary-700': '#2E2C28',
'primary-800': '#302E29',
'primary-900': '#282622',
'primary-950': '#201F1C',
'secondary-text': '#fff',
'secondary-50': '#F4F7FA',
'secondary-100': '#D7E3EE',
'secondary-200': '#B8CCE1',
'secondary-300': '#99B4D3',
'secondary-400': '#7595BE',
'secondary-500': '#5874A0',
'secondary-600': '#3A5383',
'secondary-700': '#1E3462',
'secondary-800': '#091B41',
'secondary-900': '#08183B',
'secondary-950': '#071636',
'greyscale-text': '#3C3B38',
'greyscale-000': '#fff',
'greyscale-050': '#F8F7F7',
'greyscale-100': '#F3F3F2',
'greyscale-200': '#ECEBEA',
'greyscale-250': '#E4E3E2',
'greyscale-300': '#D3D2CF',
'greyscale-350': '#eee',
'greyscale-400': '#96948E',
'greyscale-500': '#817E77',
'greyscale-600': '#6A6862',
'greyscale-700': '#3C3B38',
'greyscale-750': '#383632',
'greyscale-800': '#2D2B27',
'greyscale-900': '#262522',
'greyscale-950': '#201F1C',
'greyscale-1000': '#181714',
'success-text': '#234935',
'success-50': '#F3FBF5',
'success-100': '#E4F7EA',
'success-200': '#CAEED4',
'success-300': '#A0E0B5',
'success-400': '#6CC88C',
'success-500': '#6CC88C',
'success-600': '#358D5C',
'success-700': '#2D704B',
'success-800': '#28583F',
'success-900': '#234935',
'success-950': '#0F281B',
'info-text': '#212445',
'info-50': '#F2F6FB',
'info-100': '#E2E9F5',
'info-200': '#CCD8EE',
'info-300': '#A9C0E3',
'info-400': '#809DD4',
'info-500': '#617BC7',
'info-600': '#4A5CBF',
'info-700': '#3E49B2',
'info-800': '#353C8F',
'info-900': '#303771',
'info-950': '#212445',
'warning-text': '#D97C3A',
'warning-50': '#FDF7F1',
'warning-100': '#FBEDDC',
'warning-200': '#F5D9B9',
'warning-300': '#EDBE8C',
'warning-400': '#E2985C',
'warning-500': '#D97C3A',
'warning-600': '#C96330',
'warning-700': '#A34B32',
'warning-800': '#813B2C',
'warning-900': '#693327',
'warning-950': '#381713',
'danger-action': '#C0182A',
'danger-text': '#FFF',
'danger-050': '#FDF5F4',
'danger-100': '#FBEBE8',
'danger-200': '#F9E0DC',
'danger-300': '#F3C3BD',
'danger-400': '#E26552',
'danger-500': '#C91F00',
'danger-600': '#A71901',
'danger-700': '#562C2B',
'danger-800': '#392425',
'danger-900': '#311F20',
'danger-950': '#2A191A',
'blue-400': '#8BAECC',
'blue-500': '#567AA2',
'blue-600': '#455784',
'brown-400': '#E4C090',
'brown-500': '#BA9977',
'brown-600': '#735C45',
'cyan-400': '#5CBEC9',
'cyan-500': '#43A1B3',
'cyan-600': '#39809B',
'gold-400': '#ECBF50',
'gold-500': '#DFA038',
'gold-600': '#C17B31',
'green-400': '#5DBD9A',
'green-500': '#3AA183',
'green-600': '#2A816D',
'olive-400': '#AFD662',
'olive-500': '#90BB4B',
'olive-600': '#6E9441',
'orange-400': '#E2985C',
'orange-500': '#D97C3A',
'orange-600': '#C96330',
'pink-400': '#BE8FC8',
'pink-500': '#A563B1',
'pink-600': '#8B44A5',
'purple-400': '#BE8FC8',
'purple-500': '#A563B1',
'purple-600': '#8B44A5',
'yellow-400': '#EDC947',
'yellow-500': '#DBB13A',
'yellow-600': '#B88A34',
'brand-050': '#EEF1FA',
'brand-100': '#DDE2F5',
'brand-150': '#CED3F1',
'brand-200': '#BEC5F0',
'brand-250': '#AFB5F1',
'brand-300': '#A0A5F6',
'brand-350': '#8F94FD',
'brand-400': '#8184FC',
'brand-450': '#7576EE',
'brand-500': '#6969DF',
'brand-550': '#5E5CD0',
'brand-600': '#534FC2',
'brand-650': '#4844AD',
'brand-700': '#3E3B98',
'brand-750': '#36347D',
'brand-800': '#2D2F5F',
'brand-850': '#262848',
'brand-900': '#1C1E32',
'brand-950': '#11131F',
'gray-000': '#FFFFFF',
'gray-025': '#F8F8F9',
'gray-050': '#F0F0F3',
'gray-100': '#E2E2EA',
'gray-150': '#D3D4E0',
'gray-200': '#C5C6D5',
'gray-250': '#B7B7CB',
'gray-300': '#A9A9BF',
'gray-350': '#9C9CB2',
'gray-400': '#8F8FA4',
'gray-450': '#828297',
'gray-500': '#75758A',
'gray-550': '#69697D',
'gray-600': '#5D5D70',
'gray-650': '#515164',
'gray-700': '#454558',
'gray-750': '#3A3A4C',
'gray-800': '#2F303D',
'gray-850': '#25252F',
'gray-900': '#1B1B23',
'gray-950': '#111114',
'gray-1000': '#000000',
'info-050': '#EAF2F9',
'info-100': '#D5E4F3',
'info-150': '#BFD7F0',
'info-200': '#A7CAEE',
'info-250': '#8DBDEF',
'info-300': '#6EB0F2',
'info-350': '#50A2F5',
'info-400': '#3593F4',
'info-450': '#1185ED',
'info-500': '#0077DE',
'info-550': '#0069CF',
'info-600': '#005BC0',
'info-650': '#0D4EAA',
'info-700': '#124394',
'info-750': '#163878',
'info-800': '#192F5A',
'info-850': '#192541',
'info-900': '#141B2D',
'info-950': '#0C111C',
'success-050': '#E8F1EA',
'success-100': '#CFE4D4',
'success-150': '#BAD9C1',
'success-200': '#A2CFAD',
'success-250': '#86C597',
'success-300': '#6CBA83',
'success-350': '#4FB070',
'success-400': '#40A363',
'success-450': '#309556',
'success-500': '#1E884A',
'success-550': '#027B3E',
'success-600': '#016D31',
'success-650': '#006024',
'success-700': '#005317',
'success-750': '#0D4511',
'success-800': '#11380E',
'success-850': '#132A11',
'success-900': '#101E0F',
'success-950': '#091209',
'warning-050': '#F8F0E9',
'warning-100': '#F1E0D3',
'warning-150': '#ECD0BC',
'warning-200': '#E8C0A4',
'warning-250': '#E8AE8A',
'warning-300': '#EB9970',
'warning-350': '#E98456',
'warning-400': '#E57036',
'warning-450': '#DA5E18',
'warning-500': '#CB5000',
'warning-550': '#BC4200',
'warning-600': '#AD3300',
'warning-650': '#9E2300',
'warning-700': '#882011',
'warning-750': '#731E16',
'warning-800': '#58201A',
'warning-850': '#401D18',
'warning-900': '#2E1714',
'warning-950': '#1D0F0D',
'error-050': '#F9EFEC',
'error-100': '#F4DFD9',
'error-150': '#F0CEC6',
'error-200': '#EEBCB2',
'error-250': '#EEA99D',
'error-300': '#EF9486',
'error-350': '#F37C6E',
'error-400': '#F65F53',
'error-450': '#F0463D',
'error-500': '#E82322',
'error-550': '#D7010E',
'error-600': '#C00100',
'error-650': '#AA0000',
'error-700': '#910C06',
'error-750': '#731E16',
'error-800': '#58201A',
'error-850': '#401D18',
'error-900': '#2E1714',
'error-950': '#1D0F0D',
'red-050': '#FAEFEE',
'red-100': '#F4DEDD',
'red-150': '#F1CDCB',
'red-200': '#EFBBBA',
'red-250': '#EEA8A8',
'red-300': '#F09394',
'red-350': '#F37B7E',
'red-400': '#EF6569',
'red-450': '#E94A55',
'red-500': '#DA3B49',
'red-550': '#CA2A3C',
'red-600': '#BB1330',
'red-650': '#A90021',
'red-700': '#910A13',
'red-750': '#731E16',
'red-800': '#58201A',
'red-850': '#411D18',
'red-900': '#2E1714',
'red-950': '#1D0F0D',
'orange-050': '#F8F0E9',
'orange-100': '#F1E0D3',
'orange-150': '#ECD0BD',
'orange-200': '#EABFA6',
'orange-250': '#EBAC90',
'orange-300': '#EC9772',
'orange-350': '#E5845A',
'orange-400': '#D6774D',
'orange-450': '#C86A40',
'orange-500': '#B95D33',
'orange-550': '#AB5025',
'orange-600': '#9D4315',
'orange-650': '#8F3600',
'orange-700': '#812900',
'orange-750': '#6C2511',
'orange-800': '#572017',
'orange-850': '#401D18',
'orange-900': '#2E1714',
'orange-950': '#1D0F0D',
'brown-050': '#F6F0E8',
'brown-100': '#F1E0D3',
'brown-150': '#EBD0BA',
'brown-200': '#E2C0A6',
'brown-250': '#D4B398',
'brown-300': '#C6A58B',
'brown-350': '#B8987E',
'brown-400': '#AA8B71',
'brown-450': '#9D7E65',
'brown-500': '#8F7158',
'brown-550': '#82654C',
'brown-600': '#765841',
'brown-650': '#694C35',
'brown-700': '#5D412A',
'brown-750': '#51361E',
'brown-800': '#452A13',
'brown-850': '#392008',
'brown-900': '#29180A',
'brown-950': '#1B0F08',
'yellow-050': '#F3F0E7',
'yellow-100': '#E9E2CF',
'yellow-150': '#E1D4B7',
'yellow-200': '#D9C599',
'yellow-250': '#D2B677',
'yellow-300': '#CAA756',
'yellow-350': '#C2972E',
'yellow-400': '#B98900',
'yellow-450': '#AB7B00',
'yellow-500': '#9D6E00',
'yellow-550': '#916100',
'yellow-600': '#855400',
'yellow-650': '#784700',
'yellow-700': '#6C3A00',
'yellow-750': '#5F2E00',
'yellow-800': '#512302',
'yellow-850': '#3E1D10',
'yellow-900': '#2D1711',
'yellow-950': '#1D0F0D',
'green-050': '#E6F1E9',
'green-100': '#CFE4D5',
'green-150': '#B8D8C1',
'green-200': '#A0CFAE',
'green-250': '#84C59A',
'green-300': '#65BA86',
'green-350': '#45B173',
'green-400': '#23A562',
'green-450': '#029755',
'green-500': '#008948',
'green-550': '#017B3B',
'green-600': '#006E2E',
'green-650': '#006022',
'green-700': '#005314',
'green-750': '#0D4510',
'green-800': '#11380E',
'green-850': '#132A11',
'green-900': '#101E0F',
'green-950': '#091209',
'blue1-050': '#EBF1F9',
'blue1-100': '#D6E4F4',
'blue1-150': '#C1D7F0',
'blue1-200': '#AACAEF',
'blue1-250': '#8FBCEF',
'blue1-300': '#7CAFEB',
'blue1-350': '#68A1E4',
'blue1-400': '#5B94D6',
'blue1-450': '#4E86C7',
'blue1-500': '#4279B9',
'blue1-550': '#356CAC',
'blue1-600': '#28609E',
'blue1-650': '#1B5390',
'blue1-700': '#0B4783',
'blue1-750': '#0F3C6E',
'blue1-800': '#133059',
'blue1-850': '#152641',
'blue1-900': '#121C2D',
'blue1-950': '#0B111C',
'blue2-050': '#E7F3F4',
'blue2-100': '#CEE7E9',
'blue2-150': '#B2DCE0',
'blue2-200': '#91D1D7',
'blue2-250': '#68C7D0',
'blue2-300': '#43BBC5',
'blue2-350': '#00AFBA',
'blue2-400': '#01A0AA',
'blue2-450': '#00929D',
'blue2-500': '#00848F',
'blue2-550': '#007682',
'blue2-600': '#016874',
'blue2-650': '#005B67',
'blue2-700': '#004E5A',
'blue2-750': '#00424E',
'blue2-800': '#003642',
'blue2-850': '#002A38',
'blue2-900': '#061E28',
'blue2-950': '#071219',
'purple-050': '#F7F0F6',
'purple-100': '#EEE0EE',
'purple-150': '#E7D1E7',
'purple-200': '#DBBFE4',
'purple-250': '#D3AEE2',
'purple-300': '#CB99E1',
'purple-350': '#C188D9',
'purple-400': '#B47BCB',
'purple-450': '#A66EBD',
'purple-500': '#9961AF',
'purple-550': '#8B55A1',
'purple-600': '#7E4894',
'purple-650': '#723C87',
'purple-700': '#633376',
'purple-750': '#552A65',
'purple-800': '#452551',
'purple-850': '#35213D',
'purple-900': '#261A2C',
'purple-950': '#17111C',
'pink-050': '#F8EFF4',
'pink-100': '#F0DFEA',
'pink-150': '#EACEDF',
'pink-200': '#E9BBD1',
'pink-250': '#E9A7C2',
'pink-300': '#E095B4',
'pink-350': '#D685A8',
'pink-400': '#C7799B',
'pink-450': '#B86C8D',
'pink-500': '#AA5F80',
'pink-550': '#9C5374',
'pink-600': '#8E4767',
'pink-650': '#813B5B',
'pink-700': '#732E4F',
'pink-750': '#632643',
'pink-800': '#521F38',
'pink-850': '#3E1C2B',
'pink-900': '#2D171F',
'pink-950': '#1C0E12',
},
font: {
families: {
@@ -250,18 +374,6 @@ const genericTheme = {
},
},
},
components: {
button: {
primary: {
background: {
'color-hover': 'var(--c--theme--colors--primary-focus)',
'color-active': 'var(--c--theme--colors--primary-focus)',
'color-focus': 'var(--c--theme--colors--primary-focus)',
},
},
},
'image-system-filter': 'saturate(0.2)',
},
},
};

View File

@@ -35,11 +35,11 @@
"@fontsource-variable/material-symbols-outlined": "5.2.28",
"@fontsource/material-icons": "5.2.7",
"@gouvfr-lasuite/integration": "1.0.3",
"@gouvfr-lasuite/ui-kit": "0.16.2",
"@gouvfr-lasuite/ui-kit": "0.18.0",
"@hocuspocus/provider": "3.4.0",
"@mantine/core": "8.3.6",
"@mantine/hooks": "8.3.6",
"@openfun/cunningham-react": "3.2.3",
"@openfun/cunningham-react": "4.0.0",
"@react-pdf/renderer": "4.3.1",
"@sentry/nextjs": "10.27.0",
"@tanstack/react-query": "5.90.6",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -14,6 +14,7 @@ export interface BoxProps {
as?: HTMLElementType;
$align?: CSSProperties['alignItems'];
$background?: CSSProperties['background'];
$border?: CSSProperties['border'];
$color?: CSSProperties['color'];
$css?: string | RuleSet<object>;
$cursor?: CSSProperties['cursor'];
@@ -36,41 +37,34 @@ export interface BoxProps {
$position?: CSSProperties['position'];
$radius?: CSSProperties['borderRadius'];
$shrink?: CSSProperties['flexShrink'];
$transition?: CSSProperties['transition'];
$width?: CSSProperties['width'];
$zIndex?: CSSProperties['zIndex'];
$wrap?: CSSProperties['flexWrap'];
// Theming props
$layer?: 'background' | 'content' | 'border';
$theme?:
| 'primary'
| 'primary-text'
| 'secondary'
| 'secondary-text'
| 'brand'
| 'error'
| 'gray'
| 'info'
| 'success'
| 'warning'
| 'danger'
| 'greyscale';
$transition?: CSSProperties['transition'];
$variation?:
| 'text'
| '000'
| '100'
| '200'
| '300'
| '400'
| '500'
| '600'
| '700'
| '800'
| '900'
| '1000';
$width?: CSSProperties['width'];
$wrap?: CSSProperties['flexWrap'];
$zIndex?: CSSProperties['zIndex'];
| 'neutral'
| 'contextual'
| 'disabled'
| (string & {});
$scope?: 'surface' | 'semantic' | 'palette' | (string & {});
$variation?: 'primary' | 'secondary' | 'tertiary' | (string & {});
$withThemeBG?: boolean;
$withThemeBorder?: boolean;
$withThemeInherited?: boolean;
}
export type BoxType = ComponentPropsWithRef<typeof Box>;
export const Box = styled('div')<BoxProps>`
${({ $align }) => $align && `align-items: ${$align};`}
${({ $background }) => $background && `background: ${$background};`}
${({ $color }) => $color && `color: ${$color};`}
${({ $cursor }) => $cursor && `cursor: ${$cursor};`}
${({ $direction }) => `flex-direction: ${$direction || 'column'};`}
${({ $display, as }) =>
@@ -80,9 +74,9 @@ export const Box = styled('div')<BoxProps>`
${({ $height }) => $height && `height: ${$height};`}
${({ $hasTransition }) =>
$hasTransition && $hasTransition === 'slow'
? `transition: all 0.5s ease-in-out;`
? `transition: all 0.5s var(--c--globals--transitions--ease-out);`
: $hasTransition
? `transition: all 0.3s ease-in-out;`
? `transition: all var(--c--globals--transitions--duration) var(--c--globals--transitions--ease-out);`
: ''}
${({ $justify }) => $justify && `justify-content: ${$justify};`}
${({ $margin }) => $margin && stylesMargin($margin)}
@@ -96,11 +90,85 @@ export const Box = styled('div')<BoxProps>`
${({ $position }) => $position && `position: ${$position};`}
${({ $radius }) => $radius && `border-radius: ${$radius};`}
${({ $shrink }) => $shrink && `flex-shrink: ${$shrink};`}
${({ $theme, $variation }) => {
if (!$theme || !$variation) {
${({
$layer = 'border',
$theme = 'brand',
$variation = 'primary',
$scope = 'semantic',
$border,
$withThemeBorder,
$withThemeInherited,
}) => {
if ($border) {
return `border: ${$border};`;
}
if (!$layer || !$scope || !$theme || !$withThemeBorder) {
return '';
}
return `color: var(--c--theme--colors--${$theme}-${$variation});`;
if ($withThemeInherited) {
return `border: inherit;`;
}
return `border: 1px solid var(--c--contextuals--${$layer}--${$scope}${$theme ? `--${$theme}` : ''}${$variation ? `--${$variation}` : ''});`;
}}
${({
$layer = 'background',
$theme = 'brand',
$variation = 'primary',
$scope = 'semantic',
$background,
$withThemeBG,
$withThemeInherited,
}) => {
if ($background) {
return `background: ${$background};`;
}
if (!$layer || !$scope || !$theme || !$withThemeBG) {
return '';
}
if ($withThemeInherited) {
return `background: inherit;`;
}
return `background: var(--c--contextuals--${$layer}--${$scope}${$theme ? `--${$theme}` : ''}${$variation ? `--${$variation}` : ''});`;
}}
${({
$layer = 'content',
$theme = 'neutral',
$variation = 'primary',
$scope = 'semantic',
$color,
$withThemeBG,
$withThemeInherited,
}) => {
if ($color) {
return `color: ${$color};`;
}
if (!$layer || !$scope) {
return '';
}
// There is a special case when primary with background
if (
$withThemeBG &&
$layer === 'content' &&
$scope === 'semantic' &&
$variation === 'primary' &&
$theme
) {
$variation = `on-${$theme}`;
}
if ($withThemeInherited) {
return `color: inherit;`;
}
return `color: var(--c--contextuals--${$layer}--${$scope}${$theme ? `--${$theme}` : ''}${$variation ? `--${$variation}` : ''});`;
}}
${({ $transition }) => $transition && `transition: ${$transition};`}
${({ $width }) => $width && `width: ${$width};`}
@@ -121,7 +189,7 @@ export const Box = styled('div')<BoxProps>`
return (
effect &&
`
transition: all 0.3s ease-in-out;
transition: all var(--c--globals--transitions--duration) var(--c--globals--transitions--ease-out);
${effect}
`
);

View File

@@ -24,8 +24,8 @@ export type BoxButtonType = BoxType & {
*/
const BoxButton = forwardRef<HTMLDivElement, BoxButtonType>(
({ $css, ...props }, ref) => {
const theme = props.$theme || 'greyscale';
const variation = props.$variation || '400';
const theme = props.$theme || 'gray';
const variation = props.$variation || 'primary';
return (
<Box
@@ -40,15 +40,14 @@ const BoxButton = forwardRef<HTMLDivElement, BoxButtonType>(
border: none;
outline: none;
font-family: inherit;
color: ${props.disabled
? `var(--c--theme--colors--${theme}-400) !important`
: `inherit`};
color: ${props.disabled &&
`var(--c--contextuals--content--semantic--disabled--primary)`};
&:focus-visible {
transition: none;
outline: 2px solid var(--c--theme--colors--${theme}-${variation});
outline: 2px solid
var(--c--contextuals--content--semantic--${theme}--${variation});
border-radius: 1px;
outline-offset: 4px;
outline-offset: var(--c--globals--spacings--st);
}
${$css || ''}
`}

View File

@@ -1,27 +1,23 @@
import { PropsWithChildren } from 'react';
import { css } from 'styled-components';
import { useCunninghamTheme } from '@/cunningham';
import { Box, BoxType } from '.';
export const Card = ({
children,
className,
$css,
...props
}: PropsWithChildren<BoxType>) => {
const { colorsTokens } = useCunninghamTheme();
return (
<Box
role="region"
$withThemeBG
$withThemeBorder
className={`--docs--card ${className || ''}`}
$background="white"
$radius="4px"
$css={css`
border: 1px solid ${colorsTokens['greyscale-200']};
${$css}
`}
$radius="var(--c--globals--spacings--st)"
$padding={{ horizontal: 'xs', vertical: '3xs' }}
$scope={props.$theme ? props.$scope || 'semantic' : 'surface'}
$theme={props.$theme || 'primary'}
$variation={props.$theme ? props.$variation || 'tertiary' : ''}
{...props}
>
{children}

View File

@@ -14,10 +14,11 @@ import { BoxProps } from './Box';
const StyledPopover = styled(Popover)`
background-color: white;
border-radius: 4px;
box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.1);
border: 1px solid #dddddd;
transition: opacity 0.2s ease-in-out;
border-radius: var(--c--globals--spacings--st);
box-shadow: 0 0 6px 0 rgba(0, 0, 145, 0.1);
border: 1px solid var(--c--contextuals--border--surface--primary);
transition: opacity var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
`;
interface StyledButtonProps {
@@ -28,18 +29,22 @@ const StyledButton = styled(Button)<StyledButtonProps>`
border: none;
background: none;
outline: none;
font-weight: 500;
font-size: 0.938rem;
padding: 0;
border-radius: 4px;
font-weight: var(--c--components--button--font-weight);
font-size: var(--c--components--button--medium-font-size);
padding: var(--c--globals--spacings--0);
border-radius: var(--c--globals--spacings--st);
color: var(--c--contextuals--content--semantic--brand--tertiary);
&:hover {
background-color: var(
--c--components--button--primary-text--background--color-hover
--c--contextuals--background--semantic--contextual--primary
);
}
&:focus-visible {
box-shadow: 0 0 0 2px var(--c--theme--colors--primary-400);
border-radius: 4px;
box-shadow: 0 0 0 2px var(--c--globals--colors--brand-400);
background-color: var(
--c--contextuals--background--semantic--brand--tertiary-hover
);
border-radius: var(--c--globals--spacings--st);
}
${({ $css }) => $css};
`;

View File

@@ -13,7 +13,7 @@ export const Icon = ({
iconName,
disabled,
variant = 'outlined',
$variation = 'text',
$theme = 'neutral',
...textProps
}: IconProps) => {
const hasLabel = 'aria-label' in textProps || 'aria-labelledby' in textProps;
@@ -28,7 +28,7 @@ export const Icon = ({
'material-icons': variant === 'outlined',
'material-symbols-outlined': variant === 'symbols-outlined',
})}
$variation={disabled ? '300' : $variation}
$theme={disabled ? 'disabled' : $theme}
aria-disabled={disabled}
{...textProps}
>

View File

@@ -39,7 +39,8 @@ export const InfiniteScroll = ({
{!isLoading && hasMore && (
<Button
onClick={() => void next()}
color="primary-text"
color="brand"
variant="bordered"
icon={<Icon iconName="arrow_downward" />}
>
{buttonLabel ?? t('Load more')}

View File

@@ -24,12 +24,12 @@ export const LoadMoreText = ({
className="--docs--load-more"
>
<Icon
$theme="primary"
$variation="800"
$theme="brand"
$variation="secondary"
iconName="arrow_downward"
$size="md"
/>
<Text $theme="primary" $variation="800">
<Text $theme="brand" $variation="secondary">
{t('Load more')}
</Text>
</Box>

View File

@@ -5,7 +5,7 @@ import { tokens } from '@/cunningham';
import { Box, BoxProps } from './Box';
const { sizes } = tokens.themes.default.theme.font;
const { sizes } = tokens.themes.default.globals.font;
type TextSizes = keyof typeof sizes;
export interface TextProps extends BoxProps {
@@ -27,24 +27,14 @@ export const TextStyled = styled(Box)<TextProps>`
${({ $size }) =>
$size &&
`font-size: ${$size in sizes ? sizes[$size as TextSizes] : $size};`}
${({ $color }) => $color && `color: ${$color};`}
${({ $ellipsis }) =>
$ellipsis &&
`white-space: nowrap; overflow: hidden; text-overflow: ellipsis;`}
`;
const Text = forwardRef<HTMLElement, ComponentPropsWithRef<typeof TextStyled>>(
({ className, ...props }, ref) => {
return (
<TextStyled
ref={ref}
as="span"
$theme="greyscale"
$variation="text"
className={className}
{...props}
/>
);
(props, ref) => {
return <TextStyled ref={ref} as="span" {...props} />;
},
);

View File

@@ -7,7 +7,7 @@ import { Box, Text, TextType } from '@/components';
const AlertStyled = styled(Alert)`
& .c__button--tertiary:hover {
background-color: var(--c--theme--colors--greyscale-200);
background-color: var(--c--globals--colors--gray-200);
}
`;
@@ -54,8 +54,7 @@ export const TextOnlyErrors = ({
causes.map((cause, i) => (
<Text
key={`causes-${i}`}
$theme="danger"
$variation="600"
$theme="error"
$textAlign="center"
{...textProps}
>
@@ -64,12 +63,7 @@ export const TextOnlyErrors = ({
))}
{!causes && (
<Text
$theme="danger"
$variation="600"
$textAlign="center"
{...textProps}
>
<Text $theme="error" $textAlign="center" {...textProps}>
{defaultMessage || t('Something bad happens, please retry.')}
</Text>
)}

View File

@@ -124,18 +124,19 @@ export const DropdownMenu = ({
>
<Box>{children}</Box>
<Icon
$variation="600"
$css={
arrowCss ??
css`
color: var(--c--theme--colors--primary-600);
color: var(--c--globals--colors--brand-600);
`
}
iconName={isOpen ? 'arrow_drop_up' : 'arrow_drop_down'}
/>
</Box>
) : (
<Box ref={blockButtonRef}>{children}</Box>
<Box ref={blockButtonRef} $color="inherit">
{children}
</Box>
)
}
>
@@ -147,7 +148,6 @@ export const DropdownMenu = ({
>
{topMessage && (
<Text
$variation="700"
$wrap="wrap"
$size="xs"
$weight="bold"
@@ -186,8 +186,8 @@ export const DropdownMenu = ({
key={option.label}
$align="center"
$justify="space-between"
$background={colorsTokens['greyscale-000']}
$color={colorsTokens['primary-600']}
$background={colorsTokens['gray-000']}
$color={colorsTokens['brand-600']}
$padding={{ vertical: 'xs', horizontal: 'base' }}
$width="100%"
$gap={spacingsTokens['base']}
@@ -200,30 +200,39 @@ export const DropdownMenu = ({
`}
${index === options.length - 1 &&
css`
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom-left-radius: var(--c--globals--spacings--st);
border-bottom-right-radius: var(--c--globals--spacings--st);
`}
font-size: var(--c--theme--font--sizes--sm);
color: var(--c--theme--colors--greyscale-1000);
font-weight: 500;
font-size: var(--c--globals--font--sizes--sm);
color: var(--c--globals--colors--gray-1000);
font-weight: var(--c--globals--font--weights--medium);
cursor: ${isDisabled ? 'not-allowed' : 'pointer'};
user-select: none;
&:hover {
background-color: var(--c--theme--colors--greyscale-050);
background-color: var(
--c--contextuals--background--semantic--contextual--primary
);
}
&:focus-visible {
outline: 2px solid var(--c--theme--colors--primary-400);
outline: 2px solid var(--c--globals--colors--brand-400);
outline-offset: -2px;
background-color: var(--c--theme--colors--greyscale-050);
background-color: var(
--c--contextuals--background--semantic--contextual--primary
);
}
${isFocused &&
/**
* TODO: This part seems to have a problem with DocToolBox
*/
/* ${isFocused &&
css`
outline-offset: -2px;
background-color: var(--c--theme--colors--greyscale-050);
`}
background-color: var(
--c--contextuals--background--semantic--contextual--primary
);
`} */
`}
>
<Box
@@ -234,8 +243,8 @@ export const DropdownMenu = ({
{option.icon && typeof option.icon === 'string' && (
<Icon
$size="20px"
$theme="greyscale"
$variation={isDisabled ? '400' : '1000'}
$theme="gray"
$variation={isDisabled ? 'tertiary' : 'primary'}
iconName={option.icon}
aria-hidden="true"
/>
@@ -243,7 +252,7 @@ export const DropdownMenu = ({
{option.icon &&
typeof option.icon !== 'string' &&
option.icon}
<Text $variation={isDisabled ? '400' : '1000'}>
<Text $variation={isDisabled ? 'tertiary' : 'primary'}>
{option.label}
</Text>
</Box>
@@ -252,7 +261,7 @@ export const DropdownMenu = ({
<Icon
iconName="check"
$size="20px"
$theme="greyscale"
$theme="gray"
aria-hidden="true"
/>
)}

View File

@@ -33,32 +33,27 @@ export const FilterDropdown = ({
<Box
$css={css`
border: 1px solid
${selectedOption
? 'var(--c--theme--colors--primary-500)'
: 'var(--c--theme--colors--greyscale-250)'};
border-radius: 4px;
background-color: ${selectedOption
? 'var(--c--theme--colors--primary-100)'
: 'var(--c--theme--colors--greyscale-000)'};
gap: var(--c--theme--spacings--2xs);
padding: var(--c--theme--spacings--2xs) var(--c--theme--spacings--xs);
var(--c--contextuals--border--semantic--neutral--tertiary);
border-radius: var(--c--globals--spacings--st);
background-color: var(
--c--contextuals--background--semantic--neutral--tertiary
);
gap: var(--c--globals--spacings--2xs);
padding: var(--c--globals--spacings--2xs)
var(--c--globals--spacings--xs);
`}
color="secondary"
$direction="row"
$align="center"
>
<Text
$weight={400}
$variation={selectedOption ? '800' : '600'}
$theme={selectedOption ? 'primary' : 'greyscale'}
>
<Text $weight={400} $variation="tertiary" $theme="neutral">
{selectedOption?.label ?? options[0].label}
</Text>
<Icon
$size="16px"
$size="s"
iconName="keyboard_arrow_down"
$variation={selectedOption ? '800' : '600'}
$theme={selectedOption ? 'primary' : 'greyscale'}
$variation="tertiary"
$theme="neutral"
/>
</Box>
</DropdownMenu>

View File

@@ -38,7 +38,6 @@ export const AlertModal = ({
$margin="0"
id="alert-modal-title"
$align="flex-start"
$variation="1000"
>
{title}
</Text>
@@ -47,7 +46,7 @@ export const AlertModal = ({
<>
<Button
aria-label={`${t('Cancel')} - ${title}`}
color="secondary"
variant="secondary"
fullWidth
onClick={() => onClose()}
>
@@ -55,7 +54,7 @@ export const AlertModal = ({
</Button>
<Button
aria-label={confirmLabel ?? t('Confirm')}
color="danger"
color="error"
onClick={onConfirm}
>
{confirmLabel ?? t('Confirm')}
@@ -65,7 +64,7 @@ export const AlertModal = ({
>
<Box className="--docs--alert-modal">
<Box>
<Text $variation="600" as="p">
<Text $variation="secondary" as="p">
{description}
</Text>
</Box>

View File

@@ -1,18 +1,21 @@
import { Button, type ButtonProps } from '@openfun/cunningham-react';
import React from 'react';
import { Box } from '@/components';
import { Icon } from '@/components';
export const ButtonCloseModal = (props: ButtonProps) => {
return (
<Button
type="button"
size="small"
color="primary-text"
color="brand"
variant="tertiary"
icon={
<Box as="span" aria-hidden="true" className="material-icons-filled">
close
</Box>
<Icon
$withThemeInherited
iconName="close"
className="material-icons-filled"
/>
}
{...props}
/>

View File

@@ -59,11 +59,7 @@ export const QuickSearchGroup = <T,>({
);
})}
{group.emptyString && group.elements.length === 0 && (
<Text
$variation="500"
$margin={{ left: '2xs', bottom: '3xs' }}
$size="sm"
>
<Text $margin={{ left: '2xs', bottom: '3xs' }} $size="sm">
{group.emptyString}
</Text>
)}

View File

@@ -53,7 +53,7 @@ export const QuickSearchInput = ({
$padding={{ horizontal: 'base', vertical: 'sm' }}
>
{!loading && (
<Icon iconName="search" $variation="600" aria-hidden="true" />
<Icon iconName="search" $variation="secondary" aria-hidden="true" />
)}
{loading && (
<div>

View File

@@ -19,25 +19,25 @@ export const QuickSearchStyle = createGlobalStyle`
border: none;
width: 100%;
font-size: 17px;
padding: 8px;
padding: var(--c--globals--spacings--xs);
background: white;
outline: none;
color: var(--c--theme--colors--greyscale-1000);
border-radius: 0;
color: var(--c--globals--colors--gray-1000);
border-radius: var(--c--globals--spacings--0);
&::placeholder {
color: var(--c--theme--colors--greyscale-500);
color: var(--c--globals--colors--gray-500);
}
}
[cmdk-item] {
content-visibility: auto;
cursor: pointer;
border-radius: var(--c--theme--spacings--xs);
font-size: 14px;
border-radius: var(--c--globals--spacings--xs);
font-size: var(--c--globals--font--sizes--sm);
display: flex;
align-items: center;
gap: 8px;
gap: var(--c--globals--spacings--xs);
user-select: none;
will-change: background, color;
transition: all 150ms ease;
@@ -49,19 +49,19 @@ export const QuickSearchStyle = createGlobalStyle`
&:hover,
&[data-selected='true'] {
background: var(--c--theme--colors--greyscale-100);
background: var(--c--contextuals--background--semantic--contextual--primary);
.show-right-on-focus {
opacity: 1;
}
}
&[data-disabled='true'] {
color: var(--c--theme--colors--greyscale-500);
color: var(--c--globals--colors--gray-500);
cursor: not-allowed;
}
& + [cmdk-item] {
margin-top: 4px;
margin-top: var(--c--globals--spacings--st);
}
}
@@ -79,11 +79,11 @@ export const QuickSearchStyle = createGlobalStyle`
kbd {
font-size: 12px;
min-width: 20px;
padding: 4px;
padding: var(--c--globals--spacings--st);
height: 20px;
border-radius: 4px;
border-radius: var(--c--globals--spacings--st);
color: white;
background: var(--c--theme--colors--greyscale-500);
background: var(--c--globals--colors--gray-500);
display: inline-flex;
align-items: center;
justify-content: center;
@@ -94,23 +94,23 @@ export const QuickSearchStyle = createGlobalStyle`
[cmdk-separator] {
height: 1px;
width: 100%;
background: var(--c--theme--colors--greyscale-500);
margin: 4px 0;
background: var(--c--globals--colors--gray-500);
margin: var(--c--globals--spacings--st) 0;
}
*:not([hidden]) + [cmdk-group] {
margin-top: 8px;
margin-top: var(--c--globals--spacings--xs);
}
[cmdk-group-heading] {
user-select: none;
font-size: var(--c--theme--font--sizes--sm);
color: var(--c--theme--colors--greyscale-700);
font-size: var(--c--globals--font--sizes--sm);
color: var(--c--globals--colors--gray-700);
font-weight: bold;
display: flex;
align-items: center;
margin-bottom: var(--c--theme--spacings--xs);
margin-bottom: var(--c--globals--spacings--xs);
}
[cmdk-empty] {
@@ -128,9 +128,9 @@ export const QuickSearchStyle = createGlobalStyle`
}
.c__modal__title {
font-size: var(--c--theme--font--sizes--xs);
padding: var(--c--theme--spacings--base);
margin-bottom: 0;
font-size: var(--c--globals--font--sizes--xs);
padding: var(--c--globals--spacings--base);
margin-bottom: var(--c--globals--spacings--0);
}
}
`;

View File

@@ -1,26 +1,16 @@
import { useCunninghamTheme } from '@/cunningham';
import { Spacings } from '@/utils';
import { Box } from '../Box';
export enum SeparatorVariant {
LIGHT = 'light',
DARK = 'dark',
}
type Props = {
variant?: SeparatorVariant;
$withPadding?: boolean;
customPadding?: Spacings;
};
export const HorizontalSeparator = ({
variant = SeparatorVariant.LIGHT,
$withPadding = true,
customPadding,
}: Props) => {
const { colorsTokens } = useCunninghamTheme();
const padding = $withPadding
? (customPadding ?? 'base')
: ('none' as Spacings);
@@ -30,11 +20,7 @@ export const HorizontalSeparator = ({
$height="1px"
$width="100%"
$margin={{ vertical: padding }}
$background={
variant === SeparatorVariant.DARK
? '#e5e5e533'
: colorsTokens['greyscale-100']
}
$background="var(--c--contextuals--border--surface--primary)"
className="--docs--horizontal-separator"
/>
);

View File

@@ -13,7 +13,8 @@ export const SeparatedSection = ({
showSeparator = true,
children,
}: PropsWithChildren<Props>) => {
const { colorsTokens, spacingsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
return (
<Box
$css={css`
@@ -21,7 +22,8 @@ export const SeparatedSection = ({
padding: ${spacingsTokens['sm']} 0;
${showSeparator &&
css`
border-bottom: 1px solid ${colorsTokens['greyscale-200']};
border-bottom: 1px solid
var(--c--contextuals--border--surface--primary);
`}
`}
>

View File

@@ -2,13 +2,13 @@ import { useCunninghamTheme } from '../useCunninghamTheme';
describe('<useCunninghamTheme />', () => {
it('has the logo correctly set', () => {
expect(useCunninghamTheme.getState().themeTokens.logo?.src).toBe('');
expect(useCunninghamTheme.getState().componentTokens.logo?.src).toBe('');
// Change theme
useCunninghamTheme.getState().setTheme('dsfr');
const { themeTokens } = useCunninghamTheme.getState();
const logo = themeTokens.logo;
const { componentTokens } = useCunninghamTheme.getState();
const logo = componentTokens.logo;
expect(logo?.src).toBe('/assets/logo-gouv.svg');
expect(logo?.widthHeader).toBe('110px');
expect(logo?.widthFooter).toBe('220px');

View File

@@ -26,7 +26,7 @@
* Select
**/
--c--components--forms-select--value-color--disabled: var(
--c--theme--colors--greyscale-400
--c--globals--colors--gray-400
);
/**
@@ -44,6 +44,14 @@
contain: content;
}
.c__button:disabled {
cursor: unset;
}
.c__button:focus-visible {
outline: none;
}
.c__button--medium {
min-height: var(--c--components--button--medium-height);
height: auto;
@@ -60,14 +68,11 @@
* Tooltip
*/
.c__tooltip {
padding: 4px 6px;
padding: var(--c--globals--font--sizes--sm) var(--c--globals--spacings--xxs);
}
/**
* Image System
*/
.c__image-system-filter {
filter: var(--c--components--image-system-filter);
.c__tooltip .react-aria-OverlayArrow svg {
display: none;
}
/**

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -5,21 +5,23 @@ import { tokens } from './cunningham-tokens';
type Tokens = typeof tokens.themes.default &
Partial<(typeof tokens.themes)[keyof typeof tokens.themes]>;
type ColorsTokens = Tokens['theme']['colors'];
type FontSizesTokens = Tokens['theme']['font']['sizes'];
type SpacingsTokens = Tokens['theme']['spacings'];
type ColorsTokens = Tokens['globals']['colors'];
type FontSizesTokens = Tokens['globals']['font']['sizes'];
type SpacingsTokens = Tokens['globals']['spacings'];
type ComponentTokens = Tokens['components'];
type ContextualTokens = Tokens['contextuals'];
export type Theme = keyof typeof tokens.themes;
interface ThemeStore {
colorsTokens: Partial<ColorsTokens>;
componentTokens: ComponentTokens;
contextualTokens: ContextualTokens;
currentTokens: Partial<Tokens>;
fontSizesTokens: Partial<FontSizesTokens>;
setTheme: (theme: Theme) => void;
spacingsTokens: Partial<SpacingsTokens>;
theme: Theme;
themeTokens: Partial<Tokens['theme']>;
themeTokens: Partial<Tokens['globals']>;
}
const getMergedTokens = (theme: Theme) => {
@@ -30,14 +32,15 @@ const DEFAULT_THEME: Theme = 'generic';
const defaultTokens = getMergedTokens(DEFAULT_THEME);
const initialState: ThemeStore = {
colorsTokens: defaultTokens.theme.colors,
colorsTokens: defaultTokens.globals.colors,
componentTokens: defaultTokens.components,
contextualTokens: defaultTokens.contextuals,
currentTokens: tokens.themes[DEFAULT_THEME] as Partial<Tokens>,
fontSizesTokens: defaultTokens.theme.font.sizes,
fontSizesTokens: defaultTokens.globals.font.sizes,
setTheme: () => {},
spacingsTokens: defaultTokens.theme.spacings,
spacingsTokens: defaultTokens.globals.spacings,
theme: DEFAULT_THEME,
themeTokens: defaultTokens.theme,
themeTokens: defaultTokens.globals,
};
export const useCunninghamTheme = create<ThemeStore>((set) => ({
@@ -46,13 +49,14 @@ export const useCunninghamTheme = create<ThemeStore>((set) => ({
const newTokens = getMergedTokens(theme);
set({
colorsTokens: newTokens.theme.colors,
colorsTokens: newTokens.globals.colors,
componentTokens: newTokens.components,
contextualTokens: newTokens.contextuals,
currentTokens: tokens.themes[theme] as Partial<Tokens>,
fontSizesTokens: newTokens.theme.font.sizes,
spacingsTokens: newTokens.theme.spacings,
fontSizesTokens: newTokens.globals.font.sizes,
spacingsTokens: newTokens.globals.spacings,
theme,
themeTokens: newTokens.theme,
themeTokens: newTokens.globals,
});
},
}));

View File

@@ -18,7 +18,8 @@ export const ButtonLogin = () => {
return (
<Button
onClick={() => gotoLogin()}
color="primary-text"
color="brand"
variant="tertiary"
aria-label={t('Login')}
className="--docs--button-login"
>
@@ -31,14 +32,15 @@ export const ButtonLogin = () => {
<Box
$css={css`
.--docs--button-logout:focus-visible {
box-shadow: 0 0 0 2px ${colorsTokens['primary-400']} !important;
border-radius: 4px;
box-shadow: 0 0 0 2px ${colorsTokens['brand-400']} !important;
border-radius: var(--c--globals--spacings--st);
}
`}
>
<Button
onClick={gotoLogout}
color="primary-text"
color="brand"
variant="tertiary"
aria-label={t('Logout')}
className="--docs--button-logout"
>
@@ -56,9 +58,13 @@ export const ProConnectButton = () => {
onClick={() => gotoLogin()}
aria-label={t('Proconnect Login')}
$css={css`
background-color: var(--c--theme--colors--primary-text);
background-color: var(
--c--contextuals--background--semantic--brand--primary
);
&:hover {
background-color: var(--c--theme--colors--primary-action);
background-color: var(
--c--contextuals--background--semantic--brand--primary-hover
);
}
`}
$radius="4px"

View File

@@ -4,15 +4,12 @@ import { tokens } from '@/cunningham';
import { AvatarSvg } from './AvatarSvg';
const colors = tokens.themes.default.theme.colors;
const colors = tokens.themes.default.globals.colors;
const avatarsColors = [
colors['blue-500'],
colors['blue-1-500'],
colors['brown-500'],
colors['cyan-500'],
colors['gold-500'],
colors['green-500'],
colors['olive-500'],
colors['orange-500'],
colors['pink-500'],
colors['purple-500'],

View File

@@ -91,7 +91,7 @@ export function MarkdownButton() {
<Text
aria-hidden={true}
$css={css`
font-family: var(--c--theme--font--families--base);
font-family: var(--c--globals--font--families--base);
`}
$weight="bold"
>

View File

@@ -24,14 +24,14 @@ export const ModalConfirmDownloadUnsafe = ({
<>
<Button
aria-label={t('Cancel the download')}
color="secondary"
variant="secondary"
onClick={() => onClose()}
>
{t('Cancel')}
</Button>
<Button
aria-label={t('Download')}
color="danger"
color="error"
data-testid="modal-download-unsafe-button"
onClick={() => {
if (onConfirm) {
@@ -52,7 +52,6 @@ export const ModalConfirmDownloadUnsafe = ({
$gap="0.7rem"
$size="h6"
$align="flex-start"
$variation="1000"
$direction="row"
$margin="0"
>
@@ -67,8 +66,10 @@ export const ModalConfirmDownloadUnsafe = ({
>
<Box>
<Box $direction="column" $gap="0.35rem" $margin={{ top: 'sm' }}>
<Text $variation="700">{t('This file is flagged as unsafe.')}</Text>
<Text $variation="600">
<Text $variation="secondary">
{t('This file is flagged as unsafe.')}
</Text>
<Text $variation="secondary">
{t('Please download it only if it comes from a trusted source.')}
</Text>
</Box>

View File

@@ -46,20 +46,18 @@ export const CommentToolbarButton = () => {
<Icon
iconName="comment"
className="--docs--icon-bg"
$theme="greyscale"
$variation="600"
$theme="gray"
$padding="0.15rem"
$size="16px"
$color={colorsTokens['greyscale-600']}
$size="md"
/>
{t('Comment')}
</Box>
</Components.Generic.Toolbar.Button>
<Box
$background={colorsTokens['greyscale-100']}
$background={colorsTokens['gray-100']}
$width="1px"
$height="70%"
$margin={{ left: '2px' }}
$margin={{ left: 'var(--c--globals--spacings--4xs)' }}
$css={css`
align-self: center;
`}

View File

@@ -11,7 +11,7 @@ export const cssComments = (
.bn-thread-mark:not([data-orphan='true']),
.bn-thread-mark-selected:not([data-orphan='true']) {
background: ${canSeeComment ? '#EDB40066' : 'transparent'};
color: var(--c--theme--colors--greyscale-700);
color: var(--c--globals--colors--greyscale-700);
}
}
@@ -31,7 +31,7 @@ export const cssComments = (
max-height: 500px;
.bn-default-styles {
font-family: var(--c--theme--font--families--base);
font-family: var(--c--globals--font--families--base);
}
.bn-block {
@@ -52,21 +52,22 @@ export const cssComments = (
padding: 8px;
& .bn-editor {
padding-left: 32px;
padding-left: var(--c--globals--spacings--lg);
.bn-inline-content {
color: var(--c--theme--colors--greyscale-700);
color: var(--c--globals--colors--greyscale-700);
}
}
// Emoji
& .bn-badge-group {
padding-left: 32px;
padding-left: var(--c--globals--spacings--lg);
.bn-badge label {
padding: 0 4px;
padding: var(--c--globals--spacings--0)
var(--c--globals--spacings--st);
background: none;
border: 1px solid var(--c--theme--colors--greyscale-300);
border-radius: 4px;
height: 24px;
border: 1px solid var(--c--globals--colors--greyscale-300);
border-radius: var(--c--globals--spacings--st);
height: var(--c--globals--spacings--md);
}
}
@@ -102,17 +103,17 @@ export const cssComments = (
background-color: transparent;
&:hover {
background-color: var(--c--theme--colors--greyscale-100);
background-color: var(--c--globals--colors--greyscale-100);
}
}
button[role='menuitem'] svg {
color: var(--c--theme--colors--greyscale-600);
color: var(--c--globals--colors--greyscale-600);
}
}
& svg {
color: var(--c--theme--colors--info-600);
color: var(--c--globals--colors--info-600);
}
}
@@ -125,19 +126,19 @@ export const cssComments = (
gap: 0.4rem !important;
& > button {
height: 24px;
padding-inline: 4px;
height: var(--c--globals--spacings--md);
padding-inline: var(--c--globals--spacings--st);
&[data-test='save'] {
border: 1px solid var(--c--theme--colors--info-600);
background: var(--c--theme--colors--info-600);
border: 1px solid var(--c--globals--colors--info-600);
background: var(--c--globals--colors--info-600);
color: white;
}
&[data-test='cancel'] {
background: white;
border: 1px solid var(--c--theme--colors--greyscale-300);
color: var(--c--theme--colors--info-600);
border: 1px solid var(--c--globals--colors--greyscale-300);
color: var(--c--globals--colors--info-600);
}
}
}
@@ -179,19 +180,19 @@ export const cssComments = (
button {
font-size: 0;
background: var(--c--theme--colors--info-600);
width: 24px;
height: 24px;
padding: 0;
background: var(--c--globals--colors--info-600);
width: var(--c--globals--spacings--md);
height: var(--c--globals--spacings--md);
padding: var(--c--globals--spacings--0);
&:disabled {
background: var(--c--theme--colors--greyscale-300);
background: var(--c--globals--colors--greyscale-300);
}
& .mantine-Button-label::before {
content: '🡡';
font-size: 13px;
color: var(--c--theme--colors--greyscale-100);
color: var(--c--globals--colors--greyscale-100);
}
}
}

View File

@@ -21,8 +21,8 @@ import emojidata from './initEmojiCallout';
const CalloutBlockStyle = createGlobalStyle`
.bn-block-content[data-content-type="callout"][data-background-color] {
padding: var(--c--theme--spacings--3xs) var(--c--theme--spacings--3xs);
border-radius: var(--c--theme--spacings--3xs);
padding: var(--c--globals--spacings--3xs) var(--c--globals--spacings--3xs);
border-radius: var(--c--globals--spacings--3xs);
}
`;

View File

@@ -91,9 +91,10 @@ const LinkSelected = ({ url, title }: LinkSelectedProps) => {
margin-right: 0.2rem;
}
&:hover {
background-color: ${colorsTokens['greyscale-100']};
background-color: ${colorsTokens['gray-100']};
}
transition: background-color 0.2s ease-in-out;
transition: background-color var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
.--docs--doc-deleted & {
pointer-events: none;
@@ -103,7 +104,7 @@ const LinkSelected = ({ url, title }: LinkSelectedProps) => {
{emoji ? (
<Text $size="16px">{emoji}</Text>
) : (
<SelectedPageIcon width={11.5} color={colorsTokens['primary-400']} />
<SelectedPageIcon width={11.5} color={colorsTokens['brand-400']} />
)}
<Text
$weight="500"

View File

@@ -35,11 +35,11 @@ import { DocSearchSubPageContent, DocSearchTarget } from '@/docs/doc-search';
import { useResponsiveStore } from '@/stores';
const inputStyle = css`
background-color: var(--c--theme--colors--greyscale-100);
background-color: var(--c--globals--colors--gray-100);
border: none;
outline: none;
color: var(--c--theme--colors--greyscale-700);
font-size: 16px;
color: var(--c--globals--colors--gray-700);
font-size: var(--c--globals--font--sizes--md);
width: 100%;
font-family: 'Inter';
`;
@@ -159,8 +159,8 @@ export const SearchPage = ({
<Box
as="span"
className="inline-content"
$background={colorsTokens['greyscale-100']}
$color="var(--c--theme--colors--greyscale-700)"
$background={colorsTokens['gray-100']}
$color="var(--c--globals--colors--gray-700)"
$direction="row"
$radius="3px"
$padding="1px"
@@ -198,9 +198,9 @@ export const SearchPage = ({
<QuickSearch showInput={false}>
<Card
$css={css`
box-shadow: 0 0 3px 0px var(--c--theme--colors--greyscale-200);
box-shadow: 0 0 3px 0px var(--c--globals--colors--gray-200);
& > div {
margin-top: 0;
margin-top: var(--c--globals--spacings--0);
& [cmdk-group-heading] {
padding: 0.4rem;
margin: 0;
@@ -287,8 +287,8 @@ export const SearchPage = ({
</Box>
<Text
$size="14px"
$color="var(--c--theme--colors--greyscale-1000)"
$size="sm"
$color="var(--c--globals--colors--gray-1000)"
spellCheck="false"
>
{titleWithoutEmoji}
@@ -296,11 +296,7 @@ export const SearchPage = ({
</Box>
}
right={
<Icon
iconName="keyboard_return"
$variation="600"
spellCheck="false"
/>
<Icon iconName="keyboard_return" spellCheck="false" />
}
/>
);
@@ -317,7 +313,7 @@ export const SearchPage = ({
<Box
$css={css`
border-top: 1px solid
var(--c--theme--colors--greyscale-200);
var(--c--globals--colors--gray-200);
`}
$width="100%"
>
@@ -332,15 +328,15 @@ export const SearchPage = ({
$css={css`
&:hover {
background-color: var(
--c--theme--colors--greyscale-100
--c--globals--colors--gray-100
);
}
`}
>
<AddPageIcon />
<Text
$size="14px"
$color="var(--c--theme--colors--greyscale-1000)"
$size="sm"
$color="var(--c--globals--colors--gray-1000)"
contentEditable={false}
>
{t('New sub-doc')}

View File

@@ -8,7 +8,7 @@ export const cssEditor = css`
}
& .bn-editor {
color: var(--c--theme--colors--greyscale-700);
color: var(--c--globals--colors--greyscale-700);
}
/**
@@ -104,14 +104,14 @@ export const cssEditor = css`
* Callout, Paragraph and Heading blocks
*/
.bn-block {
border-radius: var(--c--theme--spacings--3xs);
border-radius: var(--c--globals--spacings--3xs);
}
.bn-block-outer {
border-radius: var(--c--theme--spacings--3xs);
border-radius: var(--c--globals--spacings--3xs);
}
.bn-block > .bn-block-content[data-background-color] {
padding: var(--c--theme--spacings--3xs) var(--c--theme--spacings--3xs);
border-radius: var(--c--theme--spacings--3xs);
padding: var(--c--globals--spacings--3xs) var(--c--globals--spacings--3xs);
border-radius: var(--c--globals--spacings--3xs);
}
.bn-block-content[data-content-type='checkListItem'][data-checked='true']
.bn-inline-content {
@@ -127,7 +127,7 @@ export const cssEditor = css`
font-size: 1.25rem;
}
a {
color: var(--c--theme--colors--greyscale-600);
color: var(--c--globals--colors--greyscale-600);
cursor: pointer;
}
.bn-block-group
@@ -144,7 +144,7 @@ export const cssEditor = css`
* Quotes
*/
blockquote {
border-left: 4px solid var(--c--theme--colors--greyscale-300);
border-left: 4px solid var(--c--globals--colors--gray-300);
font-style: italic;
}

View File

@@ -174,7 +174,7 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
<>
<Button
aria-label={t('Cancel the download')}
color="secondary"
variant="secondary"
fullWidth
onClick={() => onClose()}
>
@@ -183,7 +183,7 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
<Button
data-testid="doc-export-download-button"
aria-label={t('Download')}
color="primary"
variant="primary"
fullWidth
onClick={() => void onSubmit()}
disabled={isExporting}
@@ -205,7 +205,6 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
$margin="0"
id="modal-export-title"
$size="h6"
$variation="1000"
$align="flex-start"
data-testid="modal-export-title"
>
@@ -225,7 +224,7 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
$gap="1rem"
className="--docs--modal-export-content"
>
<Text $variation="600" $size="sm" as="p">
<Text $variation="secondary" $size="sm" as="p">
{t('Download your document in a .docx, .odt or .pdf format.')}
</Text>
<Select

View File

@@ -2,36 +2,37 @@ import { Button, Modal, ModalSize } from '@openfun/cunningham-react';
import { t } from 'i18next';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, BoxButton, Icon, Text } from '@/components';
import { Box, BoxButton, Card, Icon, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
export const AlertNetwork = () => {
const { t } = useTranslation();
const { colorsTokens, spacingsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<>
<Box>
<Box
<Card
$direction="row"
$justify="space-between"
$width="100%"
$background={colorsTokens['warning-100']}
$radius={spacingsTokens['3xs']}
$padding="xs"
$flex={1}
$align="center"
$gap={spacingsTokens['2xs']}
$css={css`
border: 1px solid var(--c--theme--colors--warning-300);
`}
$theme="warning"
>
<Box $direction="row" $gap={spacingsTokens['2xs']} $align="center">
<Icon iconName="mobiledata_off" $theme="warning" $variation="600" />
<Text $theme="warning" $variation="600" $weight={500}>
<Box
$direction="row"
$gap={spacingsTokens['2xs']}
$align="center"
$withThemeInherited
>
<Icon iconName="mobiledata_off" $withThemeInherited />
<Text $withThemeInherited $weight={500}>
{t('Others are editing. Your network prevent changes.')}
</Text>
</Box>
@@ -40,20 +41,20 @@ export const AlertNetwork = () => {
$gap={spacingsTokens['3xs']}
$align="center"
onClick={() => setIsModalOpen(true)}
$withThemeInherited
>
<Icon
iconName="info"
$theme="warning"
$variation="600"
$size="16px"
$withThemeInherited
$size="md"
$weight="500"
$margin={{ top: 'auto' }}
/>
<Text $theme="warning" $variation="600" $weight="500" $size="xs">
<Text $withThemeInherited $weight="500" $size="xs">
{t('Learn more')}
</Text>
</BoxButton>
</Box>
</Card>
</Box>
{isModalOpen && (
<AlertNetworkModal onClose={() => setIsModalOpen(false)} />
@@ -74,20 +75,14 @@ export const AlertNetworkModal = ({ onClose }: AlertNetworkModalProps) => {
onClose={() => onClose()}
rightActions={
<>
<Button aria-label={t('OK')} onClick={onClose} color="danger">
<Button aria-label={t('OK')} onClick={onClose} color="error">
{t('I understand')}
</Button>
</>
}
size={ModalSize.MEDIUM}
title={
<Text
$size="h6"
as="h6"
$margin={{ all: '0' }}
$align="flex-start"
$variation="1000"
>
<Text $size="h6" as="h6" $margin={{ all: '0' }} $align="flex-start">
{t("Why you can't edit the document?")}
</Text>
}
@@ -97,14 +92,14 @@ export const AlertNetworkModal = ({ onClose }: AlertNetworkModalProps) => {
className="--docs--modal-alert-network"
$margin={{ top: 'md' }}
>
<Text $size="sm" $variation="600">
<Text $size="sm" $variation="secondary">
{t(
'Others are editing this document. Unfortunately your network blocks WebSockets, the technology enabling real-time co-editing.',
)}
</Text>
<Text
$size="sm"
$variation="600"
$variation="secondary"
$margin={{ top: 'xs' }}
$weight="bold"
$display="inline"
@@ -112,7 +107,7 @@ export const AlertNetworkModal = ({ onClose }: AlertNetworkModalProps) => {
{t("This means you can't edit until others leave.")}{' '}
<Text
$size="sm"
$variation="600"
$variation="secondary"
$margin={{ top: 'xs' }}
$weight="normal"
$display="inline"

View File

@@ -1,39 +1,33 @@
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, Icon, Text } from '@/components';
import { Card, Icon, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
export const AlertPublic = ({ isPublicDoc }: { isPublicDoc: boolean }) => {
const { t } = useTranslation();
const { colorsTokens, spacingsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
return (
<Box
<Card
aria-label={t('Public document')}
$color={colorsTokens['primary-800']}
$background={colorsTokens['primary-050']}
$radius={spacingsTokens['3xs']}
$direction="row"
$padding="xs"
$flex={1}
$align="center"
$gap={spacingsTokens['2xs']}
$css={css`
border: 1px solid var(--c--theme--colors--primary-300, #e3e3fd);
`}
$theme="brand"
>
<Icon
$theme="primary"
$variation="800"
$withThemeInherited
data-testid="public-icon"
iconName={isPublicDoc ? 'public' : 'vpn_lock'}
/>
<Text $theme="primary" $variation="800" $weight="500">
<Text $withThemeInherited $weight="500">
{isPublicDoc
? t('Public document')
: t('Document accessible to any connected person')}
</Text>
</Box>
</Card>
);
};

View File

@@ -1,9 +1,12 @@
import { useTreeContext } from '@gouvfr-lasuite/ui-kit';
import { VariantType, useToastProvider } from '@openfun/cunningham-react';
import {
Button,
VariantType,
useToastProvider,
} from '@openfun/cunningham-react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, BoxButton, Icon, Text } from '@/components';
import { Box, Card, Icon } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import {
Doc,
@@ -17,7 +20,7 @@ export const AlertRestore = ({ doc }: { doc: Doc }) => {
const { t } = useTranslation();
const { toast } = useToastProvider();
const treeContext = useTreeContext<Doc>();
const { colorsTokens, spacingsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
const { mutate: restoreDoc, error } = useRestoreDoc({
listInvalidQueries: [KEY_LIST_DOC, KEY_LIST_DOC_TRASHBIN, KEY_DOC],
options: {
@@ -44,57 +47,52 @@ export const AlertRestore = ({ doc }: { doc: Doc }) => {
});
return (
<Box
<Card
className="--docs--alert-restore"
aria-label={t('Alert deleted document')}
$color={colorsTokens['danger-800']}
$background={colorsTokens['danger-100']}
$radius={spacingsTokens['3xs']}
$direction="row"
$padding="xs"
$flex={1}
$align="center"
$gap={spacingsTokens['3xs']}
$css={css`
border: 1px solid var(--c--theme--colors--danger-300, #e3e3fd);
`}
$justify="space-between"
$theme="error"
>
<Box $direction="row" $align="center" $gap={spacingsTokens['2xs']}>
<Box
$withThemeInherited
$direction="row"
$align="center"
$gap={spacingsTokens['2xs']}
>
<Icon
$theme="danger"
$variation="700"
$withThemeInherited
data-testid="public-icon"
iconName="delete"
variant="symbols-outlined"
/>
<Text $theme="danger" $variation="700" $weight="500">
{t('Document deleted')}
</Text>
{t('Document deleted')}
</Box>
<BoxButton
<Button
onClick={() =>
restoreDoc({
docId: doc.id,
})
}
$direction="row"
$gap="0.2rem"
$theme="danger"
$variation="600"
$align="center"
color="error"
variant="tertiary"
size="nano"
icon={
<Icon
iconName="undo"
$withThemeInherited
$size="18px"
variant="symbols-outlined"
/>
}
>
<Icon
iconName="undo"
$theme="danger"
$variation="600"
$size="18px"
variant="symbols-outlined"
/>
<Text $theme="danger" $variation="600" $size="s" $css="line-height:1;">
{t('Restore')}
</Text>
</BoxButton>
</Box>
Restore
</Button>
</Card>
);
};

View File

@@ -46,20 +46,19 @@ export const BoutonShare = ({
<Box
$css={css`
.c__button--medium {
height: 32px;
padding: 10px var(--c--theme--spacings--xs);
height: var(--c--globals--spacings--lg);
padding: 10px var(--c--globals--spacings--xs);
gap: 7px;
}
`}
>
<Button
color="tertiary"
aria-label={t('Share button')}
variant="secondary"
icon={
<Icon
iconName="group"
$theme="primary"
$variation="800"
$color="inherit"
variant="filled"
disabled={isDisabled}
/>
@@ -76,7 +75,8 @@ export const BoutonShare = ({
return (
<Button
color="primary-text"
color="brand"
variant="tertiary"
onClick={open}
size="medium"
disabled={isDisabled}

View File

@@ -47,15 +47,15 @@ export const DocHeaderInfo = ({ doc }: DocHeaderInfoProps) => {
return (
<>
<Text
$variation="600"
$variation="tertiary"
$size="s"
$weight="bold"
$theme={isEditable ? 'greyscale' : 'warning'}
$theme={isEditable ? 'gray' : 'warning'}
>
{transRole(isEditable ? doc.user_role || doc.link_role : Role.READER)}
&nbsp;·&nbsp;
</Text>
<Text $variation="600" $size="s">
<Text $variation="tertiary" $size="s">
{dateToDisplay}
</Text>
</>
@@ -64,11 +64,11 @@ export const DocHeaderInfo = ({ doc }: DocHeaderInfoProps) => {
return (
<>
<Text $variation="400" $size="s">
<Text $variation="tertiary" $size="s">
{hasChildren ? relativeOnly : dateToDisplay}
</Text>
{hasChildren && (
<Text $variation="400" $size="s">
<Text $variation="tertiary" $size="s">
&nbsp;&nbsp;
{t('Contains {{count}} sub-documents', {
count: childrenCount,

View File

@@ -43,7 +43,6 @@ export const DocTitleText = () => {
as="h2"
$margin={{ all: 'none', left: 'none' }}
$size={isMobile ? 'h4' : 'h2'}
$variation="1000"
>
{currentDoc?.title || untitledDocument}
</Text>
@@ -71,10 +70,11 @@ const DocTitleEmojiPicker = ({ doc }: DocTitleProps) => {
padding-top: 3px;
cursor: pointer;
&:hover {
background-color: ${colorsTokens['greyscale-100']};
border-radius: 4px;
background-color: ${colorsTokens['gray-100']};
border-radius: var(--c--globals--spacings--st);
}
transition: background-color 0.2s ease-in-out;
transition: background-color var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out);
`}
>
<DocIcon
@@ -95,7 +95,7 @@ const DocTitleEmojiPicker = ({ doc }: DocTitleProps) => {
height="25px"
aria-hidden="true"
aria-label={t('Simple document icon')}
color={colorsTokens['primary-500']}
color={colorsTokens['brand-500']}
/>
}
/>
@@ -107,7 +107,6 @@ const DocTitleEmojiPicker = ({ doc }: DocTitleProps) => {
const DocTitleInput = ({ doc }: DocTitleProps) => {
const { isDesktop } = useResponsiveStore();
const { t } = useTranslation();
const { colorsTokens } = useCunninghamTheme();
const { isTopRoot } = useDocUtils(doc);
const { untitledDocument } = useTrans();
const { emoji, titleWithoutEmoji } = getEmojiAndTitle(doc.title ?? '');
@@ -177,18 +176,19 @@ const DocTitleInput = ({ doc }: DocTitleProps) => {
onBlurCapture={(event) =>
handleTitleSubmit(event.target.textContent || '')
}
$color={colorsTokens['greyscale-1000']}
$padding={{ right: 'big' }}
$css={css`
&[contenteditable='true']:empty:not(:focus):before {
content: '${untitledDocument}';
color: grey;
color: var(
--c--contextuals--content--semantic--neutral--tertiary
);
pointer-events: none;
font-style: italic;
}
font-size: ${isDesktop
? css`var(--c--theme--font--sizes--h2)`
: css`var(--c--theme--font--sizes--sm)`};
? css`var(--c--globals--font--sizes--h2)`
: css`var(--c--globals--font--sizes--sm)`};
font-weight: 700;
outline: none;
`}

View File

@@ -215,14 +215,9 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
{!isSmallMobile && ModalExport && (
<Button
data-testid="doc-open-modal-download-button"
color="tertiary-text"
variant="tertiary"
icon={
<Icon
iconName="download"
$theme="primary"
$variation="800"
aria-hidden={true}
/>
<Icon iconName="download" $color="inherit" aria-hidden={true} />
}
onClick={() => {
setIsModalExportOpen(true);
@@ -236,17 +231,14 @@ export const DocToolBox = ({ doc }: DocToolBoxProps) => {
label={t('Open the document options')}
buttonCss={css`
padding: ${spacingsTokens['xs']};
&:hover {
background-color: ${colorsTokens['greyscale-100']};
}
${isSmallMobile
? css`
border: 1px solid ${colorsTokens['greyscale-300']};
border: 1px solid ${colorsTokens['gray-300']};
`
: ''}
`}
>
<IconOptions aria-hidden="true" isHorizontal $theme="primary" />
<IconOptions aria-hidden="true" isHorizontal $color="inherit" />
</DropdownMenu>
</Box>

View File

@@ -21,7 +21,7 @@ export const DocIcon = ({
emoji,
defaultIcon,
$size = 'sm',
$variation = '1000',
$variation = 'secondary',
$weight = '400',
docId,
title,

View File

@@ -65,7 +65,6 @@ export const DocPage403 = ({ id }: DocProps) => {
$padding={{ bottom: '2rem' }}
>
<Image
className="c__image-system-filter"
src={img403}
alt={t('Image 403')}
width={300}
@@ -77,7 +76,7 @@ export const DocPage403 = ({ id }: DocProps) => {
/>
<Box $align="center" $gap="0.8rem">
<Text as="p" $textAlign="center" $maxWidth="350px" $theme="primary">
<Text as="p" $textAlign="center" $maxWidth="350px" $theme="brand">
{hasRequested
? t('Your access request for this document is pending.')
: t('Insufficient access rights to view the document.')}
@@ -88,7 +87,6 @@ export const DocPage403 = ({ id }: DocProps) => {
as="p"
$maxWidth="320px"
$textAlign="center"
$variation="600"
$size="sm"
$margin={{ top: '0' }}
>
@@ -101,8 +99,9 @@ export const DocPage403 = ({ id }: DocProps) => {
<Box $direction="row" $gap="0.7rem">
<StyledLink href="/">
<StyledButton
icon={<Icon iconName="house" $theme="primary" />}
color="tertiary"
icon={<Icon iconName="house" $withThemeInherited />}
color="brand"
variant="secondary"
>
{t('Home')}
</StyledButton>

View File

@@ -98,7 +98,7 @@ export const ModalRemoveDoc = ({
<Button
ref={cancelButtonRef}
aria-label={t('Cancel the deletion')}
color="secondary"
variant="secondary"
fullWidth
onClick={handleClose}
onKeyDown={handleCloseKeyDown}
@@ -107,7 +107,7 @@ export const ModalRemoveDoc = ({
</Button>
<Button
aria-label={t('Delete document')}
color="danger"
color="error"
fullWidth
onClick={handleDelete}
onKeyDown={handleDeleteKeyDown}
@@ -130,7 +130,6 @@ export const ModalRemoveDoc = ({
id="modal-remove-doc-title"
$margin="0"
$align="flex-start"
$variation="1000"
>
{t('Delete a doc')}
</Text>
@@ -144,7 +143,12 @@ export const ModalRemoveDoc = ({
>
<Box className="--docs--modal-remove-doc">
{!isError && (
<Text $size="sm" $variation="600" $display="inline-block" as="p">
<Text
$size="sm"
$variation="secondary"
$display="inline-block"
as="p"
>
{hasChildren ? (
<Trans t={t}>
This document and <strong>any sub-documents</strong> will be

View File

@@ -33,7 +33,7 @@ export const SimpleDocItem = ({
showAccesses = false,
}: SimpleDocItemProps) => {
const { t } = useTranslation();
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
const { isDesktop } = useResponsiveStore();
const { untitledDocument } = useTrans();
const { isChild } = useDocUtils(doc);
@@ -63,13 +63,13 @@ export const SimpleDocItem = ({
<PinnedDocumentIcon
aria-hidden="true"
data-testid="doc-pinned-icon"
color={colorsTokens['primary-500']}
color="var(--c--contextuals--content--semantic--info--tertiary)"
/>
) : isChild ? (
<ChildDocument
aria-hidden="true"
data-testid="doc-child-icon"
color={colorsTokens['primary-500']}
color="var(--c--contextuals--content--semantic--info--tertiary)"
/>
) : (
<SimpleFileIcon
@@ -77,14 +77,13 @@ export const SimpleDocItem = ({
height="32px"
aria-hidden="true"
data-testid="doc-simple-icon"
color={colorsTokens['primary-500']}
color="var(--c--contextuals--content--semantic--info--tertiary)"
/>
)}
</Box>
<Box $justify="center" $overflow="auto">
<Text
$size="sm"
$variation="1000"
$weight="500"
$css={ItemTextCss}
data-testid="doc-title"
@@ -99,7 +98,7 @@ export const SimpleDocItem = ({
$margin={{ top: '-2px' }}
aria-hidden="true"
>
<Text $variation="600" $size="xs">
<Text $size="xs" $variation="tertiary">
{DateTime.fromISO(doc.updated_at).toRelative()}
</Text>
</Box>

View File

@@ -58,7 +58,7 @@ export const DocSearchFilters = ({
/>
</Box>
{hasFilters && (
<Button color="primary-text" size="small" onClick={onReset}>
<Button color="brand" variant="tertiary" size="small" onClick={onReset}>
{t('Reset')}
</Button>
)}

View File

@@ -24,7 +24,11 @@ export const DocSearchItem = ({ doc }: DocSearchItemProps) => {
</Box>
}
right={
<Icon iconName="keyboard_return" $theme="primary" $variation="800" />
<Icon
iconName="keyboard_return"
$theme="brand"
$variation="secondary"
/>
}
/>
</Box>

View File

@@ -85,7 +85,8 @@ const DocSearchModalGlobal = ({
aria-label={t('Close the search modal')}
onClick={modalProps.onClose}
size="small"
color="primary-text"
color="brand"
variant="tertiary"
/>
</Box>
<QuickSearch
@@ -112,7 +113,6 @@ const DocSearchModalGlobal = ({
$justify="center"
>
<Image
className="c__image-system-filter"
width={320}
src={EmptySearchIcon}
alt={t('No active search')}

View File

@@ -9,7 +9,7 @@
<path
id="&#244;&#128;&#153;&#160;"
d="M5.99986 12.2256C5.99986 11.7946 6.25238 11.5791 6.75741 11.5791H10.4145C10.802 11.5791 11.2156 11.4811 11.6553 11.2852C12.0994 11.0893 12.5413 10.8302 12.981 10.508C13.4208 10.1902 13.8235 9.84192 14.1892 9.46314C14.5593 9.08437 14.864 8.70778 15.1035 8.33336L15.4496 7.80438C15.5802 7.59105 15.7718 7.48438 16.0243 7.48438C16.1897 7.48438 16.3334 7.5388 16.4553 7.64765C16.5816 7.76084 16.6447 7.91758 16.6447 8.11785C16.6447 8.30506 16.5837 8.48791 16.4618 8.66641L16.2398 9.01254C15.996 9.37389 15.7086 9.7309 15.3778 10.0835C15.0469 10.4362 14.6964 10.7606 14.3263 11.0566C13.9606 11.357 13.6058 11.6073 13.2619 11.8076C12.9179 12.0122 12.6153 12.1472 12.3541 12.2125V12.2386C12.6153 12.2996 12.9179 12.4324 13.2619 12.637C13.6058 12.8416 13.9606 13.0941 14.3263 13.3945C14.6921 13.695 15.0404 14.0193 15.3712 14.3676C15.7065 14.7203 15.996 15.0794 16.2398 15.4451L16.4618 15.7847C16.5837 15.9632 16.6447 16.1461 16.6447 16.3333C16.6447 16.5292 16.5837 16.6838 16.4618 16.797C16.3443 16.9102 16.1963 16.9668 16.0178 16.9668C15.7696 16.9668 15.5802 16.8601 15.4496 16.6468L15.1035 16.1243C14.864 15.7499 14.5593 15.3711 14.1892 14.988C13.8235 14.6092 13.4208 14.2588 12.981 13.9366C12.5413 13.6188 12.0994 13.3619 11.6553 13.166C11.2156 12.9701 10.802 12.8721 10.4145 12.8721H6.75741C6.25238 12.8721 5.99986 12.6566 5.99986 12.2256ZM14.3068 7.64112C14.1065 7.48438 14.0303 7.32329 14.0782 7.15785C14.1261 6.99677 14.2697 6.88139 14.5092 6.81173L17.0822 6.03459C17.2782 5.97364 17.4392 5.99323 17.5655 6.09337C17.6918 6.1935 17.7505 6.34371 17.7418 6.54398L17.6308 9.23457C17.6221 9.48274 17.5437 9.64818 17.3957 9.7309C17.252 9.81362 17.0822 9.78097 16.8863 9.63294L14.3068 7.64112ZM14.3198 16.7251L16.9516 14.8117C17.1519 14.6637 17.3239 14.6354 17.4675 14.7268C17.6112 14.8182 17.6831 14.9858 17.6831 15.2296L17.7157 17.9268C17.7157 18.127 17.6504 18.2729 17.5198 18.3643C17.3935 18.4601 17.2324 18.4753 17.0365 18.41L14.4896 17.5545C14.2545 17.4805 14.1152 17.3608 14.0717 17.1953C14.0281 17.0299 14.1108 16.8732 14.3198 16.7251Z"
fill="#000091"
fill="currentColor"
/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -9,7 +9,7 @@
<path
id="v"
d="M4.6665 12.667V11.3337H9.39984C10.0998 11.3337 10.7082 11.1114 11.2248 10.667C11.7415 10.2225 11.9998 9.66699 11.9998 9.00033C11.9998 8.33366 11.7415 7.7781 11.2248 7.33366C10.7082 6.88921 10.0998 6.66699 9.39984 6.66699H5.19984L6.93317 8.40033L5.99984 9.33366L2.6665 6.00033L5.99984 2.66699L6.93317 3.60033L5.19984 5.33366H9.39984C10.4776 5.33366 11.4026 5.68366 12.1748 6.38366C12.9471 7.08366 13.3332 7.95588 13.3332 9.00033C13.3332 10.0448 12.9471 10.917 12.1748 11.617C11.4026 12.317 10.4776 12.667 9.39984 12.667H4.6665Z"
fill="#000091"
fill="currentColor"
/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 725 B

After

Width:  |  Height:  |  Size: 730 B

View File

@@ -1,8 +1,7 @@
import { Button } from '@openfun/cunningham-react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, Text } from '@/components';
import { Box, Card, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { Doc, KEY_DOC, KEY_LIST_DOC } from '@/docs/doc-management';
@@ -17,29 +16,29 @@ interface DocDesynchronizedProps {
export const DocDesynchronized = ({ doc }: DocDesynchronizedProps) => {
const { t } = useTranslation();
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
const { mutate: updateDocLink } = useUpdateDocLink({
listInvalidQueries: [KEY_LIST_DOC, KEY_DOC],
});
return (
<Box
$background={colorsTokens['primary-100']}
<Card
$padding="3xs"
$direction="row"
$align="center"
$justify="space-between"
$gap={spacingsTokens['4xs']}
$color={colorsTokens['primary-800']}
$css={css`
border: 1px solid ${colorsTokens['primary-300']};
border-radius: ${spacingsTokens['2xs']};
`}
$theme="brand"
>
<Box $direction="row" $align="center" $gap={spacingsTokens['3xs']}>
<Box
$withThemeInherited
$direction="row"
$align="center"
$gap={spacingsTokens['3xs']}
>
<Desync />
<Text $size="xs" $theme="primary" $variation="800" $weight="400">
<Text $size="xs" $withThemeInherited $weight="400">
{t('The link sharing rules differ from the parent document')}
</Text>
</Box>
@@ -53,12 +52,13 @@ export const DocDesynchronized = ({ doc }: DocDesynchronizedProps) => {
})
}
size="small"
color="primary-text"
color="brand"
variant="tertiary"
icon={<Undo />}
>
{t('Restore')}
</Button>
)}
</Box>
</Card>
);
};

View File

@@ -41,21 +41,16 @@ export const DocInheritedShareContent = ({
}}
>
<Box $direction="row" $align="center" $gap={spacingsTokens['4xs']}>
<Text $variation="1000" $weight="bold" $size="sm">
<Text $weight="bold" $size="sm">
{t('People with access via the parent document')}
</Text>
<Box>
<StyledLink href={`/docs/${rawAccesses[0].document.id}`}>
<Button
size="small"
icon={
<Icon
$theme="greyscale"
$variation="600"
iconName="open_in_new"
/>
}
color="tertiary-text"
icon={<Icon iconName="open_in_new" />}
color="neutral"
variant="tertiary"
/>
</StyledLink>
</Box>

View File

@@ -106,7 +106,12 @@ export const DocRoleDropdown = ({
if (!canUpdate) {
return (
<Text aria-label={t('Document role text')} $variation="600">
<Text
$variation="tertiary"
aria-label={t('Document role text')}
$weight={500}
$size="s"
>
{transRole(currentRole)}
</Text>
);
@@ -121,7 +126,8 @@ export const DocRoleDropdown = ({
})}
showArrow={true}
arrowCss={css`
color: var(--c--theme--colors--primary-800) !important;
color: var(--c--contextuals--content--semantic--brand--tertiary);
font-size: 16px;
`}
testId="doc-role-dropdown"
options={[
@@ -132,8 +138,14 @@ export const DocRoleDropdown = ({
callback: onRemove,
},
]}
buttonCss={css`
&:hover {
background: none;
}
font-size: 12px;
`}
>
<Text $theme="primary" $variation="800">
<Text $theme="brand" $variation="tertiary">
{transRole(currentRole)}
</Text>
</DropdownMenu>

View File

@@ -83,7 +83,8 @@ const DocShareAccessRequestItem = ({ doc, accessRequest }: Props) => {
})}
/>
<Button
color="tertiary"
color="brand"
variant="tertiary"
onClick={() =>
acceptDocAccessRequests({
docId: doc.id,
@@ -106,7 +107,7 @@ const DocShareAccessRequestItem = ({ doc, accessRequest }: Props) => {
}
aria-label={t('Close the access request modal')}
>
<Icon iconName="close" $variation="600" $size="16px" />
<Icon iconName="close" $size="16px" />
</BoxButton>
)}
</Box>
@@ -197,7 +198,7 @@ export const ButtonAccessRequest = ({
if (docAccessError?.status === 404) {
return (
<Text $maxWidth="320px" $textAlign="center" $variation="600" $size="sm">
<Text $maxWidth="320px" $textAlign="center" $size="sm">
{t(
'As this is a sub-document, please request access to the parent document to enable these features.',
)}

View File

@@ -5,10 +5,9 @@ import {
} from '@openfun/cunningham-react';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { APIError } from '@/api';
import { Box } from '@/components';
import { Box, Card } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { Doc, Role } from '@/docs/doc-management';
import { User } from '@/features/auth';
@@ -41,7 +40,7 @@ export const DocShareAddMemberList = ({
const { toast } = useToastProvider();
const [isLoading, setIsLoading] = useState(false);
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
const [invitationRole, setInvitationRole] = useState<Role>(Role.EDITOR);
const canShare = doc.abilities.accesses_manage;
const { mutateAsync: createInvitation } = useCreateDocInvitation();
@@ -116,17 +115,16 @@ export const DocShareAddMemberList = ({
: t('Invite {{count}} members', { count: selectedUsers.length });
return (
<Box
<Card
className="--docs--doc-share-add-member-list"
data-testid="doc-share-add-member-list"
$direction="row"
$padding={spacingsTokens.sm}
$align="center"
$background={colorsTokens['greyscale-050']}
$radius={spacingsTokens['3xs']}
$css={css`
border: 1px solid ${colorsTokens['greyscale-200']};
`}
className="--docs--doc-share-add-member-list"
$padding={spacingsTokens.sm}
$scope="surface"
$theme="tertiary"
$variation=""
$border="1px solid var(--c--contextuals--border--semantic--contextual--primary)"
>
<Box
$direction="row"
@@ -148,6 +146,7 @@ export const DocShareAddMemberList = ({
canUpdate={canShare}
currentRole={invitationRole}
onSelectRole={setInvitationRole}
ariaLabel={t('Invite new members')}
/>
<Button
onClick={() => void onInvite()}
@@ -158,6 +157,6 @@ export const DocShareAddMemberList = ({
{t('Invite')}
</Button>
</Box>
</Box>
</Card>
);
};

View File

@@ -1,8 +1,6 @@
import { Button } from '@openfun/cunningham-react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, Icon, Text } from '@/components';
import { Box, BoxButton, Icon, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { User } from '@/features/auth';
@@ -12,11 +10,11 @@ type Props = {
};
export const DocShareAddMemberListItem = ({ user, onRemoveUser }: Props) => {
const { t } = useTranslation();
const { spacingsTokens, colorsTokens, fontSizesTokens } =
useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
return (
<Box
className="--docs--doc-share-add-member-list-item"
data-testid={`doc-share-add-member-${user.email}`}
$radius={spacingsTokens['3xs']}
$direction="row"
@@ -24,30 +22,27 @@ export const DocShareAddMemberListItem = ({ user, onRemoveUser }: Props) => {
$justify="center"
$align="center"
$gap={spacingsTokens['3xs']}
$background={colorsTokens['greyscale-250']}
$padding={{
left: spacingsTokens['xs'],
right: spacingsTokens['4xs'],
vertical: spacingsTokens['4xs'],
}}
$css={css`
color: ${colorsTokens['greyscale-1000']};
font-size: ${fontSizesTokens['xs']};
`}
className="--docs--doc-share-add-member-list-item"
$withThemeBG
$theme="neutral"
$variation="secondary"
>
<Text $variation="1000" $size="xs">
<Text $withThemeInherited $size="xs">
{user.full_name || user.email}
</Text>
<Button
color="tertiary-text"
size="nano"
<BoxButton
onClick={() => onRemoveUser?.(user)}
icon={<Icon $variation="600" $size="sm" iconName="close" />}
aria-label={t('Remove {{name}} from the invite list', {
name: user.full_name || user.email,
})}
/>
$withThemeInherited
>
<Icon $withThemeInherited $size="sm" iconName="close" />
</BoxButton>
</Box>
);
};

View File

@@ -262,7 +262,7 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {
<Text
$maxWidth="320px"
$textAlign="center"
$variation="600"
$variation="secondary"
$size="sm"
as="p"
>
@@ -272,7 +272,7 @@ export const DocShareModal = ({ doc, onClose, isRootDoc = true }: Props) => {
</Text>
<ButtonAccessRequest
docId={doc.id}
color="tertiary"
variant="secondary"
size="small"
/>
</Box>

View File

@@ -2,7 +2,7 @@ import { Button } from '@openfun/cunningham-react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, HorizontalSeparator } from '@/components';
import { Box, HorizontalSeparator, Icon } from '@/components';
import { Doc, useCopyDocLink } from '@/docs/doc-management';
import { DocVisibility } from './DocVisibility';
@@ -38,18 +38,12 @@ export const DocShareModalFooter = ({
<Button
fullWidth={false}
onClick={copyDocLink}
color="tertiary"
icon={
<span className="material-icons" aria-hidden={true}>
add_link
</span>
}
variant="secondary"
icon={<Icon iconName="add_link" $withThemeInherited />}
>
{t('Copy link')}
</Button>
<Button onClick={onClose} color="primary">
{t('OK')}
</Button>
<Button onClick={onClose}>{t('OK')}</Button>
</Box>
</Box>
);

View File

@@ -34,7 +34,7 @@ interface DocVisibilityProps {
export const DocVisibility = ({ doc }: DocVisibilityProps) => {
const { t } = useTranslation();
const { isDesktop } = useResponsiveStore();
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
const canManage = doc.abilities.accesses_manage;
const docLinkReach = getDocLinkReach(doc);
const docLinkRole = getDocLinkRole(doc);
@@ -123,7 +123,7 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
$gap={spacingsTokens['base']}
className="--docs--doc-visibility"
>
<Text $weight="700" $size="sm" $variation="700">
<Text $weight="700" $size="sm">
{t('Link settings')}
</Text>
{isDesynchronized && <DocDesynchronized doc={doc} />}
@@ -145,7 +145,9 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
testId="doc-visibility"
label={t('Document visibility')}
arrowCss={css`
color: ${colorsTokens['primary-800']} !important;
color: var(
--c--contextuals--content--semantic--brand--tertiary
) !important;
`}
buttonCss={css`
&:hover {
@@ -163,24 +165,24 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
}
options={linkReachOptions}
>
<Box $direction="row" $align="center" $gap={spacingsTokens['3xs']}>
<Box
$theme={canManage ? 'brand' : 'gray'}
$variation={canManage ? 'tertiary' : 'primary'}
$direction="row"
$align="center"
$gap={spacingsTokens['3xs']}
>
<Icon
$theme={canManage ? 'primary' : 'greyscale'}
$variation={canManage ? '800' : '600'}
iconName={linkReachChoices[docLinkReach].icon}
$withThemeInherited
/>
<Text
$theme={canManage ? 'primary' : 'greyscale'}
$variation={canManage ? '800' : '600'}
$weight="500"
$size="md"
>
<Text $weight="500" $size="md" $withThemeInherited>
{linkReachChoices[docLinkReach].label}
</Text>
</Box>
</DropdownMenu>
{isDesktop && (
<Text $size="xs" $variation="600" $weight="400">
<Text $size="xs" $variation="secondary" $weight="400">
{description}
</Text>
)}
@@ -193,6 +195,13 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
&:hover {
background-color: unset;
}
font-size: 12px;
`}
arrowCss={css`
color: var(
--c--contextuals--content--semantic--brand--tertiary
) !important;
font-size: 16px;
`}
disabled={!canManage}
showArrow={true}
@@ -206,7 +215,7 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
}
label={t('Document access mode')}
>
<Text $weight="initial" $variation="600" $theme="primary">
<Text $weight="initial" $theme="brand" $variation="tertiary">
{linkModeTranslations[docLinkRole]}
</Text>
</DropdownMenu>
@@ -214,7 +223,7 @@ export const DocVisibility = ({ doc }: DocVisibilityProps) => {
)}
</Box>
{!isDesktop && (
<Text $size="xs" $variation="600">
<Text $size="xs" $variation="secondary">
{description}
</Text>
)}

View File

@@ -35,16 +35,14 @@ export const SearchUserRow = ({
>
<UserAvatar
fullName={user.full_name || user.email}
background={
isInvitation ? colorsTokens['greyscale-400'] : undefined
}
background={isInvitation ? colorsTokens['gray-400'] : undefined}
/>
<Box $direction="column">
<Text $size="sm" $weight="500" $variation="1000">
<Text $size="sm" $weight="500">
{hasFullName ? user.full_name : user.email}
</Text>
{hasFullName && (
<Text $size="xs" $margin={{ top: '-2px' }} $variation="600">
<Text $size="xs" $margin={{ top: '-2px' }} $variation="secondary">
{user.email}
</Text>
)}

View File

@@ -57,15 +57,15 @@ export const Heading = ({
block: 'start',
});
}}
$radius="4px"
$background={isActive ? `${colorsTokens['greyscale-100']}` : 'none'}
$radius="var(--c--globals--spacings--st)"
$background={isActive ? `${colorsTokens['gray-100']}` : 'none'}
$css={css`
text-align: left;
&:focus-visible {
/* Scoped focus style: same footprint as hover, with theme shadow */
outline: none;
box-shadow: 0 0 0 2px ${colorsTokens['primary-400']};
border-radius: 4px;
box-shadow: 0 0 0 2px ${colorsTokens['brand-400']};
border-radius: var(--c--globals--spacings--st);
}
`}
className="--docs--table-content-heading"
@@ -76,7 +76,6 @@ export const Heading = ({
<Text
$width="100%"
$padding={{ vertical: 'xtiny', left: leftPaddingMap[level] }}
$variation={isActive ? '1000' : '700'}
$weight={isHighlight ? 'bold' : 'normal'}
$css="overflow-wrap: break-word;"
$hasTransition

View File

@@ -111,11 +111,11 @@ export const TableContent = () => {
$position="sticky"
aria-label={t('Summary')}
$css={css`
top: 0;
border: 1px solid ${colorsTokens['greyscale-300']};
top: var(--c--globals--spacings--0);
border: 1px solid ${colorsTokens['brand-100']};
overflow: hidden;
border-radius: ${spacingsTokens['3xs']};
background: ${colorsTokens['greyscale-000']};
background: ${colorsTokens['gray-000']};
${isHover &&
css`
display: flex;
@@ -138,22 +138,19 @@ export const TableContent = () => {
aria-expanded={isHover}
aria-controls="toc-list"
$css={css`
&:hover {
background: ${colorsTokens['primary-100']};
}
&:focus-visible {
outline: none;
box-shadow: 0 0 0 4px ${colorsTokens['primary-400']};
background: ${colorsTokens['primary-100']};
box-shadow: 0 0 0 4px ${colorsTokens['brand-400']};
background: ${colorsTokens['brand-100']};
width: 90%;
height: 90%;
}
`}
>
<Icon
$theme="brand"
$variation="tertiary"
iconName="list"
$theme="primary"
$variation="800"
variant="symbols-outlined"
/>
</BoxButton>
@@ -173,7 +170,7 @@ export const TableContent = () => {
$justify="space-between"
$align="center"
>
<Text $weight="500" $size="sm" $variation="800" $theme="primary">
<Text $weight="500" $size="sm">
{t('Summary')}
</Text>
<BoxButton
@@ -188,12 +185,12 @@ export const TableContent = () => {
transform: rotate(180deg);
&:focus-visible {
outline: none;
box-shadow: 0 0 0 2px ${colorsTokens['primary-400']};
border-radius: 4px;
box-shadow: 0 0 0 2px ${colorsTokens['brand-400']};
border-radius: var(--c--globals--spacings--st);
}
`}
>
<Icon iconName="menu_open" $theme="primary" $variation="800" />
<Icon iconName="menu_open" $theme="brand" $variation="tertiary" />
</BoxButton>
</Box>
<Box

View File

@@ -1,4 +1,5 @@
import {
TreeViewDataType,
TreeViewItem,
TreeViewNodeProps,
useTreeContext,
@@ -39,7 +40,7 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
const treeContext = useTreeContext<Doc>();
const { untitledDocument } = useTrans();
const { node } = props;
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
const { isDesktop } = useResponsiveStore();
const { t } = useTranslation();
@@ -68,7 +69,10 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
node.open();
router.push(`/docs/${createdDoc.id}`);
treeContext?.treeData.setChildren(node.data.value.id, allChildren);
treeContext?.treeData.setChildren(
node.data.value.id,
allChildren as TreeViewDataType<Doc>[],
);
treeContext?.treeData.setSelectedNode(createdDoc);
togglePanel();
})
@@ -114,33 +118,24 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
aria-expanded={hasChildren ? isExpanded : undefined}
aria-disabled={isDisabled}
$css={css`
background-color: ${menuOpen
? 'var(--c--theme--colors--greyscale-100)'
: 'var(--c--theme--colors--greyscale-000)'};
background-color: var(--c--globals--colors--gray-000);
.light-doc-item-actions {
display: ${menuOpen || !isDesktop ? 'flex' : 'none'};
position: absolute;
right: 0;
background: ${isDesktop
? 'var(--c--theme--colors--greyscale-100)'
: 'var(--c--theme--colors--greyscale-000)'};
}
.c__tree-view--node.isSelected {
.light-doc-item-actions {
background: var(--c--theme--colors--greyscale-100);
}
right: var(--c--globals--spacings--0);
}
.c__tree-view--node.isFocused {
outline: none !important;
box-shadow: 0 0 0 2px var(--c--theme--colors--primary-500) !important;
border-radius: 4px;
box-shadow: 0 0 0 2px var(--c--globals--colors--brand-500) !important;
border-radius: var(--c--globals--spacings--st);
}
&:hover {
background-color: var(--c--theme--colors--greyscale-100);
border-radius: 4px;
background-color: var(
--c--contextuals--background--semantic--gray--tertiary
);
border-radius: var(--c--globals--spacings--st);
.light-doc-item-actions {
display: flex;
background: var(--c--theme--colors--greyscale-100);
}
}
.row.preview & {
@@ -152,7 +147,9 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
<DocIcon
emoji={emoji}
withEmojiPicker={doc.abilities.partial_update}
defaultIcon={<SubPageIcon color={colorsTokens['primary-400']} />}
defaultIcon={
<SubPageIcon color="var(--c--contextuals--content--semantic--info--tertiary)" />
}
$size="sm"
docId={doc.id}
title={doc.title}
@@ -187,15 +184,14 @@ export const DocSubPageItem = (props: TreeViewNodeProps<Doc>) => {
overflow: hidden;
`}
>
<Text $css={ItemTextCss} $size="sm" $variation="1000">
<Text $css={ItemTextCss} $size="sm">
{displayTitle}
</Text>
{doc.nb_accesses_direct >= 1 && (
<Icon
variant="filled"
iconName="group"
$size="16px"
$variation="400"
$size="md"
aria-hidden="true"
/>
)}

View File

@@ -215,24 +215,26 @@ export const DocTree = ({ currentDoc }: DocTreeProps) => {
onKeyDown={handleRootKeyDown}
$css={css`
padding: ${spacingsTokens['2xs']};
border-radius: 4px;
border-radius: var(--c--globals--spacings--st);
width: 100%;
background-color: ${rootIsSelected || rootActionsOpen
? 'var(--c--theme--colors--greyscale-100)'
? 'var(--c--contextuals--background--semantic--contextual--primary)'
: 'transparent'};
&:hover {
background-color: var(--c--theme--colors--greyscale-100);
background-color: var(
--c--contextuals--background--semantic--contextual--primary
);
}
&:focus-visible {
outline: none !important;
box-shadow: 0 0 0 2px var(--c--theme--colors--primary-500) !important;
border-radius: 4px;
box-shadow: 0 0 0 2px var(--c--globals--colors--brand-500) !important;
border-radius: var(--c--globals--spacings--st);
}
.doc-tree-root-item-actions {
display: 'flex';
display: flex;
opacity: ${rootActionsOpen ? '1' : '0'};
&:has(.isOpen) {

View File

@@ -119,7 +119,7 @@ export const DocTreeItemActions = ({
: []),
{
label: t('Duplicate'),
icon: <Icon $variation="600" iconName="content_copy" />,
icon: <Icon iconName="content_copy" />,
isDisabled: !doc.abilities.duplicate,
callback: () => {
duplicateDoc({
@@ -180,8 +180,8 @@ export const DocTreeItemActions = ({
}}
iconName="more_horiz"
variant="filled"
$theme="primary"
$variation="600"
$theme="brand"
$variation="secondary"
aria-label={t('More options')}
/>
</DropdownMenu>
@@ -195,16 +195,12 @@ export const DocTreeItemActions = ({
parentId: doc.id,
});
}}
color="primary"
$theme="brand"
$variation="secondary"
aria-label={t('Add a sub page')}
data-testid="doc-tree-item-actions-add-child"
>
<Icon
variant="filled"
$variation="800"
$theme="primary"
iconName="add_box"
/>
<Icon variant="filled" $color="inherit" iconName="add_box" />
</BoxButton>
)}
</Box>

View File

@@ -74,7 +74,7 @@ export const ModalConfirmationVersion = ({
<>
<Button
aria-label={`${t('Cancel')} - ${t('Warning')}`}
color="secondary"
variant="secondary"
fullWidth
onClick={() => onClose()}
>
@@ -82,7 +82,7 @@ export const ModalConfirmationVersion = ({
</Button>
<Button
aria-label={t('Restore')}
color="danger"
color="error"
fullWidth
onClick={() => {
if (!version?.content) {
@@ -109,7 +109,6 @@ export const ModalConfirmationVersion = ({
id="modal-confirmation-version-title"
$size="h6"
$align="flex-start"
$variation="1000"
>
{t('Warning')}
</Text>
@@ -117,10 +116,10 @@ export const ModalConfirmationVersion = ({
>
<Box className="--docs--modal-confirmation-version">
<Box>
<Text $variation="600" as="p">
<Text $variation="secondary" as="p">
{t('Your current document will revert to this version.')}
</Text>
<Text $variation="600" as="p">
<Text $variation="secondary" as="p">
{t('If a member is editing, his works can be lost.')}
</Text>
</Box>

View File

@@ -102,7 +102,7 @@ export const ModalSelectVersion = ({
$height="calc(100vh - 2em - 12px)"
$css={css`
overflow-y: hidden;
border-left: 1px solid var(--c--theme--colors--greyscale-200);
border-left: 1px solid var(--c--globals--colors--gray-200);
`}
>
<Box
@@ -118,12 +118,11 @@ export const ModalSelectVersion = ({
$direction="row"
$align="center"
$css={css`
border-bottom: 1px solid
var(--c--theme--colors--greyscale-200);
border-bottom: 1px solid var(--c--globals--colors--gray-200);
`}
$padding="sm"
>
<Text $size="h6" $variation="1000" $weight="bold">
<Text $size="h6" $weight="bold">
{t('History')}
</Text>
<ButtonCloseModal
@@ -143,14 +142,13 @@ export const ModalSelectVersion = ({
<Box
$padding="xs"
$css={css`
border-top: 1px solid var(--c--theme--colors--greyscale-200);
border-top: 1px solid var(--c--globals--colors--gray-200);
`}
>
<Button
fullWidth
disabled={!selectedVersionId}
onClick={restoreModal.open}
color="primary"
>
{t('Restore')}
</Button>

View File

@@ -32,13 +32,13 @@ export const VersionItem = ({
<Box
$width="100%"
as="li"
$background={isActive ? colorsTokens['greyscale-100'] : 'transparent'}
$background={isActive ? colorsTokens['gray-100'] : 'transparent'}
$radius={spacingsTokens['3xs']}
$css={`
cursor: pointer;
&:hover {
background: ${colorsTokens['greyscale-100']};
background: ${colorsTokens['gray-100']};
}
`}
$hasTransition
@@ -53,7 +53,7 @@ export const VersionItem = ({
$width="100%"
>
<Box $direction="row" $gap="0.5rem" $align="center">
<Text $weight="bold" $size="sm" $variation="1000">
<Text $weight="bold" $size="sm">
{text}
</Text>
</Box>

View File

@@ -6,7 +6,7 @@ import { useQueryClient } from '@tanstack/react-query';
import { useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
import { AlertModal, Box, Text } from '@/components';
import { AlertModal, Card, Text } from '@/components';
import { Doc, KEY_LIST_DOC } from '@/docs/doc-management';
import {
getDocAccesses,
@@ -147,19 +147,8 @@ export const DraggableDocGridContentList = ({
return selectedDoc?.title || t('Unnamed document');
}, [canDrag, canDrop, selectedDoc, t]);
const overlayBgColor = useMemo(() => {
if (!canDrag) {
return 'var(--c--theme--colors--danger-600)';
}
if (canDrop !== undefined && !canDrop) {
return 'var(--c--theme--colors--danger-600)';
}
if (isError) {
return 'var(--c--theme--colors--danger-600)';
}
return '#5858D3';
}, [canDrag, canDrop, isError]);
const cannotMoveDoc =
!canDrag || (canDrop !== undefined && !canDrop) || isError;
if (docs.length === 0) {
return null;
@@ -183,20 +172,20 @@ export const DraggableDocGridContentList = ({
/>
))}
<DragOverlay dropAnimation={null}>
<Box
<Card
$width="fit-content"
$padding={{ horizontal: 'xs', vertical: '3xs' }}
$radius="12px"
$background={overlayBgColor}
data-testid="drag-doc-overlay"
$height="auto"
role="alert"
aria-label={t('Drag and drop status')}
aria-label={t('Drag and drop status')}
$theme={cannotMoveDoc ? 'error' : 'brand'}
$variation="tertiary"
$scope="semantic"
>
<Text $size="xs" $variation="000" $weight="500">
<Text $size="xs" $weight="500" $withThemeInherited>
{overlayText}
</Text>
</Box>
</Card>
</DragOverlay>
</DndContext>
{modalConfirmation.isOpen && (

View File

@@ -98,18 +98,13 @@ export const DocsGrid = ({
bottom: 'md',
}}
>
<Text
as="h2"
$size="h4"
$variation="1000"
$margin={{ top: '0px', bottom: '10px' }}
>
<Text as="h2" $size="h4" $margin={{ top: '0px', bottom: '10px' }}>
{title}
</Text>
{!hasDocs && !loading && (
<Box $padding={{ vertical: 'sm' }} $align="center" $justify="center">
<Text $size="sm" $variation="600" $weight="700">
<Text $size="sm" $weight="700">
{t('No documents found')}
</Text>
</Box>
@@ -126,7 +121,7 @@ export const DocsGrid = ({
role="row"
>
<Box $flex={flexLeft} $padding="3xs" role="columnheader">
<Text $size="xs" $variation="600" $weight="500">
<Text $size="xs" $variation="secondary" $weight="500">
{t('Name')}
</Text>
</Box>
@@ -136,7 +131,7 @@ export const DocsGrid = ({
$padding={{ vertical: '3xs' }}
role="columnheader"
>
<Text $size="xs" $weight="500" $variation="600">
<Text $size="xs" $weight="500" $variation="secondary">
{DocDefaultFilter.TRASHBIN === target
? t('Days remaining')
: t('Updated at')}
@@ -162,7 +157,8 @@ export const DocsGrid = ({
{!isFetching && hasNextPage && (
<Button
onClick={() => void fetchNextPage()}
color="primary-text"
color="brand"
variant="tertiary"
>
{t('More docs')}
</Button>

View File

@@ -89,12 +89,17 @@ export const DocsGridActions = ({
options={options}
label={menuLabel}
aria-label={t('More options')}
buttonCss={css`
&:hover {
background-color: unset;
}
`}
>
<Icon
data-testid={`docs-grid-actions-button-${doc.id}`}
iconName="more_horiz"
$theme="primary"
$variation="600"
$theme="brand"
$variation="secondary"
$css={css`
cursor: pointer;
&:hover {

View File

@@ -63,7 +63,7 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
&:hover {
background-color: ${dragMode
? 'none'
: 'var(--c--theme--colors--greyscale-100)'};
: 'var(--c--contextuals--background--semantic--contextual--primary)'};
}
`}
className="--docs--doc-grid-item"
@@ -111,8 +111,9 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
{dragMode && (
<>
<Icon
$theme="greyscale"
$variation="600"
$layer="background"
$theme="neutral"
$variation="primary"
$size="14px"
iconName={isPublic ? 'public' : 'vpn_lock'}
/>
@@ -126,7 +127,7 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
{!dragMode && (
<Tooltip
content={
<Text $textAlign="center" $variation="000">
<Text $textAlign="center">
{isPublic
? t('Accessible to anyone')
: t('Accessible to authenticated users')}
@@ -136,9 +137,10 @@ export const DocsGridItem = ({ doc, dragMode = false }: DocsGridItemProps) => {
>
<div>
<Icon
$theme="greyscale"
$variation="600"
$size="14px"
$layer="background"
$theme="neutral"
$variation="primary"
$size="sm"
iconName={isPublic ? 'public' : 'vpn_lock'}
/>
<span className="sr-only">
@@ -222,7 +224,12 @@ export const DocsGridItemDate = ({
return (
<StyledLink href={`/docs/${doc.id}`}>
<Text $variation="600" $size="xs">
<Text
$size="xs"
$layer="background"
$theme="neutral"
$variation="primary"
>
{dateToDisplay}
</Text>
</StyledLink>

View File

@@ -25,7 +25,7 @@ export const DocsGridItemSharedButton = ({
return (
<Tooltip
content={
<Text $textAlign="center" $variation="000">
<Text $textAlign="center">
{t('Shared with {{count}} users', { count: sharedCount })}
</Text>
}
@@ -37,17 +37,25 @@ export const DocsGridItemSharedButton = ({
aria-label={t('Open the sharing settings for the document')}
data-testid={`docs-grid-item-shared-button-${doc.id}`}
style={{
minWidth: '50px',
justifyContent: 'center',
padding: `0 var(--c--globals--spacings--xxxs) 0 var(--c--globals--spacings--xxxs)`,
}}
onClick={(event) => {
event.preventDefault();
event.stopPropagation();
handleClick();
}}
color="tertiary"
color="brand"
variant="secondary"
size="nano"
icon={<Icon $theme="primary" iconName="group" disabled={disabled} />}
icon={
<Icon
$theme="brand"
$variation="secondary"
iconName="group"
disabled={disabled}
variant="filled"
/>
}
disabled={disabled}
>
{sharedCount}

View File

@@ -44,8 +44,6 @@ export const DocsGridTrashbinActions = ({
icon: (
<Icon
$size="20px"
$theme="greyscale"
$variation="1000"
iconName="undo"
aria-hidden="true"
variant="symbols-outlined"
@@ -70,12 +68,17 @@ export const DocsGridTrashbinActions = ({
options={options}
label={menuLabel}
aria-label={t('More options')}
buttonCss={css`
&:hover {
background-color: unset;
}
`}
>
<Icon
data-testid={`docs-grid-actions-button-${doc.id}`}
iconName="more_horiz"
$theme="primary"
$variation="600"
$theme="brand"
$variation="secondary"
$css={css`
cursor: pointer;
&:hover {

View File

@@ -37,13 +37,13 @@ export const Droppable = ({
data-testid={`droppable-doc-${id}`}
role="none"
$css={css`
border-radius: 4px;
border-radius: var(--c--globals--spacings--st);
background-color: ${enableHover
? 'var(--c--theme--colors--primary-100)'
? 'var(--c--globals--colors--brand-100)'
: 'transparent'};
border: 1.5px solid
${enableHover
? 'var(--c--theme--colors--primary-500)'
? 'var(--c--globals--colors--brand-500)'
: 'transparent'};
`}
className="--docs--grid-droppable"

View File

@@ -15,7 +15,7 @@ const BlueStripe = styled.div`
position: absolute;
height: 2px;
width: 100%;
background: var(--c--theme--colors--primary-600);
background: var(--c--globals--colors--brand-700);
top: 0;
`;
@@ -83,7 +83,6 @@ export const Footer = () => {
>
{logo?.src && (
<Image
className="c__image-system-filter"
priority
src={logo.src}
alt={logo?.alt || t('Logo')}
@@ -116,11 +115,14 @@ export const Footer = () => {
key={label}
href={href}
target="__blank"
$css={`
gap:0.2rem;
$css={css`
gap: 0.2rem;
transition: box-shadow 0.3s;
&:hover {
box-shadow: 0px 2px 0 0 var(--c--theme--colors--greyscale-text);
box-shadow: 0px 2px 0 0
var(
--c--contextuals--content--semantic--neutral--secondary
);
}
`}
>
@@ -136,7 +138,7 @@ export const Footer = () => {
$padding={{ top: 'tiny' }}
$css={`
flex-wrap: wrap;
border-top: 1px solid var(--c--theme--colors--greyscale-200);
border-top: 1px solid var(--c--globals--colors--gray-200);
column-gap: 1rem;
row-gap: .5rem;
`}
@@ -151,18 +153,20 @@ export const Footer = () => {
padding-right: 1rem;
&:not(:last-child) {
box-shadow: inset -1px 0px 0px 0px
var(--c--theme--colors--greyscale-200);
var(--c--globals--colors--gray-200);
}
`}
>
<Text
$variation="600"
$size="m"
$size="s"
$variation="secondary"
$transition="box-shadow 0.3s"
$css={css`
&:hover {
box-shadow: 0px 2px 0 0
var(--c--theme--colors--greyscale-text);
var(
--c--contextuals--content--semantic--neutral--secondary
);
}
`}
>
@@ -174,9 +178,9 @@ export const Footer = () => {
{bottomInformation && (
<Text
as="p"
$size="m"
$size="s"
$margin={{ top: 'big' }}
$variation="600"
$variation="secondary"
$display="inline"
className="--docs--footer-licence"
>
@@ -188,11 +192,11 @@ export const Footer = () => {
$css={css`
display: inline-flex;
box-shadow: 0px 1px 0 0
var(--c--theme--colors--greyscale-text);
var(--c--contextuals--content--semantic--neutral--secondary);
gap: 0.2rem;
`}
>
<Text $variation="600">{bottomInformation.link.label}</Text>
<Text>{bottomInformation.link.label}</Text>
<IconLink width={14} />
</StyledLink>
)}

View File

@@ -13,13 +13,9 @@ export const ButtonTogglePanel = () => {
size="medium"
onClick={() => togglePanel()}
aria-label={t('Open the header menu')}
color="tertiary-text"
variant="tertiary"
icon={
<Icon
$variation="800"
$theme="primary"
iconName={isPanelOpen ? 'close' : 'menu'}
/>
<Icon $withThemeInherited iconName={isPanelOpen ? 'close' : 'menu'} />
}
className="--docs--button-toggle-panel"
/>

View File

@@ -18,7 +18,7 @@ import { Title } from './Title';
export const Header = () => {
const { t } = useTranslation();
const { data: config } = useConfig();
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
const { isDesktop } = useResponsiveStore();
const logo = config?.theme_customization?.header?.logo;
@@ -38,8 +38,8 @@ export const Header = () => {
justify-content: space-between;
height: ${HEADER_HEIGHT}px;
padding: 0 ${spacingsTokens['base']};
background-color: ${colorsTokens['greyscale-000']};
border-bottom: 1px solid ${colorsTokens['greyscale-200']};
background-color: var(--c--contextuals--background--surface--primary);
border-bottom: 1px solid var(--c--contextuals--border--surface--primary);
`}
className="--docs--header"
>
@@ -51,8 +51,8 @@ export const Header = () => {
$css={css`
outline: none;
&:focus-visible {
box-shadow: 0 0 0 2px var(--c--theme--colors--primary-400) !important;
border-radius: 4px;
box-shadow: 0 0 0 2px var(--c--globals--colors--brand-400) !important;
border-radius: var(--c--globals--spacings--st);
}
`}
>

View File

@@ -9,6 +9,12 @@ import { useCunninghamTheme } from '@/cunningham';
const GaufreStyle = createGlobalStyle`
.lasuite-gaufre-btn{
box-shadow: inset 0 0 0 0 !important;
border-radius: var(--c--components--button--border-radius) !important;
transition: all var(--c--globals--transitions--duration) var(--c--globals--transitions--ease-out) !important;
&:hover, &:focus-visible {
background: var(--c--contextuals--background--semantic--contextual--primary) !important;
}
color: var(--c--contextuals--content--semantic--brand--tertiary) !important;
}
`;

View File

@@ -1,7 +1,6 @@
import { useTranslation } from 'react-i18next';
import { Box, Text } from '@/components/';
import { useCunninghamTheme } from '@/cunningham';
import { Text } from '@/components/';
type TitleSemanticsProps = {
headingLevel?: 'h1' | 'h2' | 'h3';
@@ -9,24 +8,19 @@ type TitleSemanticsProps = {
export const Title = ({ headingLevel = 'h2' }: TitleSemanticsProps) => {
const { t } = useTranslation();
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
return (
<Box
<Text
className="--docs--title"
$direction="row"
$align="center"
$gap={spacingsTokens['2xs']}
className="--docs--title"
$margin="none"
as={headingLevel}
$zIndex={1}
$size="1.375rem"
$color="var(--c--contextuals--content--logo1)"
>
<Text
$margin="none"
as={headingLevel}
$color={colorsTokens['primary-text']}
$zIndex={1}
$size="1.375rem"
>
{t('Docs')}
</Text>
</Box>
{t('Docs')}
</Text>
);
};

View File

@@ -3,8 +3,8 @@ import Image from 'next/image';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import IconDocs from '@/assets/icons/icon-docs.svg';
import { Box, Icon, Text } from '@/components';
import { useConfig } from '@/core';
import { useCunninghamTheme } from '@/cunningham';
import { ProConnectButton, gotoLogin } from '@/features/auth';
import { useResponsiveStore } from '@/stores';
@@ -15,10 +15,13 @@ import { getHeaderHeight } from './HomeHeader';
export default function HomeBanner() {
const { t } = useTranslation();
const { componentTokens, spacingsTokens, colorsTokens } =
useCunninghamTheme();
const { componentTokens, spacingsTokens } = useCunninghamTheme();
const { isMobile, isSmallMobile } = useResponsiveStore();
const withProConnect = componentTokens['home-proconnect'];
const { data: config } = useConfig();
const icon =
config?.theme_customization?.header?.icon || componentTokens.icon;
return (
<Box
@@ -47,15 +50,21 @@ export default function HomeBanner() {
$align="center"
$gap={spacingsTokens['sm']}
>
<IconDocs
aria-label={t('Back to homepage')}
width={64}
color={colorsTokens['primary-text']}
<Image
data-testid="header-icon-docs"
src={icon.src || ''}
alt=""
width={0}
height={0}
style={{
width: '64px',
height: 'auto',
}}
priority
/>
<Text
as="h2"
$size={!isMobile ? 'xs-alt' : '2.3rem'}
$variation="800"
$weight="bold"
$textAlign="center"
$margin="none"
@@ -67,9 +76,9 @@ export default function HomeBanner() {
</Text>
<Text
$size="lg"
$variation="700"
$textAlign="center"
$margin={{ bottom: 'small' }}
$variation="secondary"
>
{t(
'Collaborate and write in real time, without layout constraints.',
@@ -88,7 +97,6 @@ export default function HomeBanner() {
</Box>
{!isMobile && (
<Image
className="c__image-system-filter"
src={banner}
alt={t('Banner image')}
priority
@@ -104,10 +112,9 @@ export default function HomeBanner() {
</Box>
<Box $css="bottom: 3rem" $position="absolute">
<Button
color="secondary"
icon={
<Icon $theme="primary" $variation="800" iconName="expand_more" />
}
color="brand"
variant="secondary"
icon={<Icon $color="inherit" iconName="expand_more" />}
onClick={(e) => {
e.preventDefault();
document

View File

@@ -20,7 +20,7 @@ export function HomeBottom() {
function HomeProConnect() {
const { t } = useTranslation();
const { spacingsTokens, colorsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
const { isMobile } = useResponsiveStore();
const parentGap = '230px';
@@ -43,15 +43,12 @@ function HomeProConnect() {
$position="relative"
$height="fit-content"
$css="zoom: 1.9;"
$theme="brand"
>
<IconDocs
aria-label={t('Docs Logo')}
width={34}
color={colorsTokens['primary-text']}
/>
<IconDocs aria-label={t('Docs Logo')} width={34} />
<Title />
</Box>
<Text $size="md" $variation="1000" $textAlign="center">
<Text $size="md" $variation="secondary" $textAlign="center">
{t('Docs is already available, log in to use it now.')}
</Text>
<ProConnectButton />

View File

@@ -3,7 +3,6 @@ import { Trans, useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, Icon, Text } from '@/components';
import { useCunninghamTheme } from '@/cunningham';
import { Footer } from '@/features/footer';
import { LeftPanel } from '@/features/left-panel';
import { useResponsiveStore } from '@/stores';
@@ -28,7 +27,6 @@ import { HomeSection } from './HomeSection';
export function HomeContent() {
const { i18n, t } = useTranslation();
const { colorsTokens } = useCunninghamTheme();
const { isMobile, isSmallMobile, isTablet } = useResponsiveStore();
const isFrLanguage = i18n.resolvedLanguage === 'fr';
@@ -76,84 +74,89 @@ export function HomeContent() {
textWidth="60%"
$css={`min-height: calc(100vh - ${getHeaderHeight(isSmallMobile)}px);`}
description={
<Box
$css={css`
& a {
color: ${colorsTokens['primary-600']};
}
`}
>
<Text as="p" $display="inline">
<Trans t={t} i18nKey="home-content-open-source-part1">
Docs is built on top of{' '}
<a
href="https://www.django-rest-framework.org/"
target="_blank"
>
Django Rest Framework
</a>{' '}
and{' '}
<a href="https://nextjs.org/" target="_blank">
Next.js
</a>
. We also use{' '}
<a href="https://github.com/yjs" target="_blank">
Yjs
</a>{' '}
and{' '}
<a href="https://www.blocknotejs.org/" target="_blank">
BlockNote.js
</a>
, both of which we are proud to sponsor.
</Trans>
</Text>
<Text as="p" $display="inline">
<Trans t={t} i18nKey="home-content-open-source-part2">
You can easily self-host Docs (check our installation{' '}
<a
href="https://github.com/suitenumerique/docs/tree/main/docs"
target="_blank"
>
documentation
</a>
).
<br />
Docs uses an innovation and business friendly{' '}
<a
href="https://github.com/suitenumerique/docs/blob/main/LICENSE"
target="_blank"
>
licence
</a>{' '}
(MIT).
<br />
Contributions are welcome (see our roadmap{' '}
<a
href="https://github.com/orgs/numerique-gouv/projects/13/views/11"
target="_blank"
>
here
</a>
).
</Trans>
</Text>
<Text as="p" $display="inline">
<Trans t={t} i18nKey="home-content-open-source-part3">
Docs is the result of a joint effort lead by the French
🇫🇷🥖
<a
href="https://www.numerique.gouv.fr/dinum/"
target="_blank"
>
(DINUM)
</a>{' '}
and German 🇩🇪🥨 governments{' '}
<a href="https://zendis.de/" target="_blank">
(ZenDiS)
</a>
.
</Trans>
</Text>
<Box>
<Box
$css={css`
& a {
color: inherit;
}
`}
>
<Text as="p" $display="inline" $variation="secondary">
<Trans t={t} i18nKey="home-content-open-source-part1">
Docs is built on top of{' '}
<a
href="https://www.django-rest-framework.org/"
target="_blank"
>
Django Rest Framework
</a>{' '}
and{' '}
<a href="https://nextjs.org/" target="_blank">
Next.js
</a>
. We also use{' '}
<a href="https://github.com/yjs" target="_blank">
Yjs
</a>{' '}
and{' '}
<a
href="https://www.blocknotejs.org/"
target="_blank"
>
BlockNote.js
</a>
, both of which we are proud to sponsor.
</Trans>
</Text>
<Text as="p" $display="inline">
<Trans t={t} i18nKey="home-content-open-source-part2">
You can easily self-host Docs (check our installation{' '}
<a
href="https://github.com/suitenumerique/docs/tree/main/docs"
target="_blank"
>
documentation
</a>
).
<br />
Docs uses an innovation and business friendly{' '}
<a
href="https://github.com/suitenumerique/docs/blob/main/LICENSE"
target="_blank"
>
licence
</a>{' '}
(MIT).
<br />
Contributions are welcome (see our roadmap{' '}
<a
href="https://github.com/orgs/numerique-gouv/projects/13/views/11"
target="_blank"
>
here
</a>
).
</Trans>
</Text>
<Text as="p" $display="inline">
<Trans t={t} i18nKey="home-content-open-source-part3">
Docs is the result of a joint effort lead by the
French 🇫🇷🥖
<a
href="https://www.numerique.gouv.fr/dinum/"
target="_blank"
>
(DINUM)
</a>{' '}
and German 🇩🇪🥨 governments{' '}
<a href="https://zendis.de/" target="_blank">
(ZenDiS)
</a>
.
</Trans>
</Text>
</Box>
<Box
$direction="row"
$gap="1rem"
@@ -164,10 +167,11 @@ export function HomeContent() {
href="https://matrix.to/#/#docs-official:matrix.org"
target="_blank"
>
<Text $color="white">Matrix</Text>
Matrix
</Button>
<Button
color="secondary"
color="neutral"
variant="secondary"
icon={<GithubIcon />}
href="https://github.com/suitenumerique/docs"
target="_blank"

View File

@@ -117,7 +117,6 @@ export const HomeSection = ({
$css={css`
line-height: ${!isSmallDevice ? '50px' : 'normal'};
`}
$variation="1000"
$weight="bold"
$size={!isSmallDevice ? 'xs-alt' : isSmallMobile ? 'h6' : 'h4'}
$textAlign="left"
@@ -127,7 +126,7 @@ export const HomeSection = ({
</Text>
<Text
as="div"
$variation="700"
$variation="secondary"
$weight="400"
$size={isSmallMobile ? 'ml' : 'md'}
>
@@ -175,7 +174,6 @@ export const HomeSection = ({
{illustration && (isSmallDevice || !video) && (
<Image
className="c__image-system-filter"
src={illustration}
alt={t('Illustration')}
style={{
@@ -200,28 +198,19 @@ const SectionTag = ({
tag: string;
availableSoon?: boolean;
}) => {
const { colorsTokens, spacingsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
return (
<Box
$background={
!availableSoon
? colorsTokens['primary-100']
: colorsTokens['warning-100']
}
$padding={{ horizontal: spacingsTokens['sm'], vertical: '6px' }}
$css={css`
align-self: flex-start;
border-radius: 4px;
border-radius: var(--c--globals--spacings--st);
`}
$theme={availableSoon ? 'warning' : 'brand'}
$variation="tertiary"
$withThemeBG
>
<Text
$size="md"
$variation={availableSoon ? '600' : '800'}
$weight="bold"
$theme={availableSoon ? 'warning' : 'primary'}
>
{tag}
</Text>
{tag}
</Box>
);
};

View File

@@ -2,7 +2,7 @@ import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { DropdownMenu, Icon, Text } from '@/components/';
import { Box, DropdownMenu, Icon } from '@/components/';
import { useConfig } from '@/core';
import { useAuthQuery } from '@/features/auth';
import {
@@ -41,32 +41,32 @@ export const LanguagePicker = () => {
showArrow
label={t('Select language')}
buttonCss={css`
transition: all 0.15s ease-in-out !important;
border-radius: 4px;
transition: all var(--c--globals--transitions--duration)
var(--c--globals--transitions--ease-out) !important;
border-radius: var(--c--globals--spacings--st);
padding: 0.5rem 0.6rem;
& > div {
gap: 0.2rem;
display: flex;
}
& .material-icons {
color: var(--c--components--button--primary-text--color) !important;
color: var(
--c--contextuals--content--palette--brand--primary
) !important;
}
`}
>
<Text
$theme="primary"
<Box
className="--docs--language-picker-text"
$theme="brand"
$variation="tertiary"
$direction="row"
$gap="0.5rem"
className="--docs--language-picker-text"
$align="center"
>
<Icon
iconName="translate"
$color="inherit"
$size="xl"
aria-hidden="true"
/>
<Icon iconName="translate" $color="inherit" $size="xl" />
{currentLanguageLabel}
</Text>
</Box>
</DropdownMenu>
);
};

View File

@@ -78,29 +78,26 @@ export const LeftPanelTargetFilters = () => {
padding: ${spacingsTokens['2xs']};
border-radius: ${spacingsTokens['3xs']};
background-color: ${isActive
? colorsTokens['greyscale-100']
? 'var(--c--contextuals--background--semantic--contextual--primary)'
: 'transparent'};
font-weight: ${isActive ? 700 : 400};
color: inherit;
text-decoration: none;
cursor: pointer;
&:hover {
background-color: ${colorsTokens['greyscale-100']};
background-color: var(
--c--contextuals--background--semantic--contextual--primary
);
}
&:focus-visible {
outline: none !important;
box-shadow: 0 0 0 2px ${colorsTokens['primary-500']} !important;
border-radius: 4px;
box-shadow: 0 0 0 2px ${colorsTokens['brand-400']} !important;
border-radius: var(--c--globals--spacings--st);
}
`}
>
<Icon
$variation={isActive ? '1000' : '700'}
iconName={query.icon}
/>
<Text $variation={isActive ? '1000' : '700'} $size="sm">
{query.label}
</Text>
<Icon iconName={query.icon} />
<Text $size="sm">{query.label}</Text>
</StyledLink>
);
})}

View File

@@ -25,7 +25,7 @@ export const LeftPanel = () => {
const { isDesktop } = useResponsiveStore();
const { t } = useTranslation();
const { colorsTokens, spacingsTokens } = useCunninghamTheme();
const { spacingsTokens } = useCunninghamTheme();
const { togglePanel, isPanelOpen } = useLeftPanelStore();
const pathname = usePathname();
@@ -43,7 +43,7 @@ export const LeftPanel = () => {
height: calc(100vh - ${HEADER_HEIGHT}px);
width: 100%;
overflow: hidden;
background-color: ${colorsTokens['greyscale-000']};
background-color: var(--c--globals--colors--gray-000);
`}
className="--docs--left-panel-desktop"
as="nav"
@@ -69,10 +69,10 @@ export const LeftPanel = () => {
z-index: 999;
width: 100dvw;
height: calc(100dvh - 52px);
border-right: 1px solid var(--c--theme--colors--greyscale-200);
border-right: 1px solid var(--c--globals--colors--gray-200);
position: fixed;
transform: translateX(${isPanelOpen ? '0' : '-100dvw'});
background-color: var(--c--theme--colors--greyscale-000);
background-color: var(--c--globals--colors--gray-000);
overflow-y: auto;
overflow-x: hidden;
`}

View File

@@ -32,11 +32,16 @@ export const LeftPanelFavoriteItem = ({ doc }: LeftPanelFavoriteItemProps) => {
opacity: ${isDesktop ? 0 : 1};
}
&:hover {
background-color: ${colorsTokens['greyscale-100']};
background-color: var(
--c--contextuals--background--semantic--contextual--primary
);
.pinned-actions {
opacity: 1;
}
}
&:focus-within {
cursor: pointer;
box-shadow: 0 0 0 2px ${colorsTokens['primary-500']} !important;
box-shadow: 0 0 0 2px ${colorsTokens['brand-400']} !important;
.pinned-actions {
opacity: 1;
}
@@ -55,9 +60,9 @@ export const LeftPanelFavoriteItem = ({ doc }: LeftPanelFavoriteItemProps) => {
>
<SimpleDocItem showAccesses doc={doc} />
</StyledLink>
<div className="pinned-actions">
<Box className="pinned-actions" $align="center">
<DocsGridActions doc={doc} openShareModal={shareModal.open} />
</div>
</Box>
{shareModal.isOpen && (
<DocShareModal doc={doc} onClose={shareModal.close} />
)}

View File

@@ -38,7 +38,6 @@ export const LeftPanelFavorites = () => {
>
<Text
$size="sm"
$variation="700"
$padding={{ horizontal: '3xs' }}
$weight="700"
id="pinned-docs-title"
@@ -46,7 +45,7 @@ export const LeftPanelFavorites = () => {
{t('Pinned documents')}
</Text>
<Box>
<Box as="ul" $padding="none">
<Box as="ul" $padding="none" $margin={{ top: '4xs' }}>
{favoriteDocs.map((doc) => (
<LeftPanelFavoriteItem key={doc.id} doc={doc} />
))}

View File

@@ -52,42 +52,45 @@ export const LeftPanelHeader = ({ children }: PropsWithChildren) => {
$justify="space-between"
$align="center"
>
<Box $direction="row" $gap="2px">
<Button
data-testid="home-button"
onClick={goToHome}
aria-label={t('Back to homepage')}
size="medium"
color="tertiary-text"
icon={
<Icon
$variation="800"
$theme="primary"
iconName="house"
aria-hidden="true"
/>
}
/>
{authenticated && (
<Button
data-testid="search-docs-button"
onClick={openSearchModal}
size="medium"
color="tertiary-text"
aria-label={t('Search docs')}
icon={
<Icon
$variation="800"
$theme="primary"
iconName="search"
aria-hidden="true"
/>
}
/>
)}
</Box>
{authenticated && <LeftPanelHeaderButton />}
{(router.pathname !== '/' || authenticated) && (
<Box $direction="row" $gap="2px">
{router.pathname !== '/' && (
<Button
data-testid="home-button"
onClick={goToHome}
aria-label={t('Back to homepage')}
size="medium"
color="brand"
variant="tertiary"
icon={
<Icon
$color="inherit"
iconName="house"
aria-hidden="true"
/>
}
/>
)}
{authenticated && (
<Button
data-testid="search-docs-button"
onClick={openSearchModal}
size="medium"
color="brand"
variant="tertiary"
aria-label={t('Search docs')}
icon={
<Icon
$color="inherit"
iconName="search"
aria-hidden="true"
/>
}
/>
)}
</Box>
)}
</Box>
</SeparatedSection>
{children}

View File

@@ -50,9 +50,9 @@ export const LeftPanelHeaderButton = () => {
return (
<Button
data-testid="new-doc-button"
color="primary"
color="brand"
onClick={handleClick}
icon={<Icon $variation="000" iconName="add" aria-hidden="true" />}
icon={<Icon $color="inherit" iconName="add" aria-hidden="true" />}
disabled={isLoading}
>
{t('New doc')}

View File

@@ -6,8 +6,6 @@ import {
PanelResizeHandle,
} from 'react-resizable-panels';
import { useCunninghamTheme } from '@/cunningham';
// Convert a target pixel width to a percentage of the current viewport width.
const pxToPercent = (px: number) => {
return (px / window.innerWidth) * 100;
@@ -26,7 +24,6 @@ export const ResizableLeftPanel = ({
minPanelSizePx = 300,
maxPanelSizePx = 450,
}: ResizableLeftPanelProps) => {
const { colorsTokens } = useCunninghamTheme();
const ref = useRef<ImperativePanelHandle>(null);
const savedWidthPxRef = useRef<number>(minPanelSizePx);
@@ -76,7 +73,7 @@ export const ResizableLeftPanel = ({
style={{
borderRightWidth: '1px',
borderRightStyle: 'solid',
borderRightColor: colorsTokens['greyscale-200'],
borderRightColor: 'var(--c--contextuals--border--surface--primary)',
width: '1px',
cursor: 'col-resize',
}}

View File

@@ -29,9 +29,9 @@ export const DocEditorSkeleton = () => {
$css={css`
background: linear-gradient(
90deg,
${colorsTokens['greyscale-100']} 0%,
${colorsTokens['greyscale-200']} 50%,
${colorsTokens['greyscale-100']} 100%
${colorsTokens['black-050']} 0%,
${colorsTokens['black-100']} 50%,
${colorsTokens['black-050']} 100%
);
background-size: 1000px 100%;
animation: ${shimmer} 2s infinite linear;
@@ -51,9 +51,9 @@ export const DocEditorSkeleton = () => {
$css={css`
background: linear-gradient(
90deg,
${colorsTokens['greyscale-100']} 0%,
${colorsTokens['greyscale-200']} 50%,
${colorsTokens['greyscale-100']} 100%
${colorsTokens['black-050']} 0%,
${colorsTokens['black-100']} 50%,
${colorsTokens['black-050']} 100%
);
background-size: 1000px 100%;
animation: ${shimmer} 2s infinite linear;
@@ -100,7 +100,7 @@ export const DocEditorSkeleton = () => {
>
{/* Title and metadata skeleton */}
<Box $gap="0.25rem" $css="flex:1;">
{/* Title - "Document sans titre" style */}
{/* Title - "Untitled Document" style */}
<SkeletonLine $width="35%" $height="40px" />
{/* Metadata (role and last update) */}
@@ -111,7 +111,7 @@ export const DocEditorSkeleton = () => {
{/* Toolbox skeleton (buttons) */}
<Box $direction="row" $gap="0.75rem" $align="center">
{/* Partager button */}
{/* Share button */}
<SkeletonLine $width="90px" $height="40px" />
{/* Download icon */}
<SkeletonCircle $width="40px" $height="40px" />

View File

@@ -54,7 +54,7 @@ export const Skeleton = ({ children }: PropsWithChildren) => {
$align="center"
$width="100%"
$height="100%"
$background={colorsTokens['greyscale-000']}
$background={colorsTokens['gray-000']}
$css={css`
position: absolute;
inset: 0;

Some files were not shown because too many files have changed in this diff Show More