update a lot of change since a while

This commit is contained in:
2026-01-22 10:29:36 +01:00
parent a4dcb95d83
commit e1c1475f10
78 changed files with 4200 additions and 534 deletions

View File

@@ -0,0 +1,39 @@
<template>
<article class="ds-card">
<div v-if="$slots.media" class="ds-card__media">
<slot name="media" />
</div>
<div class="ds-card__content">
<header v-if="$slots.header" class="ds-card__header">
<slot name="header" />
</header>
<div class="ds-card__body">
<slot />
</div>
<footer v-if="$slots.footer" class="ds-card__footer">
<slot name="footer" />
</footer>
</div>
</article>
</template>
<script setup>
</script>
<style lang="scss">
.ds-card {
display: grid;
grid-template-columns: 1fr;
border-radius: var(--r-lg);
background: var(--c-surface);
overflow: hidden;
transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
&__media { aspect-ratio: 16/9; background: var(--c-surface-muted); }
&__content { display: grid; gap: var(--sp-3); }
&__header { display: grid; gap: var(--sp-2); }
&__footer { display: flex; gap: var(--sp-2); align-items: center; }
}
</style>

View File

@@ -0,0 +1,225 @@
<template>
<component
:is="componentTag"
v-bind="$attrs"
:to="isNuxtLink ? to : undefined"
:href="isAnchor ? href : undefined"
:type="isButton ? type : undefined"
:disabled="isButton ? disabled || loading : undefined"
:aria-disabled="(!isButton && (disabled || loading)) ? 'true' : undefined"
:class="[
'ds-button',
`ds-button--${variant}`,
`ds-button--${size}`,
props.textColor ? `ds-button--text-${props.textColor}` : '',
props.borderColor ? `ds-button--border-${props.borderColor}` : '',
{ 'ds-button--disabled': disabled, 'ds-button--loading': loading }
]"
@click="onClick"
>
<span class="ds-button__content">
<span v-if="$slots.iconLeft" class="ds-button__icon ds-button__icon--left">
<slot name="iconLeft" />
</span>
<span class="ds-button__label">
<slot />
</span>
<span v-if="$slots.iconRight" class="ds-button__icon ds-button__icon--right">
<slot name="iconRight" />
</span>
</span>
<span v-if="loading" class="ds-button__spinner" aria-hidden="true" />
</component>
</template>
<script setup>
defineOptions({ inheritAttrs: false }) // désactive la transmission automatique des attributs HTML, utile pour v-bind="$attrs"
import { computed, resolveComponent } from 'vue'
const props = defineProps({
variant: { type: String, default: 'primary' }, // primary/secondary/ghost/link
size: { type: String, default: 'md' }, // sm/md/lg
to: { type: [String, Object], default: '' }, // NuxtLink
href: { type: String, default: '' }, // <a>
type: { type: String, default: 'button' }, // button/submit/reset (pour éviter des soumissions involontaires on met button pas défaut, si pas submit non désiré)
disabled: { type: Boolean, default: false },
loading: { type: Boolean, default: false },
textColor: { type: String, default: '' }, // accepts CSS color or tone name (ex: invert)
borderColor: { type: String, default: '' }, // accepts CSS color or tone name (ex: invert)
})
// TYPE D'ÉLÉMENT : NUXTLINK, A ou BUTTON ?
// quelle est la prop fournie ?
const isNuxtLink = computed(() => !!props.to) // NuxtLink si prop "to" présente
const isAnchor = computed(() => !props.to && !!props.href) // <a> si prop "href" présente et pas "to"
const isButton = computed(() => !props.to && !props.href) // <button> si pas "href" et pas "to"
// décision de l'élément en fonction de la prop fournie
const componentTag = computed(() => {
if (isNuxtLink.value) resolveComponent('NuxtLink')
if (isAnchor.value) return 'a'
return 'button'
})
const emit = defineEmits(['click']) // déclare que ce composant peut émettre un événement click.
// onClick(e) est appelé quand on clique sur le bouton, sauf en cas de disabled ou loading
function onClick(e) {
if (props.disabled || props.loading) {
e.preventDefault()
e.stopPropagation()
return
}
emit('click', e)
}
</script>
<style lang="scss">
.ds-button {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--sp-2);
border-radius: var(--r-md);
border: 2px solid transparent;
font-family: var(--font-roboto);
font-weight: var(--fw-medium);
line-height: 1;
text-decoration: none;
cursor: pointer;
user-select: none;
white-space: nowrap;
transition:
transform 120ms ease,
background-color 120ms ease,
border-color 120ms ease,
box-shadow 120ms ease,
color 120ms ease;
&:hover {
transform: translateY(-2px);
}
&:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--c-focus);
}
&--disabled,
&--loading {
opacity: 0.55;
cursor: not-allowed;
}
/* Sizes */
&--sm {
font-size: var(--text-sm);
padding: var(--sp-4) var(--sp-8);
min-height: 2.25rem;
}
&--md {
font-size: var(--text-md);
padding: var(--sp-6) var(--sp-12);
min-height: 2.75rem;
}
&--lg {
font-size: var(--text-lg);
padding: var(--sp-8) var(--sp-16);
min-height: 3.25rem;
}
/* Variants */
&--primary {
background: var(--c-brand);
color: var(--ds-button-text, var(--c-brand-contrast));
border-color: var(--ds-button-border, transparent);
}
&--secondary {
background: var(--c-surface);
color: var(--ds-button-text, var(--c-text));
border-color: var(--ds-button-border, var(--c-border-strong));
box-shadow: var(--sh-soft);
}
&--secondary:hover {
background: var(--c-hover);
}
&--ghost {
background: transparent;
color: var(--ds-button-text, var(--c-text));
border-color: var(--ds-button-border, transparent);
}
&--ghost:hover {
background: var(--c-hover);
}
&--link {
background: transparent;
color: var(--ds-button-text, var(--c-brand));
padding: 0;
min-height: auto;
border-color: var(--ds-button-border, transparent);
}
&--link:hover {
text-decoration: underline;
}
&--text-default { --ds-button-text: var(--c-text); }
&--text-muted { --ds-button-text: var(--c-text-muted); }
&--text-invert { --ds-button-text: var(--c-text-invert); }
&--text-brand_rouge { --ds-button-text: var(--c-brand_rouge); }
&--text-brand_rouge-weak { --ds-button-text: var(--c-brand_rouge-weak); }
&--text-success { --ds-button-text: var(--c-success); }
&--text-warning { --ds-button-text: var(--c-warning); }
&--text-danger { --ds-button-text: var(--c-danger); }
&--text-bleu_fonce { --ds-button-text: var(--c-bleu_fonce); }
&--text-bleu_clair { --ds-button-text: var(--c-bleu_clair); }
&--text-info { --ds-button-text: var(--c-info); }
&--border-default { --ds-button-border: var(--c-text); }
&--border-muted { --ds-button-border: var(--c-text-muted); }
&--border-invert { --ds-button-border: var(--c-text-invert); }
&--border-brand_rouge { --ds-button-border: var(--c-brand_rouge); }
&--border-brand_rouge-weak { --ds-button-border: var(--c-brand_rouge-weak); }
&--border-success { --ds-button-border: var(--c-success); }
&--border-warning { --ds-button-border: var(--c-warning); }
&--border-danger { --ds-button-border: var(--c-danger); }
&--border-bleu_fonce { --ds-button-border: var(--c-bleu_fonce); }
&--border-bleu_clair { --ds-button-border: var(--c-bleu_clair); }
&--border-info { --ds-button-border: var(--c-info); }
&--border { --ds-button-border: var(--c-border); }
&--border-strong { --ds-button-border: var(--c-border-strong); }
}
.ds-button__content {
display: inline-flex;
align-items: center;
gap: var(--sp-2);
}
.ds-button__icon {
display: inline-flex;
align-items: center;
justify-content: center;
}
.ds-button__spinner {
position: absolute;
width: 1rem;
height: 1rem;
border-radius: 999px;
border: 2px solid rgba(255,255,255,0.45);
border-top-color: rgba(255,255,255,0.95);
animation: ds-spin 700ms linear infinite;
}
@keyframes ds-spin {
to { transform: rotate(360deg); }
}
</style>

