refactor(mantine): migrate home page

This commit is contained in:
Sonny
2024-10-31 02:25:59 +01:00
committed by Sonny
parent 8d474f74eb
commit 5c4ee3a1cd
13 changed files with 160 additions and 217 deletions

View File

@@ -0,0 +1,16 @@
import { useMantineColorScheme, ActionIcon } from '@mantine/core';
import { TbSun, TbMoonStars } from 'react-icons/tb';
export function MantineThemeSwitcher() {
const { colorScheme, toggleColorScheme } = useMantineColorScheme();
return (
<ActionIcon
variant="default"
aria-label="Toggle color scheme"
onClick={() => toggleColorScheme()}
size="lg"
>
{colorScheme === 'dark' ? <TbSun /> : <TbMoonStars />}
</ActionIcon>
);
}

View File

@@ -1,43 +0,0 @@
import styled from '@emotion/styled';
import { IconType } from 'react-icons/lib';
const AboutItemStyle = styled.li(({ theme }) => ({
width: '350px',
display: 'flex',
gap: '1em',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
'& svg': {
color: theme.colors.blue,
},
'& div': {
fontSize: '1.25rem',
fontWeight: '500',
},
'& p': {
height: '65px',
color: theme.colors.grey,
},
}));
const AboutItem = ({
title,
text,
icon: Icon,
}: {
title: string;
text: string;
icon: IconType;
}) => (
<AboutItemStyle>
<Icon size={60} />
<div>{title}</div>
<p>{text}</p>
</AboutItemStyle>
);
export default AboutItem;

View File

@@ -1,13 +0,0 @@
import styled from '@emotion/styled';
import UnstyledList from '~/components/common/unstyled/unstyled_list';
const AboutList = styled(UnstyledList)({
margin: '4em 0 !important',
display: 'flex',
gap: '2em',
alignItems: 'center',
justifyContent: 'center',
flexWrap: 'wrap',
});
export default AboutList;

View File

@@ -1,54 +0,0 @@
import styled from '@emotion/styled';
import { Link } from '@inertiajs/react';
import { route } from '@izzyjs/route/client';
import { useTranslation } from 'react-i18next';
import Quotes from '~/components/quotes';
const HeroStyle = styled.header(({ theme }) => ({
height: '250px',
minHeight: '250px',
width: '100%',
backgroundColor: theme.colors.secondary,
marginTop: '0.5em',
borderRadius: theme.border.radius,
padding: '1em',
display: 'flex',
gap: '1em',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
'& *': {
textAlign: 'center',
},
}));
const HeroTitle = styled.h1({
fontSize: '32px',
});
const HeroQuote = styled(Quotes)({
fontSize: '20px',
});
const LinkButton = styled(Link)(({ theme }) => ({
fontSize: '1rem',
width: 'fit-content',
color: theme.colors.white,
backgroundColor: theme.colors.primary,
borderRadius: '5rem',
padding: '0.5em 1.5em',
}));
export default function HeroHeader() {
const { t } = useTranslation();
return (
<HeroStyle>
<HeroTitle>{t('about:hero.title')}</HeroTitle>
<HeroQuote>{t('common:slogan')}</HeroQuote>
<LinkButton href={route('dashboard').url}>
{t('about:hero.cta')}
</LinkButton>
</HeroStyle>
);
}

View File

@@ -1,34 +0,0 @@
import styled from '@emotion/styled';
import { useTranslation } from 'react-i18next';
const ScreenshotWrapper = styled.div({
position: 'relative',
height: '360px',
width: '640px',
maxWidth: '100%',
margin: '0 auto',
});
const Screenshot = styled.img(({ theme }) => ({
height: 'auto !important',
width: '100%',
boxShadow: theme.colors.boxShadow,
borderRadius: theme.border.radius,
overflow: 'hidden',
}));
export default function WebsitePreview() {
const { t } = useTranslation('about');
return (
<>
<h2>{t('look-title')}</h2>
<ScreenshotWrapper>
<Screenshot
src="/website-screenshot.png"
alt={t('website-screenshot-alt')}
title={t('website-screenshot-alt')}
/>
</ScreenshotWrapper>
</>
);
}

