diff --git a/inertia/components/dashboard/side_nav/side_navigation.tsx b/inertia/components/dashboard/side_nav/side_navigation.tsx
index 1432f6e..5d19998 100644
--- a/inertia/components/dashboard/side_nav/side_navigation.tsx
+++ b/inertia/components/dashboard/side_nav/side_navigation.tsx
@@ -52,6 +52,9 @@ export default function SideNavigation() {
{t('collection.create')}
+ -
+ Archives
+
diff --git a/inertia/components/layouts/_theme_layout.tsx b/inertia/components/layouts/_theme_layout.tsx
index 3735b43..490850b 100644
--- a/inertia/components/layouts/_theme_layout.tsx
+++ b/inertia/components/layouts/_theme_layout.tsx
@@ -64,6 +64,12 @@ function GlobalStyles() {
boxShadow: '0 1px 0 rgba(0, 0, 0, 0.2), 0 0 0 2px #ffffff inset',
display: 'inline-block',
},
+
+ hr: {
+ color: localTheme.colors.secondary,
+ width: '100%',
+ marginBlock: '1em',
+ },
});
const documentStyle = css({
diff --git a/inertia/components/layouts/content_layout.tsx b/inertia/components/layouts/content_layout.tsx
index a86e119..5170b62 100644
--- a/inertia/components/layouts/content_layout.tsx
+++ b/inertia/components/layouts/content_layout.tsx
@@ -18,9 +18,15 @@ const ContentLayoutStyle = styled(TransitionLayout)(({ theme }) => ({
},
}));
-const ContentLayout = ({ children }: { children: ReactNode }) => (
+const ContentLayout = ({
+ children,
+ className,
+}: {
+ children: ReactNode;
+ className?: string;
+}) => (
-
+
{children}
diff --git a/inertia/components/quotes.tsx b/inertia/components/quotes.tsx
new file mode 100644
index 0000000..8110064
--- /dev/null
+++ b/inertia/components/quotes.tsx
@@ -0,0 +1,28 @@
+import styled from '@emotion/styled';
+import { rgba } from '~/lib/color';
+
+const Quotes = styled.p(({ theme }) => ({
+ position: 'relative',
+ width: 'fit-content',
+ whiteSpace: 'pre-wrap',
+ textAlign: 'center',
+ fontStyle: 'italic',
+ color: rgba(theme.colors.font, 0.75),
+
+ '&::before, &::after': {
+ position: 'absolute',
+ fontFamily: 'sans-serif',
+ fontSize: '2.25em',
+ },
+
+ '&::before': {
+ left: '-0.65em',
+ content: '"“"',
+ },
+ '&::after': {
+ right: '-0.5em',
+ content: '"”"',
+ },
+}));
+
+export default Quotes;
diff --git a/inertia/components/settings/modal.tsx b/inertia/components/settings/modal.tsx
index 1a6faef..8d59332 100644
--- a/inertia/components/settings/modal.tsx
+++ b/inertia/components/settings/modal.tsx
@@ -1,9 +1,12 @@
+import { Link } from '@inertiajs/react';
+import { route } from '@izzyjs/route/client';
import { useTranslation } from 'react-i18next';
import { BsGear } from 'react-icons/bs';
import Modal from '~/components/common/modal/modal';
import LangSelector from '~/components/lang_selector';
import ThemeSwitcher from '~/components/theme_switcher';
import useToggle from '~/hooks/use_modal';
+import useUser from '~/hooks/use_user';
export default function ModalSettings({
openItem: OpenItem,
@@ -13,6 +16,7 @@ export default function ModalSettings({
}) {
const { t } = useTranslation('common');
const { isShowing, open, close } = useToggle();
+ const { isAuthenticated } = useUser();
return (
<>
@@ -23,6 +27,12 @@ export default function ModalSettings({
+ {isAuthenticated && (
+ <>
+
+ {t('logout')}
+ >
+ )}
>
);
diff --git a/inertia/i18n/locales/en/common.json b/inertia/i18n/locales/en/common.json
index ff4de33..5d1027a 100644
--- a/inertia/i18n/locales/en/common.json
+++ b/inertia/i18n/locales/en/common.json
@@ -33,8 +33,8 @@
"remove-favorite": "Remove from favorites",
"favorites-appears-here": "Your favorites will appear here",
"no-item-found": "No item found",
- "search": "Search",
"admin": "Administrator",
+ "search": "Search",
"avatar": "{{name}}'s avatar",
"generic-error": "Something went wrong",
"generic-error-description": "An error has occurred, if this happens again please create an issue with as much detail as possible.",
diff --git a/inertia/i18n/locales/en/login.json b/inertia/i18n/locales/en/login.json
index 16fe994..9602b80 100644
--- a/inertia/i18n/locales/en/login.json
+++ b/inertia/i18n/locales/en/login.json
@@ -1,5 +1,6 @@
{
"title": "Authentication",
"informative-text": "Authentication required to use MyLinks",
- "continue-with": "Continue with {{provider}}"
-}
+ "continue-with": "Continue with {{provider}}",
+ "accept-terms": "By continuing, you accept the"
+}
\ No newline at end of file
diff --git a/inertia/i18n/locales/fr/common.json b/inertia/i18n/locales/fr/common.json
index 2cfd0c5..b05fd2a 100644
--- a/inertia/i18n/locales/fr/common.json
+++ b/inertia/i18n/locales/fr/common.json
@@ -18,11 +18,10 @@
"collection": {
"collections": "Collection",
"collections_other": "Collections",
- "collection": "Collection",
"name": "Nom de la collection",
"description": "Description de la collection",
- "visibility": "Public",
"no-description": "Aucune description",
+ "visibility": "Public",
"create": "Créer une collection",
"edit": "Modifier une collection",
"delete": "Supprimer une collection",
diff --git a/inertia/i18n/locales/fr/login.json b/inertia/i18n/locales/fr/login.json
index ede3193..601dfd1 100644
--- a/inertia/i18n/locales/fr/login.json
+++ b/inertia/i18n/locales/fr/login.json
@@ -1,5 +1,6 @@
{
"title": "Authentification",
"informative-text": "Authentification requise pour utiliser MyLinks",
- "continue-with": "Continuer avec {{provider}}"
-}
+ "continue-with": "Continuer avec {{provider}}",
+ "accept-terms": "En poursuivant, vous acceptez les"
+}
\ No newline at end of file
diff --git a/inertia/pages/login.tsx b/inertia/pages/login.tsx
index e9ea528..8a0fbe1 100644
--- a/inertia/pages/login.tsx
+++ b/inertia/pages/login.tsx
@@ -1,9 +1,82 @@
+import styled from '@emotion/styled';
+import { Head, Link } from '@inertiajs/react';
import { route } from '@izzyjs/route/client';
+import { useTranslation } from 'react-i18next';
+import { FcGoogle } from 'react-icons/fc';
+import Button from '~/components/common/form/_button';
import ContentLayout from '~/components/layouts/content_layout';
+import Quotes from '~/components/quotes';
-const LoginPage = () => (
-
- Continue with Google
-
-);
-export default LoginPage;
+const LoginContainer = styled.div({
+ width: '100%',
+ maxWidth: '100%',
+ whiteSpace: 'nowrap',
+ display: 'flex',
+ alignItems: 'center',
+ gap: '1.5em',
+ flexDirection: 'column',
+});
+
+const FormWrapper = styled.div(({ theme }) => ({
+ width: '100%',
+ backgroundColor: theme.colors.secondary,
+ padding: '2em',
+ borderRadius: theme.border.radius,
+ border: `1px solid ${theme.colors.lightGrey}`,
+ display: 'flex',
+ gap: '1em',
+ flex: 1,
+ alignItems: 'center',
+ justifyContent: 'center',
+ flexDirection: 'column',
+}));
+
+const InformativeText = styled.p(({ theme }) => ({
+ width: '100%',
+ padding: '10px',
+ textAlign: 'center',
+ color: theme.colors.darkBlue,
+ backgroundColor: theme.colors.lightestBlue,
+ borderRadius: theme.border.radius,
+}));
+
+const AgreementText = styled.p(({ theme }) => ({
+ color: theme.colors.grey,
+}));
+
+const ButtonLink = styled(Button.withComponent('a'))({
+ display: 'flex',
+ gap: '0.35em',
+ alignItems: 'center',
+ justifyContent: 'center',
+});
+
+export default function LoginPage() {
+ const { t } = useTranslation();
+ return (
+
+
+
+
+ {t('common:slogan')}
+
+ {t('login:title')}
+ {t('login:informative-text')}
+
+ {' '}
+ {t('login:continue-with', { provider: 'Google' })}
+
+
+
+ {t('login:accept-terms')}{' '}
+ {t('common:terms')}
+
+
+
+ );
+}
diff --git a/inertia/styles/theme.ts b/inertia/styles/theme.ts
index 567b52a..0343eb2 100644
--- a/inertia/styles/theme.ts
+++ b/inertia/styles/theme.ts
@@ -4,6 +4,7 @@ import { rgba } from '~/lib/color';
export const primaryColor = '#3f88c5';
export const primaryDarkColor = '#005aa5';
+const lightestBlue = '#d3e8fa';
const lightBlue = '#82c5fede';
const darkBlue = primaryDarkColor;
@@ -39,6 +40,7 @@ export const lightTheme: Theme = {
lightGrey: '#dadce0',
grey: '#888888',
+ lightestBlue,
lightBlue,
blue: primaryColor,
darkBlue,
@@ -68,6 +70,7 @@ export const darkTheme: Theme = {
lightGrey: '#323a47',
grey: '#999999',
+ lightestBlue,
lightBlue,
blue: '#4fadfc',
darkBlue,
diff --git a/inertia/types/emotion.d.ts b/inertia/types/emotion.d.ts
index 01a10fc..151f289 100644
--- a/inertia/types/emotion.d.ts
+++ b/inertia/types/emotion.d.ts
@@ -14,6 +14,7 @@ declare module '@emotion/react' {
lightGrey: string;
grey: string;
+ lightestBlue: string;
lightBlue: string;
blue: string;
darkBlue: string;
diff --git a/public/empty-image.png b/public/empty-image.png
new file mode 100644
index 0000000..1cb3567
Binary files /dev/null and b/public/empty-image.png differ
diff --git a/public/favicon.png b/public/favicon.png
new file mode 100644
index 0000000..213041c
Binary files /dev/null and b/public/favicon.png differ
diff --git a/public/favicon.svg b/public/favicon.svg
new file mode 100644
index 0000000..7409f0a
--- /dev/null
+++ b/public/favicon.svg
@@ -0,0 +1,5 @@
+
+
diff --git a/public/logo-light.png b/public/logo-light.png
new file mode 100644
index 0000000..466711e
Binary files /dev/null and b/public/logo-light.png differ
diff --git a/public/logo-light.svg b/public/logo-light.svg
new file mode 100644
index 0000000..6c815bc
--- /dev/null
+++ b/public/logo-light.svg
@@ -0,0 +1,47 @@
+
+
diff --git a/public/manifest.json b/public/manifest.json
new file mode 100644
index 0000000..7c1be2e
--- /dev/null
+++ b/public/manifest.json
@@ -0,0 +1,24 @@
+{
+ "name": "MyLinks",
+ "short_name": "MyLinks",
+ "description": "MyLinks is a free and open source software, that lets you manage your favorite links in an intuitive interface",
+ "launch_handler": {
+ "client_mode": [
+ "focus-existing",
+ "auto"
+ ]
+ },
+ "icons": [
+ {
+ "src": "/favicon.png",
+ "sizes": "192x192",
+ "type": "image/png",
+ "purpose": "any maskable"
+ }
+ ],
+ "theme_color": "#f0eef6",
+ "background_color": "#f0eef6",
+ "start_url": "/",
+ "display": "standalone",
+ "orientation": "portrait"
+}
\ No newline at end of file