feat(wip homepage with new design)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&display=swap');
|
||||
@import 'tailwindcss';
|
||||
@import './fonts.css';
|
||||
|
||||
@plugin 'tailwindcss-animate';
|
||||
|
||||
@@ -8,13 +8,17 @@
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@theme {
|
||||
--font-sans: 'Figtree', 'Inter', 'Instrument Sans', ui-sans-serif, system-ui, sans-serif,
|
||||
/* Fonts */
|
||||
--font-sans: 'Space Grotesk', 'Inter', 'Instrument Sans', ui-sans-serif, system-ui, sans-serif,
|
||||
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
|
||||
/* Radius Sizes */
|
||||
--radius-lg: var(--radius);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius: 0.5rem;
|
||||
|
||||
/* Colors */
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
|
||||
@@ -38,7 +42,7 @@
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
|
||||
--radius: 0.5rem;
|
||||
|
||||
}
|
||||
|
||||
:root {
|
||||
|
||||
44
resources/css/fonts.css
Normal file
44
resources/css/fonts.css
Normal file
@@ -0,0 +1,44 @@
|
||||
/* space-grotesk-300 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Space Grotesk';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: url('fonts/space-grotesk-v22-latin-300.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* space-grotesk-regular - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Space Grotesk';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('fonts/space-grotesk-v22-latin-regular.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* space-grotesk-500 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Space Grotesk';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
src: url('fonts/space-grotesk-v22-latin-500.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* space-grotesk-600 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Space Grotesk';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
src: url('fonts/space-grotesk-v22-latin-600.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
|
||||
/* space-grotesk-700 - latin */
|
||||
@font-face {
|
||||
font-display: swap; /* Check https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-display for other options. */
|
||||
font-family: 'Space Grotesk';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
src: url('fonts/space-grotesk-v22-latin-700.woff2') format('woff2'); /* Chrome 36+, Opera 23+, Firefox 39+, Safari 12+, iOS 10+ */
|
||||
}
|
||||
BIN
resources/css/fonts/space-grotesk-v22-latin-300.woff2
Normal file
BIN
resources/css/fonts/space-grotesk-v22-latin-300.woff2
Normal file
Binary file not shown.
BIN
resources/css/fonts/space-grotesk-v22-latin-500.woff2
Normal file
BIN
resources/css/fonts/space-grotesk-v22-latin-500.woff2
Normal file
Binary file not shown.
BIN
resources/css/fonts/space-grotesk-v22-latin-600.woff2
Normal file
BIN
resources/css/fonts/space-grotesk-v22-latin-600.woff2
Normal file
Binary file not shown.
BIN
resources/css/fonts/space-grotesk-v22-latin-700.woff2
Normal file
BIN
resources/css/fonts/space-grotesk-v22-latin-700.woff2
Normal file
Binary file not shown.
BIN
resources/css/fonts/space-grotesk-v22-latin-regular.woff2
Normal file
BIN
resources/css/fonts/space-grotesk-v22-latin-regular.woff2
Normal file
Binary file not shown.
@@ -2,13 +2,6 @@ import { SVGAttributes } from 'react';
|
||||
|
||||
export default function AppLogoIcon(props: SVGAttributes<SVGElement>) {
|
||||
return (
|
||||
/* <svg {...props} viewBox="0 0 40 42" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
d="M17.2 5.63325L8.6 0.855469L0 5.63325V32.1434L16.2 41.1434L32.4 32.1434V23.699L40 19.4767V9.85547L31.4 5.07769L22.8 9.85547V18.2999L17.2 21.411V5.63325ZM38 18.2999L32.4 21.411V15.2545L38 12.1434V18.2999ZM36.9409 10.4439L31.4 13.5221L25.8591 10.4439L31.4 7.36561L36.9409 10.4439ZM24.8 18.2999V12.1434L30.4 15.2545V21.411L24.8 18.2999ZM23.8 20.0323L29.3409 23.1105L16.2 30.411L10.6591 27.3328L23.8 20.0323ZM7.6 27.9212L15.2 32.1434V38.2999L2 30.9666V7.92116L7.6 11.0323V27.9212ZM8.6 9.29991L3.05913 6.22165L8.6 3.14339L14.1409 6.22165L8.6 9.29991ZM30.4 24.8101L17.2 32.1434V38.2999L30.4 30.9666V24.8101ZM9.6 11.0323L15.2 7.92117V22.5221L9.6 25.6333V11.0323Z"
|
||||
/>
|
||||
</svg>*/
|
||||
<svg {...props} viewBox="0 0 42 33" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="21.138" cy="16.5" r="15" stroke="#000" strokeWidth="3"/>
|
||||
<path d="M21.138 15c-4.4-5.2-11-2.167-13.5 0 1.6-10.4 9.333-12 13-12 10.4.4 13.667 8.167 14 12-6.4-5.6-11.5-2.333-13.5 0Z" fill="#000" stroke="#000"/>
|
||||
@@ -17,6 +10,5 @@ export default function AppLogoIcon(props: SVGAttributes<SVGElement>) {
|
||||
<path d="M5.638 11.5c-3.5 5.167-8.4 14.2 0 9v-9ZM36.638 11.5c3.5 5.167 8.4 14.2 0 9v-9Z" fill="#000" stroke="#000"/>
|
||||
<path d="M21.736 18.768a1.28 1.28 0 0 1-1.472 0l-2.879-2.117c-.778-.572-.298-1.651.736-1.651h5.758c1.034 0 1.514 1.079.736 1.651l-2.88 2.117Z" fill="#FAAE2B"/>
|
||||
</svg>
|
||||
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
8
resources/js/components/common/Container.tsx
Normal file
8
resources/js/components/common/Container.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import { cn } from '@/lib/utils';
|
||||
import React from "react";
|
||||
|
||||
export function Container({ className, ...props }: React.ComponentProps<'div'>) {
|
||||
return (
|
||||
<div className={cn('w-full max-w-7xl mx-auto px-4', className)} {...props} />
|
||||
);
|
||||
}
|
||||
33
resources/js/components/common/ScrollToTop.tsx
Normal file
33
resources/js/components/common/ScrollToTop.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { ChevronUp } from 'lucide-react';
|
||||
|
||||
export function ScrollToTop() {
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const hero = document.getElementById('hero');
|
||||
if (!hero) return;
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => setIsVisible(!entry.isIntersecting),
|
||||
{ threshold: 0 },
|
||||
);
|
||||
|
||||
observer.observe(hero);
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
const scrollToTop = () => window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={scrollToTop}
|
||||
aria-label="Retour en haut"
|
||||
className="fixed bottom-6 right-6 z-50 p-3 rounded-full border-3 border-black bg-primary shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-x-1 hover:translate-y-1 transition duration-200"
|
||||
>
|
||||
<ChevronUp className="size-5" />
|
||||
</button>
|
||||
);
|
||||
}
|
||||
27
resources/js/components/common/SectionHeading.tsx
Normal file
27
resources/js/components/common/SectionHeading.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import {cn} from '@/lib/utils';
|
||||
|
||||
interface SectionHeadingProps {
|
||||
title: string;
|
||||
color?: string;
|
||||
subtitle?: string;
|
||||
align?: 'left' | 'center';
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function SectionHeading({title, color, subtitle, align = 'center', className}: SectionHeadingProps) {
|
||||
return (
|
||||
<div className={cn(
|
||||
'flex gap-10 items-center ',
|
||||
align === 'center' && 'text-center',
|
||||
align === 'left' && 'text-left',
|
||||
className,
|
||||
)}>
|
||||
<h2 className={`text-3xl text-black font-medium bg-${color} rounded p-1`}>
|
||||
{title}
|
||||
</h2>
|
||||
{subtitle && (
|
||||
<p className="text-md text-muted-foreground max-w-2xl">{subtitle}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
0
resources/js/components/common/ServiceCard.tsx
Normal file
0
resources/js/components/common/ServiceCard.tsx
Normal file
41
resources/js/components/features/home/AboutSection.tsx
Normal file
41
resources/js/components/features/home/AboutSection.tsx
Normal file
@@ -0,0 +1,41 @@
|
||||
import {SectionHeading} from "@/components/common/SectionHeading";
|
||||
|
||||
export function AboutSection() {
|
||||
return (
|
||||
<section className="w-full py-16">
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
<SectionHeading title="Qui sommes-nous ?" color="secondary" subtitle="Le Retzien Libre, c’est une association qui promeut l’auto-hébergement et la décentralisation des services en ligne depuis 2017." align='left' />
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mt-5">
|
||||
<div className="flex flex-col gap-3">
|
||||
<h3 className="text-xl font-semibold">Une association locale</h3>
|
||||
<p>
|
||||
Le Retzien Libre est une association engagée pour la promotion du logiciel libre
|
||||
et la protection de vos données personnelles sur le territoire du Pays de Retz.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">
|
||||
<h3 className="text-xl font-semibold">Notre mission</h3>
|
||||
<p>
|
||||
Nous sensibilisons et accompagnons les citoyens vers des pratiques numériques
|
||||
plus respectueuses, libres et indépendantes des grandes plateformes commerciales.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">
|
||||
<h3 className="text-xl font-semibold">Surveillance massive</h3>
|
||||
<p>
|
||||
Les GAFAM collectent et exploitent vos données personnelles à des fins commerciales,
|
||||
sans transparence sur l'usage qui en est fait.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-3">
|
||||
<h3 className="text-xl font-semibold">Monopole numérique</h3>
|
||||
<p>
|
||||
Concentration excessive du pouvoir et dépendance aux services centralisés.
|
||||
Il existe des alternatives libres, locales et respectueuses.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
43
resources/js/components/features/home/AlternativeSection.tsx
Normal file
43
resources/js/components/features/home/AlternativeSection.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Link, usePage } from '@inertiajs/react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { dashboard, register } from '@/routes';
|
||||
import { type SharedData } from '@/types';
|
||||
import illustrationImage from '@/img/utils/lrl-illustration.png';
|
||||
|
||||
export function AlternativeSection() {
|
||||
const { auth } = usePage<SharedData>().props;
|
||||
|
||||
return (
|
||||
<section className="w-full py-16">
|
||||
<div className="max-w-7xl mx-auto px-4">
|
||||
<div className="flex flex-col lg:flex-row items-center gap-12">
|
||||
<div className="flex flex-col gap-6 lg:w-1/2">
|
||||
<h2 className="text-3xl font-bold">
|
||||
Notre alternative : Le Retzien Libre
|
||||
</h2>
|
||||
<p>
|
||||
Une association locale engagée pour la promotion du logiciel libre
|
||||
et la protection de vos données personnelles.
|
||||
</p>
|
||||
{auth.user ? (
|
||||
<Link href={dashboard()}>
|
||||
<Button variant="default">Accéder à mon espace</Button>
|
||||
</Link>
|
||||
) : (
|
||||
<Link href={register()}>
|
||||
<Button variant="default">Rejoignez-nous</Button>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<div className="lg:w-1/2 flex justify-center">
|
||||
<img
|
||||
src={illustrationImage}
|
||||
alt="Le Retzien Libre"
|
||||
className="rounded-lg max-w-md w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
58
resources/js/components/features/home/HeroSection.tsx
Normal file
58
resources/js/components/features/home/HeroSection.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { Link, usePage } from '@inertiajs/react';
|
||||
import { ChevronDown } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { dashboard, membership } from '@/routes';
|
||||
import { type SharedData } from '@/types';
|
||||
import illustrationImage from '@/img/utils/lrl-illustration.png';
|
||||
|
||||
export function HeroSection() {
|
||||
const { auth } = usePage<SharedData>().props;
|
||||
|
||||
const scrollToFirstSection = () => {
|
||||
document.getElementById('first-section')?.scrollIntoView({ behavior: 'smooth' });
|
||||
};
|
||||
|
||||
return (
|
||||
<section
|
||||
id="hero"
|
||||
className="flex flex-col w-full max-w-[335px] lg:max-w-7xl mx-auto min-h-[calc(100vh-80px)] px-4"
|
||||
>
|
||||
{/* Contenu principal */}
|
||||
<div className="flex flex-1 items-center justify-center gap-4 w-full">
|
||||
<div className="flex flex-col w-full items-center text-center lg:items-start lg:text-left justify-center gap-4">
|
||||
<h1 className="text-5xl text-accent max-w-[450px] mb-5">
|
||||
Pour un internet éthique !
|
||||
</h1>
|
||||
<p className="text-xl mb-5">
|
||||
"Dégooglisons"<br />
|
||||
nos ordinateurs, nos tablettes et nos smartphones.<br />
|
||||
<i>"Le chemin est long, mais la voie est libre"</i>
|
||||
</p>
|
||||
{auth.user ? (
|
||||
<Link href={dashboard()}>
|
||||
<Button variant="secondary">Mon espace</Button>
|
||||
</Link>
|
||||
) : (
|
||||
<Link href={membership()}>
|
||||
<Button variant="secondary">Adhérer dès maintenant</Button>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
<div className="hidden lg:flex w-full items-center justify-center">
|
||||
<img src={illustrationImage} alt="Illustration Le Retzien Libre" className="max-w-md w-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Flèche vers la première section */}
|
||||
<div className="flex justify-center pb-8">
|
||||
<button
|
||||
onClick={scrollToFirstSection}
|
||||
aria-label="Voir nos services"
|
||||
className="p-2 rounded-full border-3 border-black animate-bounce hover:animate-none transition"
|
||||
>
|
||||
<ChevronDown className="size-6" />
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
25
resources/js/components/features/home/ServiceCard.tsx
Normal file
25
resources/js/components/features/home/ServiceCard.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import {Service} from "@/types";
|
||||
|
||||
export function ServiceCard({title, colorTitle, bgColor, bgTitle, description, link, illustration}: Service) {
|
||||
return (
|
||||
<div
|
||||
className={`flex gap-1 items-center bg-${bgColor} justify-center gap-4 rounded-3xl p-10 border-3 border-black shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out`}>
|
||||
<div>
|
||||
<div className="max-w-[150px]">
|
||||
<h3 className={`inline text-2xl font-semibold text-${colorTitle} font-medium bg-${bgTitle} rounded p-1 line-clamp-2`}>{title}</h3>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mt-5">{description}</p>
|
||||
<a href={link} className="text-white underline hover:font-medium mt-4 inline-block hover:underline">
|
||||
En savoir plus
|
||||
</a>
|
||||
</div>
|
||||
<div className="relative w-full h-64">
|
||||
<img
|
||||
src={illustration}
|
||||
alt={title}
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
82
resources/js/components/features/home/ServicesSection.tsx
Normal file
82
resources/js/components/features/home/ServicesSection.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { type Service } from '@/types';
|
||||
import { ServiceCard } from './ServiceCard';
|
||||
import { SectionHeading } from '@/components/common/SectionHeading';
|
||||
import { Container } from '@/components/common/Container';
|
||||
|
||||
const services: Service[] = [
|
||||
{
|
||||
title: 'Boîte mail',
|
||||
description: 'Service de messagerie électronique sécurisé et respectueux de votre vie privée',
|
||||
colorTitle: 'white',
|
||||
bgTitle: 'accent',
|
||||
bgColor: 'secondary',
|
||||
link: '#',
|
||||
illustration: '../../img/utils/lrl-logo.svg'
|
||||
},
|
||||
{
|
||||
title: 'Stockage Cloud',
|
||||
description: 'Stockage en ligne et collaboration avec vos données hébergées localement',
|
||||
colorTitle: 'black',
|
||||
bgTitle: 'white',
|
||||
bgColor: 'primary',
|
||||
link: '#',
|
||||
illustration: '../../img/utils/lrl-logo.svg'
|
||||
},
|
||||
{
|
||||
title: 'Hébergement de site',
|
||||
description: "Solutions d'hébergement web éthiques et performantes",
|
||||
colorTitle: 'black',
|
||||
bgTitle: 'primary',
|
||||
bgColor: 'accent',
|
||||
link: '#',
|
||||
illustration: '../../img/utils/lrl-logo.svg'
|
||||
},
|
||||
{
|
||||
title: 'Email Marketing',
|
||||
description: "Gérez vos communications de groupe efficacement",
|
||||
colorTitle: 'black',
|
||||
bgTitle: 'secondary',
|
||||
bgColor: 'gray',
|
||||
link: '#',
|
||||
illustration: '../../img/utils/lrl-logo.svg'
|
||||
},
|
||||
{
|
||||
title: 'Partage de fichiers',
|
||||
description: 'Partager facielement vos fichiers en toute sécurité',
|
||||
colorTitle: 'black',
|
||||
bgTitle: 'white',
|
||||
bgColor: 'primary',
|
||||
link: '#',
|
||||
illustration: '../../img/utils/lrl-logo.svg'
|
||||
},
|
||||
{
|
||||
title: 'Outil de Sondage',
|
||||
description: 'Créez et partagez des sondages en ligne en toute confidentialité',
|
||||
colorTitle: 'black',
|
||||
bgTitle: 'primary',
|
||||
bgColor: 'accent',
|
||||
link: '#',
|
||||
illustration: '../../img/utils/lrl-logo.svg'
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
export function ServicesSection() {
|
||||
return (
|
||||
<section id="first-section" className="w-full bg-white py-16">
|
||||
<Container className="flex flex-col gap-10">
|
||||
<SectionHeading
|
||||
title="Nos services"
|
||||
color="primary"
|
||||
subtitle="Nous vous proposons, à travers des outils libres, ouverts et solidaires, de quitter l’industrie du G.A.F.A.M. N’acceptons plus d’être leur produit !"
|
||||
align="left"
|
||||
/>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{services.map((service) => (
|
||||
<ServiceCard key={service.title} {...service} />
|
||||
))}
|
||||
</div>
|
||||
</Container>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
34
resources/js/components/footer.tsx
Normal file
34
resources/js/components/footer.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Link } from '@inertiajs/react';
|
||||
import { contact, home, membership } from '@/routes';
|
||||
import AppLogoIcon from '@/components/app-logo-icon';
|
||||
|
||||
export function Footer() {
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
return (
|
||||
<footer className="w-full border-t-4 border-black py-10 mt-auto">
|
||||
<div className="max-w-7xl mx-auto px-4 flex flex-col gap-8">
|
||||
<div className="flex flex-col lg:flex-row justify-between gap-8">
|
||||
<div className="flex flex-col gap-3">
|
||||
<Link href={home()} className="flex items-center gap-2 no-underline">
|
||||
<AppLogoIcon className="size-8 text-[var(--foreground)] dark:text-white" />
|
||||
<span className="font-bold text-lg">Le Retzien Libre</span>
|
||||
</Link>
|
||||
<p className="text-sm max-w-xs">
|
||||
Une association locale pour un internet éthique, libre et respectueux.
|
||||
</p>
|
||||
</div>
|
||||
<nav className="flex flex-col gap-3">
|
||||
<span className="font-semibold">Navigation</span>
|
||||
<Link href={home()} className="text-sm no-underline hover:underline">Accueil</Link>
|
||||
<Link href={contact()} className="text-sm no-underline hover:underline">Contact</Link>
|
||||
<Link href={membership()} className="text-sm no-underline hover:underline">Adhérer</Link>
|
||||
</nav>
|
||||
</div>
|
||||
<div className="border-t border-black/20 pt-6 text-sm text-center">
|
||||
© {currentYear} Le Retzien Libre. Tous droits réservés.
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
@@ -18,7 +18,6 @@ const buttonVariants = cva(
|
||||
secondary:
|
||||
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
||||
ghost: "bg-accent hover:text-accent-foreground hover:text-accent-foreground",
|
||||
link: "text-primary underline-offset-4 hover:underline",
|
||||
},
|
||||
size: {
|
||||
default: "h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out",
|
||||
|
||||
11
resources/js/img/utils/lrl-logo.svg
Normal file
11
resources/js/img/utils/lrl-logo.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 9.5 KiB |
0
resources/js/layouts/app/app-footer-layout.tsx
Normal file
0
resources/js/layouts/app/app-footer-layout.tsx
Normal file
@@ -1,86 +1,91 @@
|
||||
import {Link, router, usePage} from "@inertiajs/react";
|
||||
import {dashboard, home, login, logout, register, contact, membership} from "@/routes";
|
||||
import AppLogoIcon from "@/components/app-logo-icon";
|
||||
import {Button} from "@/components/ui/button";
|
||||
import type {SharedData} from "@/types";
|
||||
import {useMobileNavigation} from "@/hooks/use-mobile-navigation";
|
||||
import {LogOut} from "lucide-react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Link, router, usePage } from '@inertiajs/react';
|
||||
import { dashboard, home, login, logout, contact, membership } from '@/routes';
|
||||
import AppLogoIcon from '@/components/app-logo-icon';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { type SharedData } from '@/types';
|
||||
import { useMobileNavigation } from '@/hooks/use-mobile-navigation';
|
||||
import { useAppearance } from '@/hooks/use-appearance';
|
||||
import { Menu, Moon, Sun, X } from 'lucide-react';
|
||||
import AppLogo from "@/components/app-logo";
|
||||
|
||||
export default function NavGuestLayout() {
|
||||
const {auth} = usePage<SharedData>().props;
|
||||
|
||||
const { auth } = usePage<SharedData>().props;
|
||||
const cleanup = useMobileNavigation();
|
||||
const { appearance, updateAppearance } = useAppearance();
|
||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||
|
||||
const handleLogout = () => {
|
||||
cleanup();
|
||||
router.flushAll();
|
||||
};
|
||||
|
||||
const [dark, setDark] = useState(false);
|
||||
const toggleAppearance = () => {
|
||||
updateAppearance(appearance === 'dark' ? 'light' : 'dark');
|
||||
};
|
||||
|
||||
const closeMenu = () => setIsMenuOpen(false);
|
||||
|
||||
// Fermer sur navigation Inertia
|
||||
useEffect(() => {
|
||||
if (dark) {
|
||||
document.documentElement.classList.add("dark");
|
||||
} else {
|
||||
document.documentElement.classList.remove("dark");
|
||||
}
|
||||
}, [dark]);
|
||||
return router.on('navigate', closeMenu);
|
||||
}, []);
|
||||
|
||||
// Fermer sur touche Escape
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') closeMenu();
|
||||
};
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
return () => document.removeEventListener('keydown', handleKeyDown);
|
||||
}, []);
|
||||
|
||||
// Bloquer le scroll quand menu ouvert
|
||||
useEffect(() => {
|
||||
document.body.style.overflow = isMenuOpen ? 'hidden' : '';
|
||||
return () => { document.body.style.overflow = ''; };
|
||||
}, [isMenuOpen]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<header
|
||||
className="flex justify-between my-6 w-full max-w-[335px] text-sm not-has-[nav]:hidden lg:max-w-7xl">
|
||||
<div className="flex items-center justify-start">
|
||||
<Link
|
||||
href={home()}
|
||||
className="flex items-center justify-start gap-2 font-medium no-underline"
|
||||
>
|
||||
<div className="mb-1 flex h-9 w-9 items-center justify-center rounded-md">
|
||||
<AppLogoIcon className="size-9 text-[var(--foreground)] dark:text-white"/>
|
||||
</div>
|
||||
<h1 className="text-black">Le Retzien Libre</h1>
|
||||
</Link>
|
||||
</div>
|
||||
<nav className="flex items-center justify-end gap-4">
|
||||
<Link
|
||||
href={home()}
|
||||
className="inline-block px-5 py-1.5 text-lg leading-normal text-[#1b1b18] hover:border-[#1915014a] dark:border-[#3E3E3A] dark:text-[#EDEDEC] dark:hover:border-[#62605b] no-underline"
|
||||
>
|
||||
<header className="flex justify-between items-center my-6 w-full max-w-[335px] lg:max-w-7xl text-sm">
|
||||
{/* Logo */}
|
||||
<Link href={home()} className="flex items-center gap-2 font-medium no-underline">
|
||||
<div className="flex items-center justify-center rounded-md">
|
||||
<AppLogo className="max-w-[200px] max-h-[42px] w-full h-auto" />
|
||||
</div>
|
||||
{/*@todo: gérer l'accessibilité de l'image'*/}
|
||||
{/*<span className="font-bold text-black dark:text-white">Le Retzien Libre</span>*/}
|
||||
</Link>
|
||||
|
||||
{/* Navigation desktop */}
|
||||
<nav className="hidden lg:flex items-center gap-1">
|
||||
<Link href={home()} className="px-5 py-1.5 text-lg text-[#1b1b18] dark:text-[#EDEDEC] no-underline hover:underline">
|
||||
Accueil
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
className="inline-block px-5 py-1.5 text-lg leading-normal text-[#1b1b18] hover:border-[#1915014a] dark:border-[#3E3E3A] dark:text-[#EDEDEC] dark:hover:border-[#62605b] no-underline"
|
||||
>
|
||||
<Link href="#services" className="px-5 py-1.5 text-lg text-[#1b1b18] dark:text-[#EDEDEC] no-underline hover:underline">
|
||||
Nos Services
|
||||
</Link>
|
||||
<Link
|
||||
href="#"
|
||||
className="inline-block px-5 py-1.5 text-lg leading-normal text-[#1b1b18] hover:border-[#1915014a] dark:border-[#3E3E3A] dark:text-[#EDEDEC] dark:hover:border-[#62605b] no-underline"
|
||||
>
|
||||
<Link href="#" className="px-5 py-1.5 text-lg text-[#1b1b18] dark:text-[#EDEDEC] no-underline hover:underline">
|
||||
Le Blog
|
||||
</Link>
|
||||
<Link
|
||||
href={contact()}
|
||||
className="inline-block px-5 py-1.5 text-lg leading-normal text-[#1b1b18] hover:border-[#1915014a] dark:border-[#3E3E3A] dark:text-[#EDEDEC] dark:hover:border-[#62605b] no-underline"
|
||||
>
|
||||
<Link href={contact()} className="px-5 py-1.5 text-lg text-[#1b1b18] dark:text-[#EDEDEC] no-underline hover:underline">
|
||||
Contact
|
||||
</Link>
|
||||
</nav>
|
||||
<nav className="flex items-center justify-end gap-4">
|
||||
|
||||
{/* Actions desktop */}
|
||||
<div className="hidden lg:flex items-center gap-3">
|
||||
|
||||
{auth.user ? (
|
||||
<>
|
||||
<Link
|
||||
href={dashboard()}
|
||||
className=" no-underline"
|
||||
>
|
||||
<Link href={dashboard()} className="no-underline">
|
||||
<Button variant="outline">Tableau de bord</Button>
|
||||
</Link>
|
||||
|
||||
<Link
|
||||
className="border-3 bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out font-bold"
|
||||
href={logout()}
|
||||
onClick={handleLogout}
|
||||
className="border-3 bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out font-bold no-underline"
|
||||
data-test="logout-button"
|
||||
>
|
||||
Se déconnecter
|
||||
@@ -88,26 +93,118 @@ export default function NavGuestLayout() {
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Link
|
||||
href={login()}
|
||||
>
|
||||
<Link href={login()} className="no-underline">
|
||||
<Button variant="outline">Se connecter</Button>
|
||||
</Link>
|
||||
<Link
|
||||
href={membership()}
|
||||
>
|
||||
<Link href={membership()} className="no-underline">
|
||||
<Button>Adhérer</Button>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</nav>
|
||||
<button
|
||||
onClick={() => setDark(!dark)}
|
||||
className="absolute top-4 right-4 px-3 py-1 rounded-xl border border-gray-400 dark:border-gray-600 hover:bg-gray-200 dark:hover:bg-gray-800 transition"
|
||||
>
|
||||
{dark ? "☀️ Mode clair" : "🌙 Mode sombre"}
|
||||
</button>
|
||||
<button
|
||||
onClick={toggleAppearance}
|
||||
className="border-3 bg-primary text-secondary-foreground hover:bg-primary/80 h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out font-bold no-underline"
|
||||
aria-label="Changer le thème"
|
||||
>
|
||||
{appearance === 'dark' ? <Sun className="size-4" /> : <Moon className="size-4" />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Actions mobile : thème + hamburger */}
|
||||
<div className="flex lg:hidden items-center gap-2">
|
||||
<button
|
||||
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
||||
className="border-3 bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out font-bold no-underline"
|
||||
aria-label={isMenuOpen ? 'Fermer le menu' : 'Ouvrir le menu'}
|
||||
aria-expanded={isMenuOpen}
|
||||
>
|
||||
{isMenuOpen ? <X className="size-5" /> : <Menu className="size-5" />}
|
||||
</button>
|
||||
<button
|
||||
onClick={toggleAppearance}
|
||||
className="border-3 bg-primary text-secondary-foreground hover:bg-primary/80 h-10 px-4 py-2 shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out font-bold no-underline"
|
||||
aria-label="Changer le thème"
|
||||
>
|
||||
{appearance === 'dark' ? <Sun className="size-4" /> : <Moon className="size-4" />}
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Menu mobile */}
|
||||
{isMenuOpen && (
|
||||
<>
|
||||
{/* Backdrop */}
|
||||
<div
|
||||
className="fixed inset-0 z-40 bg-black/30 lg:hidden"
|
||||
onClick={closeMenu}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
{/* Panel */}
|
||||
<div className="fixed inset-x-0 top-0 z-50 lg:hidden bg-[#F5F5F5] dark:bg-[#0a0a0a] border-b-4 border-black flex flex-col gap-6 p-6">
|
||||
{/* En-tête du panel */}
|
||||
<div className="flex justify-between items-center">
|
||||
<Link href={home()} onClick={closeMenu} className="flex items-center gap-2 no-underline">
|
||||
<AppLogoIcon className="size-8 text-[var(--foreground)] dark:text-white" />
|
||||
<span className="font-bold text-black dark:text-white">Le Retzien Libre</span>
|
||||
</Link>
|
||||
<button
|
||||
onClick={closeMenu}
|
||||
className="p-2 rounded-md border border-black/20 dark:border-white/20 hover:bg-black/5 dark:hover:bg-white/5 transition"
|
||||
aria-label="Fermer le menu"
|
||||
>
|
||||
<X className="size-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Liens de navigation */}
|
||||
<nav className="flex flex-col">
|
||||
<Link href={home()} onClick={closeMenu} className="text-lg py-3 border-b border-black/10 dark:border-white/10 no-underline">
|
||||
<span className="text-black hover:underline">Accueil</span>
|
||||
</Link>
|
||||
<Link href="#services" onClick={closeMenu} className="text-lg py-3 border-b border-black/10 dark:border-white/10 no-underline">
|
||||
<span className="text-black hover:underline">Nos Services</span>
|
||||
</Link>
|
||||
<Link href="#" onClick={closeMenu} className="text-lg py-3 border-b border-black/10 dark:border-white/10 no-underline">
|
||||
<span className="text-black hover:underline">Le Blog</span>
|
||||
</Link>
|
||||
<Link href={contact()} onClick={closeMenu} className="text-lg py-3 no-underline">
|
||||
<span className="text-black hover:underline">Contact</span>
|
||||
</Link>
|
||||
</nav>
|
||||
|
||||
{/* Boutons auth */}
|
||||
<div className="flex flex-col gap-3">
|
||||
{auth.user ? (
|
||||
<>
|
||||
<Link href={dashboard()} onClick={closeMenu} className="no-underline mx-auto mb-4">
|
||||
<Button variant="outline" className="max-w-[150px]">Tableau de bord</Button>
|
||||
</Link>
|
||||
<Link
|
||||
href={logout()}
|
||||
method="post"
|
||||
as="button"
|
||||
onClick={() => { closeMenu(); handleLogout(); }}
|
||||
className="inline-flex items-center justify-center max-w-[150px] mx-auto gap-2 whitespace-nowrap rounded-md text-sm font-bold cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2 border-3 border-black shadow-[4px_4px_0px_rgba(0,0,0,1)] hover:shadow-none hover:translate-2 transition delay-50 duration-200 ease-in-out w-full no-underline"
|
||||
data-test="logout-button"
|
||||
>
|
||||
Se déconnecter
|
||||
</Link>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Link href={login()} onClick={closeMenu} className="no-underline">
|
||||
<Button variant="outline" className="w-full">Se connecter</Button>
|
||||
</Link>
|
||||
<Link href={membership()} onClick={closeMenu} className="no-underline">
|
||||
<Button className="w-full">Adhérer</Button>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
export default function MaintenancePage() {
|
||||
const [dark, setDark] = useState(false);
|
||||
|
||||
|
||||
@@ -1,118 +1,35 @@
|
||||
import {dashboard, home, login, register} from '@/routes';
|
||||
import {type SharedData} from '@/types';
|
||||
import {Head, Link, usePage} from '@inertiajs/react';
|
||||
import {Button} from "@/components/ui/button";
|
||||
import AppLogoIcon from "@/components/app-logo-icon";
|
||||
import illustrationImage from '@/img/utils/lrl-illustration.png';
|
||||
import NavGuestLayout from "@/layouts/nav-guest-layout";
|
||||
|
||||
import { Head } from '@inertiajs/react';
|
||||
import NavGuestLayout from '@/layouts/nav-guest-layout';
|
||||
import { HeroSection } from '@/components/features/home/HeroSection';
|
||||
import { ServicesSection } from '@/components/features/home/ServicesSection';
|
||||
import { AboutSection } from '@/components/features/home/AboutSection';
|
||||
import { AlternativeSection } from '@/components/features/home/AlternativeSection';
|
||||
import { Footer } from '@/components/footer';
|
||||
import { ScrollToTop } from '@/components/common/ScrollToTop';
|
||||
|
||||
export default function Welcome() {
|
||||
const {auth} = usePage<SharedData>().props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head title="Bienvenue">
|
||||
<link rel="preconnect" href="https://fonts.bunny.net"/>
|
||||
<link rel="preconnect" href="https://fonts.bunny.net" />
|
||||
<link
|
||||
href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</Head>
|
||||
<div
|
||||
className="flex min-h-screen flex-col items-center bg-[#F5F5F5] text-[#1b1b18] lg:justify-center dark:bg-[#0a0a0a]">
|
||||
<NavGuestLayout />
|
||||
<section className="flex items-center justify-center gap-4 w-full max-w-[335px] lg:max-w-7xl">
|
||||
<div className="flex w-full items-center justify-center gap-4">
|
||||
<div
|
||||
className="flex flex-col w-full items-center accent-middle py-50 text-center justify-center gap-4">
|
||||
<h1 className="text-5xl text-accent max-w-[450px] mb-5">Pour un internet éthique !</h1>
|
||||
<p className="text-xl mb-5">"Dégooglisons"<br/>
|
||||
nos ordinateurs, nos tablettes et nos smartphones.<br/>
|
||||
<i>"Le chemin est long, mais la voie est libre"</i></p>
|
||||
<Link
|
||||
href={register()}
|
||||
>
|
||||
<Button variant="secondary">Adhérer dès maintenant</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full items-center justify-center gap-4">
|
||||
<img src={illustrationImage} alt="illustration"/>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div
|
||||
className="flex flex-col items-center bg-[#F5F5F5] text-[#1b1b18] lg:justify-center dark:bg-[#0a0a0a]">
|
||||
|
||||
<section className="w-full bg-accent pr-0 py-16">
|
||||
<div className="flex flex-col items-center gap-8 w-full max-w-7xl mx-auto">
|
||||
<h2 className="text-3xl font-bold text-center mb-10">Nos services numériques éthiques, libres,
|
||||
ouverts et locaux</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{[
|
||||
{
|
||||
title: 'Boîte mail',
|
||||
description: 'Service de messagerie électronique sécurisé et respectueux de votre vie privée'
|
||||
},
|
||||
{
|
||||
title: 'Cloud (Nextcloud)',
|
||||
description: 'Stockage en ligne et collaboration avec vos données hébergées localement'
|
||||
},
|
||||
{title: 'File2link', description: 'Partage de fichiers simplifié et sécurisé'},
|
||||
{
|
||||
title: 'Hébergement web',
|
||||
description: 'Solutions d\'hébergement web éthiques et performantes'
|
||||
},
|
||||
{
|
||||
title: 'Sondage',
|
||||
description: 'Créez et partagez des sondages en ligne en toute confidentialité'
|
||||
},
|
||||
{
|
||||
title: 'Liste de diffusion Mail',
|
||||
description: 'Gérez vos communications de groupe efficacement'
|
||||
}
|
||||
].map((service, index) => (
|
||||
<div key={index} className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-lg">
|
||||
<h3 className="text-xl font-semibold mb-3">{service.title}</h3>
|
||||
<p>{service.description}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<section className="w-full max-w-7xl py-16 bg-gray-50 dark:bg-gray-900">
|
||||
<h2 className="text-3xl font-bold text-center mb-10">GAFAM : Quels dangers ?</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-lg">
|
||||
<h3 className="text-xl font-semibold mb-3">Surveillance massive</h3>
|
||||
<p>Les GAFAM collectent et exploitent vos données personnelles à des fins commerciales</p>
|
||||
</div>
|
||||
<div className="bg-white dark:bg-gray-800 p-6 rounded-lg shadow-lg">
|
||||
<h3 className="text-xl font-semibold mb-3">Monopole numérique</h3>
|
||||
<p>Concentration excessive du pouvoir et dépendance aux services centralisés</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="w-full max-w-7xl py-16">
|
||||
<div className="flex flex-col lg:flex-row items-center gap-8">
|
||||
<div className="lg:w-1/2">
|
||||
<h2 className="text-3xl font-bold mb-6">Notre alternative : Le Retzien Libre</h2>
|
||||
<p className="mb-6">Une association locale engagée pour la promotion du logiciel libre et la
|
||||
protection de vos données personnelles.</p>
|
||||
<Link href={register()}>
|
||||
<Button variant="default">Rejoignez-nous</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="lg:w-1/2">
|
||||
<img src={illustrationImage} alt="Le Retzien Libre" className="rounded-lg"/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<div className="flex flex-col min-h-screen bg-[#F5F5F5] text-[#1b1b18] dark:bg-[#0a0a0a] dark:text-[#EDEDEC]">
|
||||
<div className="flex flex-col items-center px-4">
|
||||
<NavGuestLayout />
|
||||
</div>
|
||||
<main className="flex flex-col items-center">
|
||||
<HeroSection />
|
||||
<ServicesSection />
|
||||
<AboutSection />
|
||||
<AlternativeSection />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
<ScrollToTop />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
10
resources/js/types/index.d.ts
vendored
10
resources/js/types/index.d.ts
vendored
@@ -59,6 +59,16 @@ export interface Plans {
|
||||
}
|
||||
|
||||
|
||||
export interface Service {
|
||||
title: string;
|
||||
colorTitle: string;
|
||||
bgTitle: string;
|
||||
bgColor: string;
|
||||
description: string;
|
||||
link: string;
|
||||
illustration: string;
|
||||
}
|
||||
|
||||
export interface PageProps {
|
||||
flash?: FlashMessages;
|
||||
auth?: Auth;
|
||||
|
||||
@@ -32,9 +32,12 @@
|
||||
|
||||
<title inertia>{{ config('app.name', 'Laravel') }}</title>
|
||||
|
||||
<link rel="icon" href="/favicon.ico" sizes="any">
|
||||
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
||||
<link rel="icon" type="image/png" href="/favicons/favicon-96x96.png" sizes="96x96" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicons/favicon.svg" />
|
||||
<link rel="shortcut icon" href="/favicons/favicon.ico" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png" />
|
||||
<meta name="apple-mobile-web-app-title" content="Le Retzien Libre" />
|
||||
<link rel="manifest" href="/favicons/site.webmanifest" />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.bunny.net">
|
||||
<link href="https://fonts.bunny.net/css?family=instrument-sans:400,500,600" rel="stylesheet" />
|
||||
|
||||
Reference in New Issue
Block a user