View File

@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next';
import '@mantine/core/styles.css';
import '@mantine/spotlight/styles.css';
import '../../../styles/index.css';
const theme = createTheme({});

View File

@@ -6,19 +6,23 @@ import MantineNavbar from '~/components/navbar/mantine_navbar';
function MantineContentLayout({ children }: PropsWithChildren) {
return (
<div
<Container
style={{
minHeight: '100%',
width: '100%',
backgroundColor: 'rgb(34, 40, 49)',
display: 'flex',
flexDirection: 'column',
}}
>
<Container>
<MantineNavbar />
<main>{children}</main>
<MantineFooter />
</Container>
</div>
<MantineNavbar />
<main
style={{
flex: 1,
}}
>
{children}
</main>
<MantineFooter />
</Container>
);
}

View File

@@ -15,6 +15,7 @@ import {
import { useDisclosure } from '@mantine/hooks';
import { useTranslation } from 'react-i18next';
import ExternalLink from '~/components/common/external_link';
import { MantineThemeSwitcher } from '~/components/common/mantine_theme_switcher';
import classes from './mobile_navbar.module.css';
export default function MantineNavbar() {
@@ -29,7 +30,7 @@ export default function MantineNavbar() {
<Image src="/logo-light.png" h={40} alt="MyLinks's logo" />
<Group h="100%" gap={0} visibleFrom="sm">
<Link href="#" className={classes.link}>
<Link href="/" className={classes.link}>
{t('home')}
</Link>
<ExternalLink href={PATHS.REPO_GITHUB} className={classes.link}>
@@ -40,17 +41,21 @@ export default function MantineNavbar() {
</ExternalLink>
</Group>
<Group visibleFrom="sm">
<Button component={Link} href={route('auth.login').url}>
<Group>
<MantineThemeSwitcher />
<Button
component={Link}
href={route('auth.login').url}
visibleFrom="sm"
>
{t('login')}
</Button>
<Burger
opened={drawerOpened}
onClick={toggleDrawer}
hiddenFrom="sm"
/>
</Group>
<Burger
opened={drawerOpened}
onClick={toggleDrawer}
hiddenFrom="sm"
/>
</Group>
</header>

View File

@@ -3,6 +3,7 @@
"title": "Welcome to MyLinks",
"cta": "Get started"
},
"description": "An open-source, self-hosted bookmark manager that lets you manage your favorite links in an intuitive interface",
"collection": {
"title": "Create collections",
"text": "Organize your bookmarks by collections to keep your links tidy and find them easily."

View File

@@ -3,6 +3,7 @@
"title": "Bienvenue sur MyLinks",
"cta": "Lancez-vous !"
},
"description": "Un gestionnaire de favoris open-source et auto-hébergé qui vous permet de gérer vos liens favoris dans une interface intuitive",
"collection": {
"title": "Créer des collections",
"text": "Organisez vos favoris dans des collections pour garder vos liens en ordre et les retrouver facilement."

View File

@@ -0,0 +1,26 @@
.wrapper {
padding-top: calc(var(--mantine-spacing-xl) * 2);
padding-bottom: calc(var(--mantine-spacing-xl) * 2);
}
.title {
font-family:
Greycliff CF,
var(--mantine-font-family);
font-weight: 900;
margin-bottom: var(--mantine-spacing-md);
text-align: center;
@media (max-width: $mantine-breakpoint-sm) {
font-size: rem(28px);
text-align: left;
}
}
.description {
text-align: center;
@media (max-width: $mantine-breakpoint-sm) {
text-align: left;
}
}

View File

@@ -1,68 +1,95 @@
import styled from '@emotion/styled';
import { ReactNode } from 'react';
import { MantineContentLayout } from '~/components/layouts/mantine/mantine_content_layout';
import {
Container,
SimpleGrid,
Text,
ThemeIcon,
Title,
rem,
} from '@mantine/core';
import { useTranslation } from 'react-i18next';
import { AiFillFolderOpen } from 'react-icons/ai';
import { FaUser } from 'react-icons/fa';
import { IoIosLink, IoIosSearch, IoIosShareAlt } from 'react-icons/io';
import { IoExtensionPuzzleOutline } from 'react-icons/io5';
import AboutItem from '~/components/home/about/about_item';
import AboutList from '~/components/home/about/about_list';
import HeroHeader from '~/components/home/hero_header';
import WebsitePreview from '~/components/home/website_preview';
import ContentLayout from '~/components/layouts/content_layout';
import classes from './home.module.css';
const PageContent = styled.div({
marginBottom: '4em',
textAlign: 'center',
display: 'flex',
gap: '2em',
flex: 1,
flexDirection: 'column',
});
const features = [
'collection',
'link',
'search',
'extension',
'share',
'contribute',
] as const;
type FeatureName = (typeof features)[number];
function HomePage() {
const { t } = useTranslation();
interface FeatureProps {
name: FeatureName;
}
function getIcon(name: FeatureName) {
switch (name) {
case 'collection':
return AiFillFolderOpen;
case 'link':
return IoIosLink;
case 'search':
return IoIosSearch;
case 'extension':
return IoExtensionPuzzleOutline;
case 'share':
return IoIosShareAlt;
case 'contribute':
return FaUser;
}
}
export function Feature({ name: featureName }: FeatureProps) {
const { t } = useTranslation('about');
const Icon = getIcon(featureName);
return (
<>
<HeroHeader />
<PageContent>
<AboutList>
<AboutItem
icon={AiFillFolderOpen}
title={t('about:collection.title')}
text={t('about:collection.text')}
/>
<AboutItem
icon={IoIosLink}
title={t('about:link.title')}
text={t('about:link.text')}
/>
<AboutItem
icon={IoIosSearch}
title={t('about:search.title')}
text={t('about:search.text')}
/>
<AboutItem
icon={IoExtensionPuzzleOutline}
title={t('about:extension.title')}
text={t('about:extension.text')}
/>
<AboutItem
icon={IoIosShareAlt}
title={t('about:share.title')}
text={t('about:share.text')}
/>
<AboutItem
icon={FaUser}
title={t('about:contribute.title')}
text={t('about:contribute.text')}
/>
</AboutList>
<WebsitePreview />
</PageContent>
</>
<div>
<ThemeIcon variant="light" size={40} radius={40}>
<Icon style={{ width: rem(18), height: rem(18) }} />
</ThemeIcon>
<Text mt="sm" mb={7}>
{t(`${featureName}.title`)}
</Text>
<Text size="sm" c="dimmed" lh={1.6}>
{t(`${featureName}.text`)}
</Text>
</div>
);
}
HomePage.layout = (page: ReactNode) => <ContentLayout children={page} />;
function HomePage() {
const { t } = useTranslation('about');
return (
<Container className={classes.wrapper}>
<Title className={classes.title}>{t('hero.title')}</Title>
<Container size={560} p={0}>
<Text size="sm" className={classes.description}>
{t('description')}
</Text>
</Container>
<SimpleGrid
mt={60}
cols={{ base: 1, sm: 2, md: 3 }}
spacing={{ base: 'xl', md: 50 }}
verticalSpacing={{ base: 'xl', md: 50 }}
>
{features.map((feature, index) => (
<Feature name={feature} key={index} />
))}
</SimpleGrid>
</Container>
);
}
HomePage.layout = (page: ReactNode) => <MantineContentLayout children={page} />;
export default HomePage;

6
inertia/styles/index.css Normal file
View File

@@ -0,0 +1,6 @@
html,
body {
height: 100svh;
width: 100%;
background-color: light-dark(var(--mantine-color-white), rgb(34, 40, 49));
}