chore: initial commit
This commit is contained in:
commit
03f03f7ad2
39 files changed
+7292
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1 @@
|
||||
@import 'tailwindcss';
|
||||
@@ -0,0 +1,63 @@
|
||||
import { SerwistProvider } from '@serwist/turbopack/react'
|
||||
import type { Metadata, Viewport } from 'next'
|
||||
import type { ReactNode } from 'react'
|
||||
import './globals.css'
|
||||
|
||||
const APP_NAME = 'flashcards'
|
||||
const APP_DESCRIPTION = 'Application web PWA installable et utilisable hors connexion.'
|
||||
const APP_TITLE_TEMPLATE = '%s · flashcards'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
applicationName: APP_NAME,
|
||||
title: {
|
||||
default: APP_NAME,
|
||||
template: APP_TITLE_TEMPLATE,
|
||||
},
|
||||
description: APP_DESCRIPTION,
|
||||
manifest: '/manifest.webmanifest',
|
||||
appleWebApp: {
|
||||
capable: true,
|
||||
statusBarStyle: 'default',
|
||||
title: APP_NAME,
|
||||
},
|
||||
formatDetection: {
|
||||
telephone: false,
|
||||
},
|
||||
icons: {
|
||||
icon: '/icon.svg',
|
||||
apple: '/apple-touch-icon-180x180.png',
|
||||
},
|
||||
openGraph: {
|
||||
type: 'website',
|
||||
siteName: APP_NAME,
|
||||
title: {
|
||||
default: APP_NAME,
|
||||
template: APP_TITLE_TEMPLATE,
|
||||
},
|
||||
description: APP_DESCRIPTION,
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary',
|
||||
title: {
|
||||
default: APP_NAME,
|
||||
template: APP_TITLE_TEMPLATE,
|
||||
},
|
||||
description: APP_DESCRIPTION,
|
||||
},
|
||||
}
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: '#0f172a',
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="fr">
|
||||
<body>
|
||||
<SerwistProvider swUrl="/serwist/sw.js" disable={process.env.NODE_ENV === 'development'}>
|
||||
{children}
|
||||
</SerwistProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import type { MetadataRoute } from 'next'
|
||||
|
||||
export default function manifest(): MetadataRoute.Manifest {
|
||||
return {
|
||||
name: 'flashcards',
|
||||
short_name: 'flashcards',
|
||||
description: 'Application web PWA installable et utilisable hors connexion.',
|
||||
lang: 'fr',
|
||||
start_url: '/',
|
||||
scope: '/',
|
||||
display: 'standalone',
|
||||
background_color: '#0f172a',
|
||||
theme_color: '#0f172a',
|
||||
orientation: 'portrait',
|
||||
icons: [
|
||||
{ src: '/pwa-64x64.png', sizes: '64x64', type: 'image/png' },
|
||||
{ src: '/pwa-192x192.png', sizes: '192x192', type: 'image/png' },
|
||||
{ src: '/pwa-512x512.png', sizes: '512x512', type: 'image/png' },
|
||||
{
|
||||
src: '/maskable-icon-512x512.png',
|
||||
sizes: '512x512',
|
||||
type: 'image/png',
|
||||
purpose: 'maskable',
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { render, screen } from '@testing-library/react'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import Home from './page'
|
||||
|
||||
describe('Home', () => {
|
||||
it('affiche le contenu minimal', () => {
|
||||
render(<Home />)
|
||||
expect(screen.getByRole('heading', { level: 1, name: 'Hello world' })).toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
export default function Home() {
|
||||
return (
|
||||
<main>
|
||||
<h1>Hello world</h1>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { createSerwistRoute } from '@serwist/turbopack'
|
||||
|
||||
// Révision du cache : change à chaque commit pour invalider le precache.
|
||||
const revision =
|
||||
spawnSync('git', ['rev-parse', 'HEAD'], { encoding: 'utf-8' }).stdout ?? crypto.randomUUID()
|
||||
|
||||
export const { dynamic, dynamicParams, revalidate, generateStaticParams, GET } = createSerwistRoute(
|
||||
{
|
||||
additionalPrecacheEntries: [{ url: '/~offline', revision }],
|
||||
swSrc: 'src/app/sw.ts',
|
||||
useNativeEsbuild: true,
|
||||
},
|
||||
)
|
||||
@@ -0,0 +1,41 @@
|
||||
/// <reference lib="webworker" />
|
||||
import { defaultCache } from '@serwist/turbopack/worker'
|
||||
import type { PrecacheEntry, RuntimeCaching, SerwistGlobalConfig } from 'serwist'
|
||||
import { NetworkOnly, Serwist } from 'serwist'
|
||||
|
||||
declare global {
|
||||
interface WorkerGlobalScope extends SerwistGlobalConfig {
|
||||
__SW_MANIFEST: (PrecacheEntry | string)[] | undefined
|
||||
}
|
||||
}
|
||||
|
||||
declare const self: ServiceWorkerGlobalScope
|
||||
|
||||
// Ne jamais mettre en cache les appels API
|
||||
const runtimeCaching: RuntimeCaching[] = [
|
||||
{
|
||||
matcher: ({ sameOrigin, url }) => sameOrigin && url.pathname.startsWith('/api/'),
|
||||
handler: new NetworkOnly(),
|
||||
},
|
||||
...defaultCache,
|
||||
]
|
||||
|
||||
const serwist = new Serwist({
|
||||
precacheEntries: self.__SW_MANIFEST,
|
||||
skipWaiting: true,
|
||||
clientsClaim: true,
|
||||
navigationPreload: true,
|
||||
runtimeCaching,
|
||||
fallbacks: {
|
||||
entries: [
|
||||
{
|
||||
url: '/~offline',
|
||||
matcher({ request }) {
|
||||
return request.mode === 'navigate'
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
serwist.addEventListeners()
|
||||
@@ -0,0 +1,11 @@
|
||||
import Link from 'next/link'
|
||||
|
||||
export default function OfflinePage() {
|
||||
return (
|
||||
<main>
|
||||
<h1>Vous êtes hors connexion</h1>
|
||||
<p>Reconnectez-vous pour continuer.</p>
|
||||
<Link href="/">Accueil</Link>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import '@testing-library/jest-dom/vitest'
|
||||
import { cleanup } from '@testing-library/react'
|
||||
import { afterEach } from 'vitest'
|
||||
|
||||
afterEach(() => cleanup())
|
||||
|
||||
Object.defineProperty(window, 'matchMedia', {
|
||||
writable: true,
|
||||
value: (query: string) => ({
|
||||
matches: false,
|
||||
media: query,
|
||||
onchange: null,
|
||||
addListener: () => {},
|
||||
removeListener: () => {},
|
||||
addEventListener: () => {},
|
||||
removeEventListener: () => {},
|
||||
dispatchEvent: () => false,
|
||||
}),
|
||||
})
|
||||
Reference in new issue
Block a user