View File

@@ -0,0 +1,161 @@
<template>
<component
:is="componentTag"
v-bind="$attrs"
:to="isNuxtLink ? to : undefined"
:href="isAnchor ? href : undefined"
:type="isButton ? type : undefined"
:disabled="isButton ? disabled || loading : undefined"
:aria-disabled="(!isButton && (disabled || loading)) ? 'true' : undefined"
:class="[
'ds-button-arrow',
`ds-button-arrow--${size}`,
`ds-button-arrow--${variant}`,
{ 'ds-button--disabled': disabled, 'ds-button--loading': loading }
]"
@click="onClick"
>
<span class="ds-button-arrow__content">
<img
class="ds-button-arrow__icon"
src="/img/icones/arrow_right.svg"
alt=""
aria-hidden="true"
/>
<span class="ds-button-arrow__label">
<slot />
</span>
</span>
</component>
</template>
<script setup>
defineOptions({ inheritAttrs: false })
import { computed, resolveComponent } from 'vue'
const props = defineProps({
variant: { type: String, default: 'primary' }, // primary / secondary / ghost / link
size: { type: String, default: 'md' }, // sm/md/lg
to: { type: [String, Object], default: '' }, // NuxtLink
href: { type: String, default: '' }, // <a>
type: { type: String, default: 'button' }, // button/submit/reset
disabled: { type: Boolean, default: false },
loading: { type: Boolean, default: false },
})
const isNuxtLink = computed(() => !!props.to)
const isAnchor = computed(() => !props.to && !!props.href)
const isButton = computed(() => !props.to && !props.href)
const componentTag = computed(() => {
if (isNuxtLink.value) return resolveComponent('NuxtLink')
if (isAnchor.value) return 'a'
return 'button'
})
const emit = defineEmits(['click'])
function onClick(e) {
if (props.disabled || props.loading) {
e.preventDefault()
e.stopPropagation()
return
}
emit('click', e)
}
</script>
<style lang="scss">
.ds-button-arrow {
display: inline-flex;
align-items: center;
justify-content: center;
font-family: var(--font-roboto);
font-weight: var(--fw-semibold);
line-height: 1;
text-decoration: none;
cursor: pointer;
user-select: none;
white-space: nowrap;
&:hover {
transform: translateY(-3px);
}
transition: transform 120ms ease, background-color 120ms ease, border-color 120ms ease;
&:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--c-focus);
}
&--disabled {
opacity: 0.55;
cursor: not-allowed;
}
&__content {
display: inline-flex;
align-items: center;
gap: var(--sp-2);
}
&__label {
font-size: var(--fs-17);
}
&__icon {
height: var(--fs-24);
padding-right: var(--sp-4);
}
/* Sizes */
&--sm { font-size: var(--text-sm); padding: var(--sp-2) var(--sp-3); min-height: 2.25rem; }
&--md { font-size: var(--text-md); padding: var(--sp-3) var(--sp-4); min-height: 2.75rem; }
&--lg { font-size: var(--text-lg); padding: var(--sp-4) var(--sp-5); min-height: 3.25rem; }
/* Variants */
&--primary {
background: var(--c-brand_rouge);
color: var(--c-brand-contrast);
}
&--primary:hover { transform: translateY(-1px); }
&--secondary {
background: var(--c-surface);
color: var(--c-text);
border-color: var(--c-border-strong);
}
&--secondary:hover { background: var(--c-hover); }
&--invert {
color: var(--c-text-invert);
border-color: var(--c-border-strong);
img {
filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(0deg) brightness(100%) contrast(100%);
}
}
&--secondary:hover { background: var(--c-hover); }
&--ghost {
background: transparent;
color: var(--c-text);
}
&--ghost:hover { background: var(--c-hover); }
&--link {
background: transparent;
color: var(--c-brand);
padding: 0;
min-height: auto;
}
&--link:hover { text-decoration: underline; }
}
</style>

View File

@@ -0,0 +1,143 @@
<template>
<component
:is="as"
:class="[
'ds-heading',
`ds-heading--${font}`,
`ds-heading--${resolvedsize}`,
`ds-heading--${resolvedWeight}`,
`ds-heading--${resolvedspacing}`, //margin-bottom
`ds-heading--${tone}`
]"
>
<slot />
</component>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
as: { type: String, default: 'h2' }, // h1/h2/h3/p/span...
font: { type: String, default: 'roboto' }, // barlow | brandon
tone: { type: String, default: 'default' }, // default/muted/invert
})
const resolvedWeight = computed(() => {
switch (props.as) {
case 'h1':
return 'extrabold'
case 'h2':
return 'bold'
case 'h3':
return 'semibold'
case 'h4':
return 'black'
case 'h5':
return 'medium'
case 'h6':
return 'extralight'
default:
return 'semibold'
}
})
const resolvedsize = computed(() => {
switch (props.as) {
case 'h1':
return '2xl'
case 'h2':
return 'xl'
case 'h3':
return 'lg'
case 'h4':
return 'lg2'
case 'h5':
return 'md2'
case 'h6':
return 'xs2'
default:
return 'semibold'
}
})
// Margin-bottom
const resolvedspacing = computed(() => {
switch (props.as) {
case 'h1':
return 'space-6'
case 'h2':
return 'space-6'
case 'h3':
return 'space-6'
case 'h4':
return 'space-6'
case 'h5':
return 'space-6'
case 'h6':
return 'space-6'
default:
return 'space-6'
}
})
</script>
<style lang="scss">
.ds-heading {
&--roboto { font-family: var(--font-roboto); }
&--barlow { font-family: var(--font-barlow); }
&--brandon { font-family: var(--font-brandon); }
line-height: var(--lh-tight);
letter-spacing: var(--ls-tight);
margin: 0;
font-optical-sizing: auto; /* laisser le navigateur gérer opsz */
font-variation-settings: "opsz" var(--opsz-title); /* optionnel pour le forcer */
&--xs { font-size: var(--title-xs); }
&--xs2 { font-size: var(--title-xs2); }
&--sm { font-size: var(--title-sm); }
&--md { font-size: var(--title-md); }
&--md2 { font-size: var(--title-md2); }
&--lg { font-size: var(--title-lg); }
&--lg2 { font-size: var(--title-lg2); }
&--xl { font-size: var(--title-xl); }
&--2xl { font-size: var(--title-2xl); }
&--extralight { font-weight: var(--fw-extralight); }
&--light { font-weight: var(--fw-light); }
&--regular { font-weight: var(--fw-regular); }
&--medium { font-weight: var(--fw-medium); }
&--semibold { font-weight: var(--fw-semibold); }
&--bold { font-weight: var(--fw-bold); }
&--extrabold { font-weight: var(--fw-extrabold); }
&--black { font-weight: var(--fw-black); }
&--space-48 { margin-bottom: var(--sp-48); }
&--space-40 { margin-bottom: var(--sp-40); }
&--space-32 { margin-bottom: var(--sp-32); }
&--space-24 { margin-bottom: var(--sp-24); }
&--space-20 { margin-bottom: var(--sp-20); }
&--space-16 { margin-bottom: var(--sp-16); }
&--space-6 { margin-bottom: var(--sp-6); }
//TONE
&--default { color: var(--c-text, #111); }
&--muted { color: var(--c-text-muted, #555); }
&--invert { color: var(--c-text-invert, #fff); }
&--brand_rouge { color: var(--c-brand_rouge); }
&--brand_rouge-weak { color: var(--c-brand_rouge-weak); }
&--success { color: var(--c-success); }
&--warning { color: var(--c-warning); }
&--danger { color: var(--c-danger); }
&--bleu_fonce { color: var(--c-bleu_fonce); }
&--bleu_clair { color: var(--c-bleu_clair); }
&--info { color: var(--c-info); }
}
</style>

View File

@@ -0,0 +1,37 @@
<template>
<div class="ds-media" :class="`ds-media--${ratio}`">
<img
class="ds-media__img"
:src="src"
:alt="alt"
loading="lazy"
decoding="async"
/>
</div>
</template>
<script setup>
defineProps({
src: { type: String, required: true },
alt: { type: String, default: '' },
ratio: { type: String, default: '' }, // 16-9 / 4-3 / square
})
</script>
<style lang="scss">
.ds-media {
width: 100%;
background: rgba(0,0,0,0.04);
overflow: hidden;
&--16-9 { aspect-ratio: 16 / 9; }
&--4-3 { aspect-ratio: 4 / 3; }
&--square { aspect-ratio: 1 / 1; }
.ds-media__img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
}
</style>

View File

@@ -0,0 +1,127 @@
<template>
<component
:is="as"
:class="[
'ds-text',
`ds-text--${props.font}`,
`ds-text--${props.size || resolvedsize}`,
`ds-text--${props.weight || resolvedWeight}`, //si la classe weight n'est pas donné dans la classe on prend la mapping par défaut
`ds-text--${props.spacing || resolvedspacing}`,
`ds-text--${props.tone}`,
props.clamp ? `ds-text--clamp_${props.clamp}` : '',
]"
>
<slot />
</component>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({
as: { type: String, default: 'p' }, // p/span/div
font: { type: String, default: 'roboto' }, // barlow | brandon
size: { type: String, default: '' }, // xs/sm/md/lg
spacing: { type: String, default: '' },
tone: { type: String, default: 'default' }, // default/muted/invert
weight: { type: String, default: 'regular' }, // regular/medium
clamp: { type: Number, default: undefined }, // nombre de lignes du contenu
})
const resolvedsize = computed(() => {
switch (props.as) {
case 'p':
return 'md'
default:
return 'md'
}
})
const resolvedWeight = computed(() => {
switch (props.as) {
case 'p':
return 'regular'
default:
return 'regular'
}
})
const resolvedspacing = computed(() => {
switch (props.as) {
case 'p':
return 'space-6'
case 'ul':
return 'space-6'
case 'ol':
return 'space-6'
case 'li':
return 'space-6'
case 'pre':
return 'space-6'
case 'blockquote':
return 'space-6'
default:
return 'space-6'
}
})
</script>
<style lang="scss">
.ds-text {
&--roboto { font-family: var(--font-roboto); }
&--barlow { font-family: var(--font-barlow); }
&--brandon { font-family: var(--font-brandon); }
font-optical-sizing: auto; /* laisser le navigateur gérer opsz */
font-variation-settings: "opsz" var(--opsz-title); /* optionnel pour le forcer */
line-height: var(--lh-base);
letter-spacing: var(--ls-normal);
margin: 0;
&--xs { font-size: var(--text-xs); }
&--sm { font-size: var(--text-sm); }
&--md { font-size: var(--text-md); }
&--lg { font-size: var(--text-lg); }
&--light { font-weight: var(--fw-light); }
&--regular { font-weight: var(--fw-regular); }
&--medium { font-weight: var(--fw-medium); }
&--semibold { font-weight: var(--fw-semibold); }
&--bold { font-weight: var(--fw-bold); }
&--extrabold { font-weight: var(--fw-extrabold); }
&--black { font-weight: var(--fw-black); }
&--space-48 { margin-bottom: var(--sp-48); }
&--space-40 { margin-bottom: var(--sp-40); }
&--space-32 { margin-bottom: var(--sp-32); }
&--space-24 { margin-bottom: var(--sp-24); }
&--space-20 { margin-bottom: var(--sp-20); }
&--space-16 { margin-bottom: var(--sp-16); }
&--space-6 { margin-bottom: var(--sp-6); }
&--default { color: var(--c-text, #111); }
&--muted { color: var(--c-text-muted, #555); }
&--invert { color: var(--c-text-invert, #fff); }
&--brand_rouge { color: var(--c-brand_rouge); }
&--brand_rouge-weak { color: var(--c-brand_rouge-weak); }
&--success { color: var(--c-success); }
&--warning { color: var(--c-warning); }
&--danger { color: var(--c-danger); }
&--bleu_fonce { color: var(--c-bleu_fonce); }
&--bleu_clair { color: var(--c-bleu_clair); }
// clampé sur 2 lignes pour les cartes (résumé, programme, etc.).
// Si ça dépasse, ça coupe proprement. Pour du texte de description qui doit tenir dans un cadre, mais qui a été écrit trop long, pour ne pas casser le design du site, on va limiter l'affichage à 2 lignes. c'est pour des espace réduit. Pour ne pas casser le design de la page. J'ai presque écrit 2 lignes, je vais bientôt être censurée.
&--clamp_3 {
display: -webkit-box;
line-clamp: 3;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
}
</style>

View File

@@ -0,0 +1,31 @@
:root {
/* Texte */
--c-text: #111;
--c-surface: #ffffff;
--c-text-muted: #555;
--c-text-invert: #fff;
/* Marque / accent (ex: rouge ONDIF) */
//--c-brand_rouge: #E30613;
--c-brand_rouge: #E20018;
--c-brand_rouge45: rgba(226, 0, 24, 0.45);
--c-brand_rouge-weak: #e3061391;
--c-backgroud-black: #111;
--c-backgroud-brandreverse: #ACCFCF;
/* États */
--c-success: green;
--c-warning: #E30613;
--c-danger: #E30613;
/* Liens / info (si tu veux) */
--c-info: #0056b3;
--c-bleu_fonce: #0056b3;
--c-bleu_clair: #007bff;
--c-border: rgba(0,0,0,0.10);
--c-border-strong: rgba(0,0,0,0.18);
--c-hover: rgba(0,0,0,0.04);
--c-focus: rgba(227, 6, 19, 0.25);
}

View File

@@ -0,0 +1,102 @@
@font-face {
font-family: "Roboto Flex";
src: url("@/assets/fonts/robotoflex.ttf") format("truetype");
font-weight: 100 1000;
font-stretch: 25% 151%;
font-style: oblique 0deg 10deg;
font-display: swap;
}
@font-face {
font-family: 'Brandon Text';
src: url('@/assets/fonts/brandontext_bold.woff2') format('woff2');
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Brandon Text';
src: url('@/assets/fonts/brandontext_boldItalic.woff2') format('woff2');
font-weight: 700;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Brandon Text';
src: url('@/assets/fonts/brandontext_mediumItalic.woff2') format('woff2');
font-weight: 500;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Brandon Text';
src: url('@/assets/fonts/brandontext_medium.woff2') format('woff2');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Brandon Text';
src: url('@/assets/fonts/brandontext_regularItalic.woff2') format('woff2');
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: 'Brandon Text';
src: url('@/assets/fonts/brandontext_regular.woff2') format('woff2');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Barlow';
src: url('@/assets/fonts/barlow_medium.ttf') format('truetype');
font-weight: 500;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Barlow';
src: url('@/assets/fonts/barlow_semibold.ttf') format('truetype');
font-weight: 600;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Barlow';
src: url('@/assets/fonts/barlow_regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Barlow';
src: url('@/assets/fonts/barlow_light.ttf') format('truetype');
font-weight: 300;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Barlow';
src: url('@/assets/fonts/barlow_extrabold.ttf') format('truetype');
font-weight: 800;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Barlow';
src: url('@/assets/fonts/barlow_bold.ttf') format('truetype');
font-weight: 700;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: 'Barlow';
src: url('@/assets/fonts/barlow_black.ttf') format('truetype');
font-weight: 900;
font-style: normal;
font-display: swap;
}

View File

@@ -0,0 +1,28 @@
:root {
/* Containers largeur de contenu */
/* padding latéral (respiration) */
--page-padding-mobile: 0.5rem; /* 16px */
--page-padding-tablet: 1.5rem; /* 24px */
--page-padding-desktop: 2rem; /* 32px */
--container-narrow: 48rem; /* 768px → éditorial, texte long */
--container-default: 72rem; /* 1152px → pages standard */
--container-wide: 90rem; /* 1440px → listings, agenda */
--gap-cards: var(--sp-22);
}
@media (min-width: 600px) {
:root {
--gap-cards: var(--sp-16);
}
}
@media (min-width: 1200px) {
:root {
--gap-cards: var(--sp-22);
}
}

View File

@@ -0,0 +1,4 @@
:root {
--r-md: 0.75rem;
--sh-soft: 0 2px 6px rgba(0,0,0,0.06), 0 0 20px rgba(0,0,0,0.08);
}

View File

@@ -0,0 +1,3 @@
:root {
--sh-md: 0 8px 20px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.08);
}

View File

@@ -0,0 +1,31 @@
:root {
/* Base unit */
--sp-0: 0;
/* Micro spacing (UI fine) */
--sp-4: 0.25rem; /* 4px */
--sp-6: 0.375rem; /* 6px */
--sp-8: 0.5rem; /* 8px */
--sp-12: 0.75rem; /* 12px */
/* Spacing standard */
--sp-16: 1rem; /* 16px */
--sp-20: 1.25rem; /* 20px */
--sp-22: 1.375rem; /* 22px */
--sp-24: 1.5rem; /* 24px */
/* Spacing fort (sections, titres) */
--sp-32: 2rem; /* 32px */
--sp-40: 2.5rem; /* 40px */
--sp-45: 45px; /* 45px */
--sp-48: 3rem; /* 48px */
/* Spacing très fort (pages, hero) */
--sp-64: 4rem; /* 64px */
--sp-80: 5rem; /* 80px */
--sp-96: 6rem; /* 96px */
--sp-120: 7.5rem; /* 120px */
--sp-180: 11.25rem; /* 120px */
--sp-200: 200px; /* 200px */
--sp-220: 13.75rem; /* 220px */
}

View File

@@ -0,0 +1,113 @@
:root {
/* Font stacks (remplace Inter si tu as une font ONDIF) */
--font-roboto: "Roboto Flex", system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
--font-brandon: 'Brandon Text',
system-ui,
-apple-system,
"Segoe UI",
Roboto,
Arial,
sans-serif;
--font-barlow: 'Barlow',
system-ui,
-apple-system,
"Segoe UI",
Roboto,
Arial,
sans-serif;
/* Font weights */
--fw-extralight: 200;
--fw-light: 300;
--fw-regular: 400;
--fw-medium: 500;
--fw-semibold: 600;
--fw-bold: 700;
--fw-extrabold: 800;
--fw-black: 900;
/* Optical size (opsz) : utile avec Roboto Flex */
--opsz-body: 14;
--opsz-title: 28;
/* Line heights */
--lh-tight: 1.15;
--lh-snug: 1.25;
--lh-base: 1.5;
/* Letter spacing (optionnel mais utile) */
--ls-tight: -0.01em;
--ls-normal: 0;
--ls-wide: 0.02em;
/* Scale (mobile-first) */
--fs-12: 0.75rem; /* 12 */
--fs-14: 0.875rem; /* 14 */
--fs-16: 1rem; /* 16 */
--fs-17: 1.0625rem; /* 17 */
--fs-18: 1.125rem; /* 18 */
--fs-20: 1.25rem; /* 20 */
--fs-23: 1.4375rem; /* 23 */
--fs-24: 1.5rem; /* 24 */
--fs-28: 1.75rem; /* 28 */
--fs-30: 1.875rem; /* 30 */
--fs-32: 2rem; /* 32 */
--fs-40: 2.5rem; /* 40 */
/* Semantic mapping (ça cest ton “API” DS) */
--text-xs: var(--fs-12);
--text-sm: var(--fs-14);
--text-md: var(--fs-16);
--text-lg: var(--fs-18);
--title-xs: var(--fs-16);
--title-xs2: var(--fs-17);
--title-sm: var(--fs-18);
--title-md: var(--fs-20);
--title-md2: var(--fs-23);
--title-lg: var(--fs-24);
--title-lg2: var(--fs-30);
--title-xl: var(--fs-32);
--title-2xl: var(--fs-40);
}
/* Option : ajustements desktop */
@media (max-width: 700px) {
:root {
--title-xs: var(--fs-12);
--title-xs2: var(--fs-14);
--title-sm: var(--fs-14);
--title-md: var(--fs-16);
--title-md2: var(--fs-17);
--title-lg: var(--fs-18);
--title-lg2: var(--fs-20);
--title-xl: var(--fs-20);
--title-2xl: var(--fs-24);
}
}
@media (min-width: 700px) {
:root {
--title-xs: var(--fs-14);
--title-xs2: var(--fs-16);
--title-sm: var(--fs-16);
--title-md: var(--fs-18);
--title-md2: var(--fs-20);
--title-lg: var(--fs-20);
--title-lg2: var(--fs-24);
--title-xl: var(--fs-24);
--title-2xl: var(--fs-32);
}
}
@media (min-width: 1024px) {
:root {
--title-xs: var(--fs-16);
--title-xs2: var(--fs-17);
--title-sm: var(--fs-18);
--title-md: var(--fs-20);
--title-md2: var(--fs-23);
--title-lg: var(--fs-24);
--title-lg2: var(--fs-30);
--title-xl: var(--fs-32);
--title-2xl: var(--fs-40);
}
}

View File

@@ -0,0 +1,8 @@
@use "./fonts";
@use "./typography";
@use "./colors";
@use "./spacing";
@use "./radius";
@use "./shadow";
@use "./layout";