feat: add multiple project info pages with metadata and structured data
- Created new project pages for LazyBot, Learn, Linktree, Moon Phases, FocusPomodoro, Portfolio, QCU Physique-Chimie, QRCode, ReduceLink, Sudoku, and Visio. - Each page includes detailed descriptions, features, use cases, tech stack, FAQs, and images. - Implemented JSON-LD structured data for SEO optimization. - Added a sitemap generation for better indexing of project pages. - Introduced a reusable JsonLd component for structured data rendering. - Configured Tailwind CSS for styling across the application.
@@ -30,6 +30,9 @@ yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# local editor settings (can contain private deployment config)
|
||||
.vscode/
|
||||
|
||||
# env files (can opt-in for committing if needed)
|
||||
.env*
|
||||
|
||||
|
||||
@@ -1,36 +1,99 @@
|
||||
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
||||
# Hub ArthurP
|
||||
|
||||
## Getting Started
|
||||
Hub centralisant les projets et outils d'ArthurP.
|
||||
|
||||
First, run the development server:
|
||||
Le site regroupe des applications web (productivite, utilitaires, education, etc.) avec une page detaillee pour chaque projet, des pages legales, et les elements SEO (robots, sitemap, donnees structurees).
|
||||
|
||||
## Site en production
|
||||
|
||||
- URL officielle: https://arthurp.fr
|
||||
|
||||
## Stack technique
|
||||
|
||||
- Next.js 16 (App Router)
|
||||
- React 19
|
||||
- TypeScript
|
||||
- Tailwind CSS 4
|
||||
- ESLint
|
||||
|
||||
## Fonctionnalites principales
|
||||
|
||||
- Page d'accueil avec presentation des projets
|
||||
- Pages dediees par projet dans `src/app/projets/*`
|
||||
- Pages legales dans `src/app/legal/*`
|
||||
- SEO technique avec `public/robots.txt` et `src/app/sitemap.ts`
|
||||
- Donnees structurees JSON-LD via composant reutilisable
|
||||
|
||||
## Installation locale
|
||||
|
||||
Pre-requis:
|
||||
|
||||
- Node.js 20+
|
||||
- npm
|
||||
|
||||
Installation:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Lancer le projet
|
||||
|
||||
Developpement:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
Build de production:
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
||||
Lancer le build en local:
|
||||
|
||||
## Learn More
|
||||
```bash
|
||||
npm run start
|
||||
```
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
Lint:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
```bash
|
||||
npm run lint
|
||||
```
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
||||
## Scripts npm
|
||||
|
||||
## Deploy on Vercel
|
||||
- `dev`: demarre le serveur Next.js en mode developpement
|
||||
- `build`: genere le build de production
|
||||
- `start`: demarre le serveur sur le build genere
|
||||
- `lint`: verifie la qualite du code avec ESLint
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
## Structure du projet
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
||||
```text
|
||||
src/
|
||||
app/
|
||||
page.tsx
|
||||
layout.tsx
|
||||
globals.css
|
||||
legal/
|
||||
projets/
|
||||
sitemap.ts
|
||||
components/
|
||||
public/
|
||||
robots.txt
|
||||
```
|
||||
|
||||
## Publication GitHub
|
||||
|
||||
Points importants avant push:
|
||||
|
||||
- Ne jamais versionner de secrets ou credentials
|
||||
- Verifier que les fichiers d'environnement restent ignores (`.env*`)
|
||||
- Verifier que les configurations locales editeur/deploiement restent ignorees (`.vscode/`)
|
||||
|
||||
## License
|
||||
|
||||
Projet prive - tous droits reserves sauf mention contraire.
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
services:
|
||||
web:
|
||||
image: node:20-alpine
|
||||
working_dir: /app
|
||||
volumes:
|
||||
- ./:/app
|
||||
ports:
|
||||
- "3004:3000"
|
||||
command: sh -c "npm install && npm run build && npm start"
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/components/*": ["src/components/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
"name": "hub",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"next": "16.1.6",
|
||||
"next": "^16.2.1",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3"
|
||||
},
|
||||
@@ -18,7 +18,7 @@
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.1.6",
|
||||
"eslint-config-next": "^16.2.1",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
@@ -1036,15 +1036,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz",
|
||||
"integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.1.tgz",
|
||||
"integrity": "sha512-n8P/HCkIWW+gVal2Z8XqXJ6aB3J0tuM29OcHpCsobWlChH/SITBs1DFBk/HajgrwDkqqBXPbuUuzgDvUekREPg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/eslint-plugin-next": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.6.tgz",
|
||||
"integrity": "sha512-/Qq3PTagA6+nYVfryAtQ7/9FEr/6YVyvOtl6rZnGsbReGLf0jZU6gkpr1FuChAQpvV46a78p4cmHOVP8mbfSMQ==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.1.tgz",
|
||||
"integrity": "sha512-r0epZGo24eT4g08jJlg2OEryBphXqO8aL18oajoTKLzHJ6jVr6P6FI58DLMug04MwD3j8Fj0YK0slyzneKVyzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1052,9 +1052,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz",
|
||||
"integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.1.tgz",
|
||||
"integrity": "sha512-BwZ8w8YTaSEr2HIuXLMLxIdElNMPvY9fLqb20LX9A9OMGtJilhHLbCL3ggyd0TwjmMcTxi0XXt+ur1vWUoxj2Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1068,9 +1068,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz",
|
||||
"integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.1.tgz",
|
||||
"integrity": "sha512-/vrcE6iQSJq3uL3VGVHiXeaKbn8Es10DGTGRJnRZlkNQQk3kaNtAJg8Y6xuAlrx/6INKVjkfi5rY0iEXorZ6uA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1084,9 +1084,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz",
|
||||
"integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.1.tgz",
|
||||
"integrity": "sha512-uLn+0BK+C31LTVbQ/QU+UaVrV0rRSJQ8RfniQAHPghDdgE+SlroYqcmFnO5iNjNfVWCyKZHYrs3Nl0mUzWxbBw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1100,9 +1100,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz",
|
||||
"integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.1.tgz",
|
||||
"integrity": "sha512-ssKq6iMRnHdnycGp9hCuGnXJZ0YPr4/wNwrfE5DbmvEcgl9+yv97/Kq3TPVDfYome1SW5geciLB9aiEqKXQjlQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1116,9 +1116,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz",
|
||||
"integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.1.tgz",
|
||||
"integrity": "sha512-HQm7SrHRELJ30T1TSmT706IWovFFSRGxfgUkyWJZF/RKBMdbdRWJuFrcpDdE5vy9UXjFOx6L3mRdqH04Mmx0hg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1132,9 +1132,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz",
|
||||
"integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.1.tgz",
|
||||
"integrity": "sha512-aV2iUaC/5HGEpbBkE+4B8aHIudoOy5DYekAKOMSHoIYQ66y/wIVeaRx8MS2ZMdxe/HIXlMho4ubdZs/J8441Tg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1148,9 +1148,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz",
|
||||
"integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.1.tgz",
|
||||
"integrity": "sha512-IXdNgiDHaSk0ZUJ+xp0OQTdTgnpx1RCfRTalhn3cjOP+IddTMINwA7DXZrwTmGDO8SUr5q2hdP/du4DcrB1GxA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1164,9 +1164,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz",
|
||||
"integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.1.tgz",
|
||||
"integrity": "sha512-qvU+3a39Hay+ieIztkGSbF7+mccbbg1Tk25hc4JDylf8IHjYmY/Zm64Qq1602yPyQqvie+vf5T/uPwNxDNIoeg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1767,9 +1767,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
|
||||
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1777,13 +1777,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||
"version": "9.0.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
|
||||
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
|
||||
"version": "9.0.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
|
||||
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
"brace-expansion": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
@@ -2141,9 +2141,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz",
|
||||
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2420,9 +2420,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
|
||||
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
|
||||
"version": "1.1.13",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
|
||||
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3087,13 +3087,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-next": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.6.tgz",
|
||||
"integrity": "sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.1.tgz",
|
||||
"integrity": "sha512-qhabwjQZ1Mk53XzXvmogf8KQ0tG0CQXF0CZ56+2/lVhmObgmaqj7x5A1DSrWdZd3kwI7GTPGUjFne+krRxYmFg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/eslint-plugin-next": "16.1.6",
|
||||
"@next/eslint-plugin-next": "16.2.1",
|
||||
"eslint-import-resolver-node": "^0.3.6",
|
||||
"eslint-import-resolver-typescript": "^3.5.2",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
@@ -3217,6 +3217,7 @@
|
||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
@@ -3569,9 +3570,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
||||
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
|
||||
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@@ -4884,9 +4885,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
@@ -4955,14 +4956,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz",
|
||||
"integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==",
|
||||
"version": "16.2.1",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.2.1.tgz",
|
||||
"integrity": "sha512-VaChzNL7o9rbfdt60HUj8tev4m6d7iC1igAy157526+cJlXOQu5LzsBXNT+xaJnTP/k+utSX5vMv7m0G+zKH+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/env": "16.1.6",
|
||||
"@next/env": "16.2.1",
|
||||
"@swc/helpers": "0.5.15",
|
||||
"baseline-browser-mapping": "^2.8.3",
|
||||
"baseline-browser-mapping": "^2.9.19",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
"postcss": "8.4.31",
|
||||
"styled-jsx": "5.1.6"
|
||||
@@ -4974,15 +4975,15 @@
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "16.1.6",
|
||||
"@next/swc-darwin-x64": "16.1.6",
|
||||
"@next/swc-linux-arm64-gnu": "16.1.6",
|
||||
"@next/swc-linux-arm64-musl": "16.1.6",
|
||||
"@next/swc-linux-x64-gnu": "16.1.6",
|
||||
"@next/swc-linux-x64-musl": "16.1.6",
|
||||
"@next/swc-win32-arm64-msvc": "16.1.6",
|
||||
"@next/swc-win32-x64-msvc": "16.1.6",
|
||||
"sharp": "^0.34.4"
|
||||
"@next/swc-darwin-arm64": "16.2.1",
|
||||
"@next/swc-darwin-x64": "16.2.1",
|
||||
"@next/swc-linux-arm64-gnu": "16.2.1",
|
||||
"@next/swc-linux-arm64-musl": "16.2.1",
|
||||
"@next/swc-linux-x64-gnu": "16.2.1",
|
||||
"@next/swc-linux-x64-musl": "16.2.1",
|
||||
"@next/swc-win32-arm64-msvc": "16.2.1",
|
||||
"@next/swc-win32-x64-msvc": "16.2.1",
|
||||
"sharp": "^0.34.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.1.0",
|
||||
@@ -5280,9 +5281,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -6083,9 +6084,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby/node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"lint": "eslint"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "16.1.6",
|
||||
"next": "^16.2.1",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3"
|
||||
},
|
||||
@@ -19,7 +19,7 @@
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.1.6",
|
||||
"eslint-config-next": "^16.2.1",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 246 KiB |
@@ -1 +0,0 @@
|
||||
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
|
||||
|
Before Width: | Height: | Size: 391 B |
@@ -1 +0,0 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 68 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 52 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,3 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
Sitemap: https://arthurp.fr/sitemap.xml
|
||||
@@ -1 +0,0 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
|
||||
|
Before Width: | Height: | Size: 128 B |
@@ -1 +0,0 @@
|
||||
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
|
||||
|
Before Width: | Height: | Size: 385 B |
|
Before Width: | Height: | Size: 25 KiB |
@@ -1,8 +1,12 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--background: #f8f6f3; /* blanc-beige */
|
||||
--foreground: #171717;
|
||||
--scrollbar-bg: #f3ede6;
|
||||
--scrollbar-thumb: #e2d6c2;
|
||||
--scrollbar-thumb-hover: #cbb893;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
@@ -12,10 +16,14 @@
|
||||
--font-mono: var(--font-geist-mono);
|
||||
}
|
||||
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
--scrollbar-bg: #23211e;
|
||||
--scrollbar-thumb: #3a3327;
|
||||
--scrollbar-thumb-hover: #5a4a2e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,3 +32,48 @@ body {
|
||||
color: var(--foreground);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
/* Scrollbar styling (Webkit/Blink) */
|
||||
::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
background: var(--scrollbar-bg);
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--scrollbar-thumb);
|
||||
border-radius: 8px;
|
||||
border: 2px solid var(--scrollbar-bg);
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: var(--scrollbar-thumb-hover);
|
||||
}
|
||||
::-webkit-scrollbar-corner {
|
||||
background: var(--scrollbar-bg);
|
||||
}
|
||||
|
||||
/* Scrollbar styling (Firefox) */
|
||||
html {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-bg);
|
||||
}
|
||||
|
||||
/* Scrollbar styling */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
background: #f4f4f5;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #dbeafe;
|
||||
border-radius: 8px;
|
||||
border: 2px solid #f4f4f5;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #60a5fa;
|
||||
}
|
||||
::-webkit-scrollbar-corner {
|
||||
background: #f4f4f5;
|
||||
}
|
||||
|
||||
html {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #dbeafe #f4f4f5;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import Link from "next/link";
|
||||
import JsonLd from "@/components/JsonLd";
|
||||
import "./globals.css";
|
||||
|
||||
const geistSans = Geist({
|
||||
@@ -13,8 +15,26 @@ const geistMono = Geist_Mono({
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
title: "ArthurP.fr – Hub de projets et outils",
|
||||
description: "Découvre tous les outils, bots Discord, QCM, générateurs et ressources créés par ArthurP. Un point d’accès unique pour tout ce que je développe et partage.",
|
||||
metadataBase: new URL("https://arthurp.fr"),
|
||||
openGraph: {
|
||||
title: "ArthurP.fr – Hub de projets et outils",
|
||||
description: "Découvre tous les outils, bots Discord, QCM, générateurs et ressources créés par ArthurP.",
|
||||
url: "https://arthurp.fr",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: "ArthurP.fr – Hub de projets et outils",
|
||||
description: "Découvre tous les outils, bots Discord, QCM, générateurs et ressources créés par ArthurP.",
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
@@ -23,11 +43,37 @@ export default function RootLayout({
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
{children}
|
||||
<html lang="fr">
|
||||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased bg-white text-zinc-900`}>
|
||||
<JsonLd
|
||||
data={{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
name: "ArthurP.fr",
|
||||
url: "https://arthurp.fr",
|
||||
description:
|
||||
"Découvre tous les outils, bots Discord, QCM, générateurs et ressources créés par ArthurP.",
|
||||
inLanguage: "fr-FR",
|
||||
author: {
|
||||
"@type": "Person",
|
||||
name: "ArthurP",
|
||||
url: "https://arthurp.fr",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<div className="min-h-screen flex flex-col">
|
||||
<div className="flex-1">
|
||||
{children}
|
||||
</div>
|
||||
<footer className="w-full border-t border-zinc-200 bg-zinc-50 py-4 text-center text-sm text-zinc-500">
|
||||
<nav aria-label="Liens légaux" className="flex flex-wrap justify-center gap-4">
|
||||
<Link href="/legal/mentions-legales" className="hover:underline">Mentions légales</Link>
|
||||
<Link href="/legal/confidentialite" className="hover:underline">Confidentialité</Link>
|
||||
<Link href="/legal/cgu" className="hover:underline">CGU</Link>
|
||||
</nav>
|
||||
<div className="mt-2">© {new Date().getFullYear()} ArthurP</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import Link from "next/link";
|
||||
|
||||
export default function CGU() {
|
||||
return (
|
||||
<div className="min-h-screen bg-white w-full">
|
||||
<main className="max-w-2xl mx-auto py-12 px-4 text-zinc-900">
|
||||
<Link href="/" className="mb-6 inline-block">
|
||||
<button className="rounded-lg bg-[#e2d6c2] px-4 py-2 text-[#5a4a2e] font-medium hover:bg-[#d6bfa3] border border-[#d6bfa3] transition-colors">← Retour à l'accueil</button>
|
||||
</Link>
|
||||
<h1 className="text-2xl font-bold mb-4">Conditions Générales d’Utilisation</h1>
|
||||
<p className="mb-2">L’utilisation des outils proposés sur arthurp.fr est libre et gratuite. L’éditeur ne saurait être tenu responsable d’un usage inapproprié ou des conséquences liées à l’utilisation des outils.</p>
|
||||
<p className="mb-2">En utilisant ce site, vous acceptez ces conditions. Pour toute question, contactez-moi à contact [at] arthurp.fr.</p>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Confidentialite() {
|
||||
return (
|
||||
<div className="min-h-screen bg-white w-full">
|
||||
<main className="max-w-2xl mx-auto py-12 px-4 text-zinc-900">
|
||||
<Link href="/" className="mb-6 inline-block">
|
||||
<button className="rounded-lg bg-[#e2d6c2] px-4 py-2 text-[#5a4a2e] font-medium hover:bg-[#d6bfa3] border border-[#d6bfa3] transition-colors">← Retour à l'accueil</button>
|
||||
</Link>
|
||||
<h1 className="text-2xl font-bold mb-4">Politique de confidentialité</h1>
|
||||
<p className="mb-2">Aucune donnée personnelle n’est collectée à des fins commerciales. Les outils proposés peuvent utiliser des cookies techniques pour le bon fonctionnement du site.</p>
|
||||
<p className="mb-2">Aucune information n’est transmise à des tiers. Pour toute question, contactez-moi à contact [at] arthurp.fr.</p>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import Link from "next/link";
|
||||
|
||||
export default function MentionsLegales() {
|
||||
return (
|
||||
<div className="min-h-screen bg-white w-full">
|
||||
<main className="max-w-2xl mx-auto py-12 px-4 text-zinc-900">
|
||||
<Link href="/" className="mb-6 inline-block">
|
||||
<button className="rounded-lg bg-[#e2d6c2] px-4 py-2 text-[#5a4a2e] font-medium hover:bg-[#d6bfa3] border border-[#d6bfa3] transition-colors">← Retour à l'accueil</button>
|
||||
</Link>
|
||||
<h1 className="text-2xl font-bold mb-4">Mentions légales</h1>
|
||||
<p className="mb-2">Conformément à la loi, voici les informations légales du site arthurp.fr.</p>
|
||||
<ul className="mb-4 list-disc pl-6">
|
||||
<li><strong>Éditeur :</strong> Arthur P. (contact via Discord ou formulaire sur le site)</li>
|
||||
<li><strong>Contact :</strong> contact [at] arthurp.fr</li>
|
||||
</ul>
|
||||
<p className="text-zinc-500 text-sm">Ce site est un projet personnel, sans but commercial.</p>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,63 +1,178 @@
|
||||
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
const projects = [
|
||||
{
|
||||
title: "LazyBot",
|
||||
description: "Un bot Discord configurable avec dashboard web, inspiré de Draftbot.",
|
||||
image: "/placeholder-lazybot.webp", // À remplacer par une capture plus tard
|
||||
url: "https://lazybot.arthurp.fr",
|
||||
infoUrl: "/projets/lazybot"
|
||||
},
|
||||
{
|
||||
title: "QRCode",
|
||||
description: "Générateur de QR codes personnalisés, partageable par URL, sans téléchargement d'image.",
|
||||
image: "/placeholder-qrcode.webp",
|
||||
url: "https://qrcode.arthurp.fr",
|
||||
infoUrl: "/projets/qrcode"
|
||||
},
|
||||
{
|
||||
title: "QCU Physique-Chimie",
|
||||
description: "Révise la physique-chimie avec plus de 150 QCU configurables et corrigés.",
|
||||
image: "/placeholder-qcu.webp",
|
||||
url: "https://qcu.arthurp.fr",
|
||||
infoUrl: "/projets/qcu"
|
||||
},
|
||||
{
|
||||
title: "ReduceLink",
|
||||
description: "Transformez vos URLs longues en liens courts et mémorables. Gratuit, sans inscription, avec QR Code et statistiques.",
|
||||
image: "/placeholder-reducelink.webp",
|
||||
url: "https://reducelink.arthurp.fr/",
|
||||
infoUrl: "/projets/reducelink"
|
||||
},
|
||||
{
|
||||
title: "Linktree",
|
||||
description: "Tous mes réseaux et liens importants, centralisés pour ma communauté.",
|
||||
image: "/placeholder-linktree.webp",
|
||||
url: "https://links.arthurp.fr",
|
||||
infoUrl: "/projets/links"
|
||||
},
|
||||
{
|
||||
title: "Learn",
|
||||
description: "Des réponses claires à des questions populaires sur de nombreux sujets.",
|
||||
image: "/placeholder-learn.webp",
|
||||
url: "https://learn.arthurp.fr",
|
||||
infoUrl: "/projets/learn"
|
||||
},
|
||||
{
|
||||
title: "Sudoku Generator & Solver",
|
||||
description: "Génère, résout et vérifie des grilles de sudoku de plusieurs niveaux de difficulté.",
|
||||
image: "/placeholder-sudoku.webp",
|
||||
url: "https://sudoku.arthurp.fr",
|
||||
infoUrl: "/projets/sudoku"
|
||||
}
|
||||
,
|
||||
{
|
||||
title: "Clock",
|
||||
description: "Affiche l’heure en temps réel, analogique ou numérique, avec personnalisation du thème.",
|
||||
image: "/placeholder-clock.webp",
|
||||
url: "https://clock.arthurp.fr",
|
||||
infoUrl: "/projets/clock"
|
||||
}
|
||||
,
|
||||
{
|
||||
title: "FormCraft",
|
||||
description: "Générez des formulaires sans inscription, une alternative à Google Forms. Simple, rapide et privé.",
|
||||
image: "/placeholder-formcraft.webp",
|
||||
url: "https://form.arthurp.fr/",
|
||||
infoUrl: "/projets/formcraft"
|
||||
},
|
||||
{
|
||||
title: "FocusPomodoro",
|
||||
description: "Boostez votre productivité avec la technique Pomodoro : sessions de focus, pauses, statistiques et gestion des tâches.",
|
||||
image: "/placeholder-pomodoro.webp",
|
||||
url: "https://pomodoro.arthurp.fr",
|
||||
infoUrl: "/projets/pomodoro"
|
||||
},
|
||||
{
|
||||
title: "Visio",
|
||||
description: "Créez une salle de visioconférence en un clic et partagez le lien avec vos participants. Aucune inscription requise.",
|
||||
image: "/placeholder-visio.webp",
|
||||
url: "https://visio.arthurp.fr",
|
||||
infoUrl: "/projets/visio"
|
||||
},
|
||||
{
|
||||
title: "Les Aventures de Doudou",
|
||||
description: "Un album photo interactif racontant les merveilleuses aventures de Doudou, avec vue chronologique ou par albums.",
|
||||
image: "/placeholder-doudou.webp",
|
||||
url: "https://doudou.arthurp.fr",
|
||||
infoUrl: "/projets/doudou"
|
||||
},
|
||||
{
|
||||
title: "Portfolio ArthurP",
|
||||
description: "Le site personnel d'Arthur : développeur passionné par l'auto-hébergement, navigateur de haut niveau en voile.",
|
||||
image: "/placeholder-portfolio.webp",
|
||||
url: "https://portfolio.arthurp.fr",
|
||||
infoUrl: "/projets/portfolio"
|
||||
},
|
||||
{
|
||||
title: "Moon Phases",
|
||||
description: "Explorez les phases lunaires en temps réel, consultez le calendrier, la prochaine pleine lune, un simulateur et un quiz.",
|
||||
image: "/placeholder-moon.webp",
|
||||
url: "https://moon.arthurp.fr",
|
||||
infoUrl: "/projets/moon"
|
||||
},
|
||||
{
|
||||
title: "Calculatrice",
|
||||
description: "Calculatrice en ligne gratuite avec modes simple et scientifique, historique des calculs et thème sombre/clair.",
|
||||
image: "/placeholder-calculatrice.webp",
|
||||
url: "https://calculatrice.arthurp.fr",
|
||||
infoUrl: "/projets/calculatrice"
|
||||
},
|
||||
{
|
||||
title: "Chrono",
|
||||
description: "Chronomètre précis à la milliseconde et minuteur flexible avec enregistrement des tours et raccourcis clavier.",
|
||||
image: "/placeholder-chrono.webp",
|
||||
url: "https://chrono.arthurp.fr",
|
||||
infoUrl: "/projets/chrono"
|
||||
},
|
||||
{
|
||||
title: "BlocNote",
|
||||
description: "Application de prise de notes en ligne : créez, recherchez et organisez vos notes avec mode sombre, sans inscription.",
|
||||
image: "/placeholder-blocnote.webp",
|
||||
url: "https://blocnote.arthurp.fr",
|
||||
infoUrl: "/projets/blocnote"
|
||||
},
|
||||
{
|
||||
title: "ImprimerSudoku",
|
||||
description: "Générez 6 grilles de sudoku imprimables sur feuille A4 avec solutions. 4 niveaux de difficulté, en un clic.",
|
||||
image: "/placeholder-imprimersudoku.webp",
|
||||
url: "https://imprimersudoku.arthurp.fr",
|
||||
infoUrl: "/projets/imprimersudoku"
|
||||
},
|
||||
];
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
|
||||
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/next.svg"
|
||||
alt="Next.js logo"
|
||||
width={100}
|
||||
height={20}
|
||||
priority
|
||||
/>
|
||||
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
|
||||
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
|
||||
To get started, edit the page.tsx file.
|
||||
</h1>
|
||||
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
|
||||
Looking for a starting point or more instructions? Head over to{" "}
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
>
|
||||
Templates
|
||||
</a>{" "}
|
||||
or the{" "}
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
className="font-medium text-zinc-950 dark:text-zinc-50"
|
||||
>
|
||||
Learning
|
||||
</a>{" "}
|
||||
center.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<Image
|
||||
className="dark:invert"
|
||||
src="/vercel.svg"
|
||||
alt="Vercel logomark"
|
||||
width={16}
|
||||
height={16}
|
||||
/>
|
||||
Deploy Now
|
||||
</a>
|
||||
<a
|
||||
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Documentation
|
||||
</a>
|
||||
<div className="min-h-screen bg-white font-sans text-zinc-900">
|
||||
<main className="mx-auto flex max-w-5xl flex-col items-center px-4 py-16">
|
||||
<h1 className="mb-2 text-4xl font-bold tracking-tight">Le hub d'ArthurP</h1>
|
||||
<p className="mb-10 max-w-2xl text-center text-lg text-zinc-600">
|
||||
Découvre tous mes outils, projets et ressources en ligne : bots Discord, générateurs, QCM, linktree et plus encore. Un point d’accès unique pour tout ce que je développe et partage.
|
||||
</p>
|
||||
<div className="grid w-full grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{projects.map((project) => (
|
||||
<div key={project.title} className="flex flex-col rounded-2xl border border-zinc-200 bg-zinc-50 shadow-sm hover:shadow-lg transition-shadow overflow-hidden">
|
||||
<Image
|
||||
src={project.image}
|
||||
alt={project.title}
|
||||
width={600}
|
||||
height={300}
|
||||
className="h-40 w-full object-cover bg-zinc-200"
|
||||
/>
|
||||
<div className="flex flex-1 flex-col p-5">
|
||||
<h2 className="mb-2 text-xl font-semibold">{project.title}</h2>
|
||||
<p className="mb-4 text-zinc-600 flex-1">{project.description}</p>
|
||||
<div className="mt-auto flex gap-2">
|
||||
<a
|
||||
href={project.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="rounded-lg bg-[#e2d6c2] px-4 py-2 text-[#5a4a2e] font-medium hover:bg-[#d6bfa3] transition-colors border border-[#d6bfa3]"
|
||||
>
|
||||
Accéder à l’outil
|
||||
</a>
|
||||
<Link
|
||||
href={project.infoUrl}
|
||||
className="rounded-lg border border-[#e2d6c2] px-4 py-2 text-[#5a4a2e] font-medium hover:bg-[#f3ede6] transition-colors"
|
||||
>
|
||||
Plus d’info
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "BlocNote – Prise de notes en ligne | ArthurP.fr",
|
||||
description: "Application de prise de notes en ligne simple et rapide : créez, recherchez et organisez vos notes avec mode sombre, sans inscription.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/blocnote" },
|
||||
openGraph: {
|
||||
title: "BlocNote – Prise de notes en ligne",
|
||||
description: "Prenez des notes rapidement en ligne, avec recherche, tri par date et mode sombre. Simple et sans inscription.",
|
||||
url: "https://arthurp.fr/projets/blocnote",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function BlocNoteInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="BlocNote"
|
||||
description="Application de prise de notes en ligne simple et rapide : créez, recherchez et organisez vos notes avec mode sombre, sans inscription."
|
||||
longDescription="BlocNote est une application de prise de notes très légère et efficace. Son interface à deux panneaux affiche la liste de vos notes sur la gauche et l'éditeur sur la droite. Créez une nouvelle note en un clic (ou avec Ctrl+N), rédigez votre contenu, et retrouvez-la facilement grâce à la barre de recherche. Les notes peuvent être triées par date de création ou modification. Le thème sombre par défaut est reposant pour un usage prolongé, et il existe un thème clair. Toutes les notes sont stockées localement dans votre navigateur."
|
||||
features={[
|
||||
"Création rapide de notes (bouton + ou Ctrl+N)",
|
||||
"Éditeur de texte intégré",
|
||||
"Recherche dans les notes en temps réel",
|
||||
"Tri des notes par date",
|
||||
"Mode sombre et mode clair",
|
||||
"Stockage local dans le navigateur (pas de compte)",
|
||||
"Interface double panneau liste / éditeur",
|
||||
]}
|
||||
useCases={[
|
||||
"Prendre des notes rapides pendant le travail",
|
||||
"Faire des listes de tâches ou de courses",
|
||||
"Garder des mémos et informations temporaires",
|
||||
"Alternative légère à des applications de notes complexes",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS", "localStorage"]}
|
||||
faq={[
|
||||
{ question: "Les notes sont-elles sauvegardées automatiquement ?", answer: "Oui, les notes sont sauvegardées automatiquement dans le localStorage de votre navigateur à chaque modification." },
|
||||
{ question: "Les notes sont-elles synchronisées entre appareils ?", answer: "Non, les notes sont stockées localement sur votre appareil. Pour les retrouver sur un autre appareil, il faudrait les exporter manuellement." },
|
||||
{ question: "Y a-t-il une limite au nombre de notes ?", answer: "La limite est celle du localStorage de votre navigateur (généralement 5-10 Mo), ce qui permet de stocker un très grand nombre de notes texte." },
|
||||
]}
|
||||
images={["/placeholder-blocnote.webp", "/placeholder-blocnote-2.webp", "/placeholder-blocnote-3.webp"]}
|
||||
url="https://blocnote.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Calculatrice – Calculatrice en ligne simple et scientifique | ArthurP.fr",
|
||||
description: "Calculatrice en ligne gratuite avec mode simple et mode scientifique, historique des calculs et thème sombre/clair.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/calculatrice" },
|
||||
openGraph: {
|
||||
title: "Calculatrice – Calculatrice en ligne simple et scientifique",
|
||||
description: "Effectuez vos calculs en ligne avec une calculatrice simple ou scientifique, avec historique et mode sombre.",
|
||||
url: "https://arthurp.fr/projets/calculatrice",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function CalculatriceInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="Calculatrice"
|
||||
description="Calculatrice en ligne gratuite avec modes simple et scientifique, historique des calculs et thème sombre ou clair."
|
||||
longDescription="La calculatrice en ligne d'ArthurP propose deux modes complémentaires : un mode simple pour les opérations courantes (addition, soustraction, multiplication, division) et un mode scientifique pour les calculs avancés (fonctions trigonométriques, exponentielles, logarithmes, etc.). Un historique des calculs est accessible à tout moment, et l'interface peut être basculée entre mode clair et mode sombre selon les préférences. L'outil fonctionne entièrement dans le navigateur, sans installation."
|
||||
features={[
|
||||
"Mode simple : opérations arithmétiques courantes",
|
||||
"Mode scientifique : fonctions avancées (trig, log, exp...)",
|
||||
"Historique des calculs consultable",
|
||||
"Thème sombre et thème clair",
|
||||
"Support des parenthèses pour les expressions complexes",
|
||||
"Aucune installation ni inscription requise",
|
||||
]}
|
||||
useCases={[
|
||||
"Effectuer des calculs rapides depuis le navigateur",
|
||||
"Résoudre des expressions mathématiques complexes",
|
||||
"Utiliser les fonctions scientifiques sans installer de logiciel",
|
||||
"Consulter l'historique des calculs précédents",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Quelle est la différence entre mode simple et scientifique ?", answer: "Le mode simple propose les 4 opérations de base plus les parenthèses. Le mode scientifique ajoute sin, cos, tan, log, exp, racine carrée et d'autres fonctions mathématiques avancées." },
|
||||
{ question: "L'historique est-il sauvegardé ?", answer: "L'historique est disponible pendant la session. Pour une sauvegarde permanente, il peut être stocké localement selon la version de l'application." },
|
||||
{ question: "La calculatrice fonctionne-t-elle sans Internet ?", answer: "Oui, une fois la page chargée, la calculatrice fonctionne entièrement hors ligne." },
|
||||
]}
|
||||
images={["/placeholder-calculatrice.webp", "/placeholder-calculatrice-2.webp", "/placeholder-calculatrice-3.webp"]}
|
||||
url="https://calculatrice.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Chrono – Chronomètre et minuteur en ligne | ArthurP.fr",
|
||||
description: "Chronomètre en ligne avec précision à la milliseconde, enregistrement des tours (laps), minuteur avec préréglages rapides et raccourcis clavier.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/chrono" },
|
||||
openGraph: {
|
||||
title: "Chrono – Chronomètre et minuteur en ligne",
|
||||
description: "Chronomètre professionnel et minuteur flexible, précis à la milliseconde, avec raccourcis clavier et préréglages.",
|
||||
url: "https://arthurp.fr/projets/chrono",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function ChronoInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="Chrono"
|
||||
description="Chronomètre professionnel et minuteur flexible en ligne, précis à la milliseconde, avec enregistrement des tours et raccourcis clavier."
|
||||
longDescription="Chrono est un outil de mesure du temps double en un : un chronomètre haute précision (à la milliseconde) pour mesurer des durées, et un minuteur configurable pour définir des comptes à rebours. Le chronomètre permet d'enregistrer des tours (laps) pour suivre des temps intermédiaires. Le minuteur propose des préréglages rapides (1, 3, 5, 10, 15, 30 minutes) ainsi qu'un réglage manuel. Des raccourcis clavier permettent une utilisation sans souris. L'interface, sobre sur fond sombre, est optimale pour un usage prolongé."
|
||||
features={[
|
||||
"Chronomètre précis à la milliseconde (heures:minutes:secondes.millisecondes)",
|
||||
"Enregistrement des tours (laps) avec temps intermédiaires",
|
||||
"Minuteur avec préréglages rapides (1, 3, 5, 10, 15, 30 min)",
|
||||
"Réglage manuel des heures, minutes et secondes du minuteur",
|
||||
"Raccourcis clavier : Espace (start/pause), L (tour), R (reset), C (copier)",
|
||||
"Mode plein écran pour affichage large",
|
||||
"Thème clair/sombre",
|
||||
"Fonctionne sans inscription",
|
||||
]}
|
||||
useCases={[
|
||||
"Chronométrer des sessions de sport ou d'entraînement",
|
||||
"Mesurer des temps de cuisson ou de préparation",
|
||||
"Minuter des présentations ou des prises de parole",
|
||||
"Enregistrer des temps de passage (laps) en compétition",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Quelle est la précision du chronomètre ?", answer: "Le chronomètre est précis à la milliseconde, affichant heures, minutes, secondes et millisecondes en temps réel." },
|
||||
{ question: "Comment enregistrer un tour ?", answer: "Appuyez sur la touche L ou sur le bouton dédié pendant que le chronomètre tourne pour enregistrer un temps intermédiaire (lap)." },
|
||||
{ question: "Le minuteur peut-il sonner à la fin ?", answer: "Oui, le minuteur émet une alerte sonore ou visuelle à la fin du décompte selon la configuration du navigateur." },
|
||||
]}
|
||||
images={["/placeholder-chrono.webp", "/placeholder-chrono-2.webp", "/placeholder-chrono-3.webp"]}
|
||||
url="https://chrono.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Clock – Horloge en ligne personnalisable | ArthurP.fr",
|
||||
description: "Affichez l'heure en temps réel : horloge analogique ou numérique, personnalisation du thème (clair/sombre/couleurs).",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/clock" },
|
||||
openGraph: {
|
||||
title: "Clock – Horloge en ligne personnalisable",
|
||||
description: "Affichez l'heure en temps réel avec une horloge analogique ou numérique personnalisable.",
|
||||
url: "https://arthurp.fr/projets/clock",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function ClockInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="Clock"
|
||||
description="Affichez l'heure en temps réel : horloge analogique ou numérique, personnalisation du thème (clair/sombre/couleurs)."
|
||||
longDescription="Clock est une horloge en ligne élégante et personnalisable. Choisissez entre un affichage analogique classique ou un mode numérique moderne, et adaptez le thème à vos préférences : mode clair, mode sombre ou couleurs personnalisées. L'horloge se met à jour en temps réel avec une précision à la seconde. Idéale pour l'afficher en plein écran sur un second monitor, la garder en onglet de fond ou simplement vérifier l'heure rapidement."
|
||||
features={[
|
||||
"Affichage en temps réel avec précision à la seconde",
|
||||
"Mode analogique (aiguilles) et numérique au choix",
|
||||
"Thèmes personnalisables : clair, sombre et couleurs",
|
||||
"Mode plein écran pour affichage sur moniteur",
|
||||
"Design minimaliste et responsive",
|
||||
"Aucune installation ni inscription requise",
|
||||
]}
|
||||
useCases={[
|
||||
"Afficher l'heure sur un second écran pendant le travail",
|
||||
"Utiliser comme horloge de bureau en plein écran",
|
||||
"Vérifier l'heure rapidement depuis un onglet navigateur",
|
||||
"Personnaliser l'affichage selon l'ambiance de la pièce",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS", "Canvas API"]}
|
||||
faq={[
|
||||
{ question: "L'horloge utilise-t-elle l'heure locale ?", answer: "Oui, l'horloge affiche automatiquement l'heure de votre fuseau horaire détecté par votre navigateur." },
|
||||
{ question: "Peut-on utiliser Clock en plein écran ?", answer: "Oui, un bouton dédié permet de passer en plein écran pour un affichage optimal sur tout type de moniteur." },
|
||||
{ question: "L'horloge fonctionne-t-elle hors ligne ?", answer: "Oui, une fois la page chargée, l'horloge fonctionne sans connexion internet puisqu'elle utilise l'heure système." },
|
||||
]}
|
||||
images={["/placeholder-clock.webp", "/placeholder-clock-2.webp", "/placeholder-clock-3.webp"]}
|
||||
url="https://clock.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Les Aventures de Doudou – Album photo interactif | ArthurP.fr",
|
||||
description: "Découvrez les aventures de Doudou, un album de photos et d'histoires racontant les péripéties d'un doudou bien-aimé.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/doudou" },
|
||||
openGraph: {
|
||||
title: "Les Aventures de Doudou – Album photo interactif",
|
||||
description: "Un album photo interactif racontant les merveilleuses aventures de Doudou.",
|
||||
url: "https://arthurp.fr/projets/doudou",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function DoudouInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="Les Aventures de Doudou"
|
||||
description="Un album photo interactif racontant les merveilleuses aventures de Doudou, avec une vue chronologique ou par albums."
|
||||
longDescription="Les Aventures de Doudou est un site personnel et affectif qui retrace les aventures d'un doudou bien-aimé. Chaque aventure est illustrée par des photos et accompagnée d'une courte histoire. Le site propose deux modes de navigation : une vue chronologique qui présente toutes les aventures dans l'ordre du temps, et une vue par albums regroupant les aventures par thème. L'interface propose trois thèmes visuels : Rose, Clair et Sombre."
|
||||
features={[
|
||||
"Vue chronologique de toutes les aventures",
|
||||
"Navigation par albums thématiques",
|
||||
"Galerie de photos pour chaque aventure",
|
||||
"Trois thèmes : Rose, Clair et Sombre",
|
||||
"Interface responsive et ludique",
|
||||
"Mode administrateur pour gérer le contenu",
|
||||
]}
|
||||
useCases={[
|
||||
"Partager des souvenirs sous forme d'album interactif",
|
||||
"Créer un journal de bord illustré",
|
||||
"Offrir un album numérique personnalisé",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Qui est Doudou ?", answer: "Doudou est un doudou (jouet en peluche) dont les aventures sont illustrées et racontées sur ce site." },
|
||||
{ question: "Puis-je ajouter mes propres aventures ?", answer: "Le site dispose d'un mode administrateur permettant d'ajouter et gérer les aventures." },
|
||||
{ question: "Le site est-il adapté aux mobiles ?", answer: "Oui, le site est entièrement responsive et s'adapte aux smartphones, tablettes et ordinateurs." },
|
||||
]}
|
||||
images={["/placeholder-doudou.webp", "/placeholder-doudou-2.webp", "/placeholder-doudou-3.webp"]}
|
||||
url="https://doudou.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "FormCraft – Créez des formulaires sans inscription | ArthurP.fr",
|
||||
description: "Générez des formulaires en ligne sans inscription ni collecte de données personnelles. Alternative simple et rapide à Google Forms.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/formcraft" },
|
||||
openGraph: {
|
||||
title: "FormCraft – Créez des formulaires sans inscription",
|
||||
description: "Générez des formulaires en ligne sans inscription. Alternative simple à Google Forms.",
|
||||
url: "https://arthurp.fr/projets/formcraft",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function FormCraftInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="FormCraft"
|
||||
description="Générez des formulaires en ligne sans inscription ni collecte de données personnelles. Alternative simple et rapide à Google Forms."
|
||||
longDescription="FormCraft est un outil de création de formulaires en ligne qui met la simplicité et la confidentialité au premier plan. Aucune inscription n'est requise, aucune donnée personnelle n'est collectée. Créez votre formulaire en quelques clics, partagez-le via un lien unique et recevez les réponses directement. Idéal pour les enquêtes rapides, les sondages, les inscriptions ou les retours d'expérience, FormCraft se positionne comme une alternative légère et respectueuse de la vie privée face à Google Forms."
|
||||
features={[
|
||||
"Création de formulaires sans inscription ni compte",
|
||||
"Aucune collecte de données personnelles",
|
||||
"Partage via un lien unique généré automatiquement",
|
||||
"Plusieurs types de champs : texte, choix multiple, cases à cocher…",
|
||||
"Consultation des réponses en temps réel",
|
||||
"Interface intuitive et responsive",
|
||||
"Alternative respectueuse de la vie privée à Google Forms",
|
||||
]}
|
||||
useCases={[
|
||||
"Créer un sondage rapide pour sa communauté",
|
||||
"Organiser des inscriptions à un événement",
|
||||
"Collecter des retours d'expérience de manière anonyme",
|
||||
"Réaliser une enquête sans dépendre d'un compte Google",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS", "PostgreSQL"]}
|
||||
faq={[
|
||||
{ question: "FormCraft est-il vraiment sans inscription ?", answer: "Oui, vous pouvez créer et partager un formulaire sans jamais créer de compte. Vous recevez un lien d'administration pour gérer votre formulaire." },
|
||||
{ question: "Les réponses sont-elles stockées de manière sécurisée ?", answer: "Oui, les réponses sont stockées de manière sécurisée et ne sont accessibles que via votre lien d'administration." },
|
||||
{ question: "Peut-on exporter les réponses ?", answer: "Oui, les réponses peuvent être exportées pour une analyse plus approfondie." },
|
||||
{ question: "Combien de réponses peut-on recevoir ?", answer: "Il n'y a pas de limite sur le nombre de réponses que vous pouvez recevoir pour un formulaire." },
|
||||
]}
|
||||
images={["/placeholder-formcraft.webp", "/placeholder-formcraft-2.webp", "/placeholder-formcraft-3.webp"]}
|
||||
url="https://form.arthurp.fr/"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "ImprimerSudoku – Générateur de sudoku imprimable | ArthurP.fr",
|
||||
description: "Générez 6 grilles de sudoku sur une feuille A4 avec leurs solutions. Choisissez votre niveau de difficulté et imprimez en un clic.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/imprimersudoku" },
|
||||
openGraph: {
|
||||
title: "ImprimerSudoku – Générateur de sudoku imprimable",
|
||||
description: "Imprimez 6 sudokus par page avec solutions. 4 niveaux de difficulté, génération instantanée.",
|
||||
url: "https://arthurp.fr/projets/imprimersudoku",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function ImprimerSudokuInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="ImprimerSudoku"
|
||||
description="Générez 6 grilles de sudoku sur une feuille A4 avec leurs solutions. Choisissez votre niveau et imprimez en un clic."
|
||||
longDescription="ImprimerSudoku est l'outil idéal pour imprimer des grilles de sudoku à la maison ou en classe. En choisissant votre niveau de difficulté parmi quatre options (Facile, Moyen, Difficile, Expert), l'application génère instantanément 6 grilles uniques disposées sur une feuille A4, avec leurs solutions complètes au bas de la page. Un simple clic sur 'Imprimer' lance l'impression directement depuis le navigateur. Parfait pour les enfants, les adultes en quête de divertissement ou les enseignants."
|
||||
features={[
|
||||
"6 grilles de sudoku générées automatiquement par feuille A4",
|
||||
"4 niveaux de difficulté : Facile, Moyen, Difficile, Expert",
|
||||
"Solutions incluses sur la page d'impression",
|
||||
"Impression en un clic directement depuis le navigateur",
|
||||
"Grilles uniques à chaque génération",
|
||||
"Gratuit et sans inscription",
|
||||
]}
|
||||
useCases={[
|
||||
"Imprimer des sudokus pour les enfants ou la famille",
|
||||
"Préparer des exercices pour la classe",
|
||||
"Avoir des grilles disponibles hors ligne (papier)",
|
||||
"Varier les niveaux de difficulté selon son humeur",
|
||||
]}
|
||||
techStack={["React", "TypeScript", "Tailwind CSS", "Algorithme de génération de sudoku"]}
|
||||
faq={[
|
||||
{ question: "Les grilles sont-elles toujours différentes ?", answer: "Oui, chaque clic sur un niveau génère 6 nouvelles grilles uniques avec un algorithme de génération aléatoire." },
|
||||
{ question: "Les solutions sont-elles toujours incluses ?", answer: "Oui, les solutions des 6 grilles sont incluses dans la zone d'impression en bas de la feuille A4." },
|
||||
{ question: "Puis-je imprimer sans les solutions ?", answer: "Actuellement, les solutions sont automatiquement incluses. Vous pouvez les masquer en les repliant si vous imprimez en recto-verso." },
|
||||
]}
|
||||
images={["/placeholder-imprimersudoku.webp", "/placeholder-imprimersudoku-2.webp", "/placeholder-imprimersudoku-3.webp"]}
|
||||
url="https://imprimersudoku.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "LazyBot – Bot Discord configurable | ArthurP.fr",
|
||||
description: "Un bot Discord configurable avec dashboard web, inspiré de Draftbot. Gérez votre serveur, personnalisez les fonctionnalités et profitez d'une expérience unique.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/lazybot" },
|
||||
openGraph: {
|
||||
title: "LazyBot – Bot Discord configurable",
|
||||
description: "Un bot Discord configurable avec dashboard web, inspiré de Draftbot.",
|
||||
url: "https://arthurp.fr/projets/lazybot",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function LazyBotInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="LazyBot"
|
||||
description="Un bot Discord configurable avec dashboard web, inspiré de Draftbot. Gérez votre serveur, personnalisez les fonctionnalités et profitez d'une expérience unique."
|
||||
longDescription="LazyBot est un bot Discord complet pensé pour simplifier la gestion de votre serveur. Grâce à son dashboard web intuitif, vous pouvez configurer chaque fonctionnalité sans toucher à une seule ligne de commande. Modération automatique, messages de bienvenue, rôles réactifs, logs détaillés… tout est paramétrable en quelques clics. Inspiré de bots populaires comme Draftbot, LazyBot se distingue par sa simplicité d'utilisation et sa flexibilité."
|
||||
features={[
|
||||
"Dashboard web complet pour configurer le bot sans commandes",
|
||||
"Système de modération automatique (anti-spam, anti-raid, filtres de mots)",
|
||||
"Messages de bienvenue et d'au revoir personnalisables",
|
||||
"Attribution automatique de rôles via réactions",
|
||||
"Logs détaillés de toutes les actions du serveur",
|
||||
"Commandes personnalisées créées depuis le dashboard",
|
||||
"Système de niveaux et d'expérience pour les membres",
|
||||
]}
|
||||
useCases={[
|
||||
"Gérer un serveur communautaire avec des centaines de membres",
|
||||
"Automatiser la modération pour gagner du temps",
|
||||
"Personnaliser l'accueil des nouveaux membres",
|
||||
"Suivre l'activité du serveur avec des logs centralisés",
|
||||
]}
|
||||
techStack={["Node.js", "Discord.js", "React", "Next.js", "MongoDB", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "LazyBot est-il gratuit ?", answer: "Oui, LazyBot est entièrement gratuit. Toutes les fonctionnalités sont accessibles sans abonnement ni paiement." },
|
||||
{ question: "Comment ajouter LazyBot à mon serveur ?", answer: "Il suffit de se rendre sur lazybot.arthurp.fr et de cliquer sur le bouton d'invitation. Vous serez redirigé vers Discord pour autoriser le bot sur votre serveur." },
|
||||
{ question: "Peut-on configurer le bot sans connaissances techniques ?", answer: "Absolument. Le dashboard web est conçu pour être accessible à tous, avec une interface visuelle intuitive." },
|
||||
]}
|
||||
images={["/placeholder-lazybot.webp", "/placeholder-lazybot-2.webp", "/placeholder-lazybot-3.webp"]}
|
||||
url="https://lazybot.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Learn – Réponses claires à vos questions | ArthurP.fr",
|
||||
description: "Des réponses claires à des questions populaires sur de nombreux sujets. Idéal pour apprendre rapidement et efficacement.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/learn" },
|
||||
openGraph: {
|
||||
title: "Learn – Réponses claires à vos questions",
|
||||
description: "Des réponses claires à des questions populaires sur de nombreux sujets.",
|
||||
url: "https://arthurp.fr/projets/learn",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function LearnInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="Learn"
|
||||
description="Des réponses claires à des questions populaires sur de nombreux sujets. Idéal pour apprendre rapidement et efficacement."
|
||||
longDescription="Learn est une plateforme éducative qui fournit des réponses claires, concises et bien structurées à des questions fréquemment posées sur de nombreux sujets. Que ce soit en sciences, technologie, culture générale ou vie quotidienne, chaque réponse est rédigée pour être compréhensible par tous. L'objectif est de permettre à chacun d'apprendre rapidement sans se perdre dans des articles trop longs."
|
||||
features={[
|
||||
"Réponses claires et concises à des questions populaires",
|
||||
"Couverture de nombreux sujets (sciences, tech, culture générale…)",
|
||||
"Contenu structuré et facile à lire",
|
||||
"Navigation rapide entre les questions",
|
||||
"Optimisé pour la lecture sur mobile",
|
||||
"Nouveau contenu ajouté régulièrement",
|
||||
]}
|
||||
useCases={[
|
||||
"Trouver rapidement la réponse à une question de culture générale",
|
||||
"Compléter ses connaissances sur un sujet précis",
|
||||
"Utiliser comme support de révision rapide",
|
||||
"Satisfaire sa curiosité au quotidien",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS", "MDX"]}
|
||||
faq={[
|
||||
{ question: "Qui rédige les réponses ?", answer: "Les réponses sont rédigées par ArthurP avec un souci de clarté et de précision, en s'appuyant sur des sources fiables." },
|
||||
{ question: "Peut-on suggérer une question ?", answer: "Oui, les suggestions sont les bienvenues ! Vous pouvez contacter ArthurP via ses réseaux pour proposer un sujet." },
|
||||
{ question: "Le contenu est-il gratuit ?", answer: "Oui, tout le contenu de Learn est entièrement gratuit et accessible sans inscription." },
|
||||
]}
|
||||
images={["/placeholder-learn.webp", "/placeholder-learn-2.webp", "/placeholder-learn-3.webp"]}
|
||||
url="https://learn.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Linktree – Tous mes liens et réseaux | ArthurP.fr",
|
||||
description: "Tous mes réseaux et liens importants, centralisés pour ma communauté. Facile à partager et à mettre à jour.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/links" },
|
||||
openGraph: {
|
||||
title: "Linktree – Tous mes liens et réseaux",
|
||||
description: "Tous mes réseaux et liens importants, centralisés pour ma communauté.",
|
||||
url: "https://arthurp.fr/projets/links",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function LinksInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="Linktree"
|
||||
description="Tous mes réseaux et liens importants, centralisés pour ma communauté. Facile à partager et à mettre à jour."
|
||||
longDescription="Linktree par ArthurP regroupe tous les liens importants en une seule page. Réseaux sociaux, projets, outils et ressources : tout est centralisé et accessible depuis un lien unique. Parfait pour partager sa présence en ligne dans une bio Instagram, un profil Discord ou une signature email. La page est mise à jour en temps réel et s'adapte à tous les écrans."
|
||||
features={[
|
||||
"Tous les liens importants regroupés sur une seule page",
|
||||
"Design épuré et responsive (mobile, tablette, desktop)",
|
||||
"Mise à jour en temps réel sans rechargement",
|
||||
"Chargement ultra-rapide",
|
||||
"Lien unique facile à partager partout",
|
||||
]}
|
||||
useCases={[
|
||||
"Partager une page de liens dans sa bio Instagram ou TikTok",
|
||||
"Centraliser ses réseaux sociaux pour sa communauté Discord",
|
||||
"Ajouter un lien unique dans une signature email",
|
||||
"Présenter ses projets à un recruteur ou un collaborateur",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Puis-je créer mon propre Linktree avec cet outil ?", answer: "Cette page est le Linktree personnel d'ArthurP. Si vous souhaitez un outil similaire, vous pouvez vous inspirer du projet ou utiliser des services dédiés." },
|
||||
{ question: "Les liens sont-ils toujours à jour ?", answer: "Oui, la page est mise à jour régulièrement pour refléter les derniers projets et réseaux d'ArthurP." },
|
||||
]}
|
||||
images={["/placeholder-linktree.webp", "/placeholder-linktree-2.webp", "/placeholder-linktree-3.webp"]}
|
||||
url="https://links.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Moon Phases – Phases lunaires et calendrier | ArthurP.fr",
|
||||
description: "Explorez les phases de la lune en temps réel : phase actuelle, prochaine pleine lune, calendrier lunaire, simulateur et quiz.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/moon" },
|
||||
openGraph: {
|
||||
title: "Moon Phases – Phases lunaires et calendrier",
|
||||
description: "Suivez les phases de la lune, consultez le calendrier lunaire et découvrez les traditions liées aux pleines lunes.",
|
||||
url: "https://arthurp.fr/projets/moon",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function MoonInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="Moon Phases"
|
||||
description="Explorez les phases de la lune en temps réel : phase actuelle, prochaine pleine lune, calendrier lunaire, simulateur et quiz."
|
||||
longDescription="Moon Phases est une application complète dédiée aux phases lunaires. Elle affiche la phase actuelle de la lune (pourcentage d'illumination, nom de la phase) et indique la prochaine pleine lune avec son nom traditionnel. Le calendrier lunaire visualise toutes les phases du mois, tandis que le simulateur permet d'explorer les phases de n'importe quelle date. Des articles éducatifs et un quiz permettent d'approfondir ses connaissances sur les cycles lunaires et les traditions culturelles qui leur sont associées."
|
||||
features={[
|
||||
"Phase lunaire actuelle avec pourcentage d'illumination",
|
||||
"Prochaine pleine lune avec nom traditionnel et date",
|
||||
"Calendrier lunaire mensuel interactif",
|
||||
"Simulateur de phases pour n'importe quelle date",
|
||||
"Articles éducatifs sur les traditions lunaires",
|
||||
"Quiz sur les phases de la lune",
|
||||
"Disponible en français et en anglais",
|
||||
]}
|
||||
useCases={[
|
||||
"Suivre les phases de la lune au quotidien",
|
||||
"Planifier des événements en fonction du calendrier lunaire",
|
||||
"Apprendre les traditions culturelles liées aux pleines lunes",
|
||||
"Tester ses connaissances sur la lune avec le quiz",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Comment l'application calcule-t-elle les phases lunaires ?", answer: "L'application utilise des algorithmes astronomiques précis basés sur les cycles lunaires pour calculer la phase actuelle et les phases futures à partir de la date système." },
|
||||
{ question: "Qu'est-ce que le simulateur de phases ?", answer: "Le simulateur permet d'entrer n'importe quelle date passée ou future et d'afficher la phase lunaire correspondante." },
|
||||
{ question: "Qu'est-ce qu'une 'Worm Moon' ?", answer: "Les pleines lunes ont des noms traditionnels selon les cultures. 'Worm Moon' est le nom de la pleine lune de mars, signifiant que la nature reprend vie (vers de terre réapparaissent)." },
|
||||
]}
|
||||
images={["/placeholder-moon.webp", "/placeholder-moon-2.webp", "/placeholder-moon-3.webp"]}
|
||||
url="https://moon.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "FocusPomodoro – Timer Pomodoro en ligne | ArthurP.fr",
|
||||
description: "Boostez votre productivité avec la technique Pomodoro : sessions de focus de 25 minutes, pauses, statistiques quotidiennes et gestion de tâches.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/pomodoro" },
|
||||
openGraph: {
|
||||
title: "FocusPomodoro – Timer Pomodoro en ligne",
|
||||
description: "Restez concentré et productif grâce au timer Pomodoro avec statistiques et gestion des tâches.",
|
||||
url: "https://arthurp.fr/projets/pomodoro",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function PomodoroInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="FocusPomodoro"
|
||||
description="Boostez votre productivité avec la technique Pomodoro : sessions de focus, pauses et statistiques en temps réel."
|
||||
longDescription="FocusPomodoro est un timer Pomodoro complet et élégant. La technique Pomodoro consiste à travailler par sessions de 25 minutes (un 'pomodoro') entrecoupées de courtes pauses de 5 minutes, et d'une pause longue de 15 minutes après 4 sessions. L'application suit votre progression quotidienne, compte vos séries et vous permet de gérer una liste de tâches directement depuis l'interface. Son design épuré et ses statistiques détaillées en font un outil idéal pour améliorer sa concentration."
|
||||
features={[
|
||||
"Timer Pomodoro configurable (25min focus / 5min pause courte / 15min pause longue)",
|
||||
"Sessions 1/4 avec objectif journalier de 8 tomates",
|
||||
"Statistiques : sessions du jour, total, série actuelle et meilleure série",
|
||||
"Gestion de tâches intégrée avec priorités",
|
||||
"Thèmes clair et sombre",
|
||||
"Aucune inscription requise",
|
||||
]}
|
||||
useCases={[
|
||||
"Travailler en sessions concentrées sans distraction",
|
||||
"Suivre sa productivité au quotidien",
|
||||
"Gérer ses tâches et les associer à ses sessions",
|
||||
"Construire une habitude de travail régulière",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Qu'est-ce que la technique Pomodoro ?", answer: "La technique Pomodoro consiste à travailler par intervalles de 25 minutes (pomodoros) séparés par des courtes pauses. Après 4 pomodoros, on fait une pause plus longue. Cette méthode améliore la concentration et réduit la fatigue mentale." },
|
||||
{ question: "L'application sauvegarde-t-elle mes statistiques ?", answer: "Oui, vos statistiques et tâches sont sauvegardées localement dans votre navigateur grâce au localStorage." },
|
||||
{ question: "Puis-je personnaliser la durée des sessions ?", answer: "Oui, un menu de paramètres permet d'ajuster la durée des sessions de focus et des pauses selon vos préférences." },
|
||||
]}
|
||||
images={["/placeholder-pomodoro.webp", "/placeholder-pomodoro-2.webp", "/placeholder-pomodoro-3.webp"]}
|
||||
url="https://pomodoro.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Portfolio – Site personnel d'ArthurP | ArthurP.fr",
|
||||
description: "Découvrez le portfolio personnel d'Arthur : développeur passionné par l'auto-hébergement et l'infrastructure, et sportif de haut niveau en voile.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/portfolio" },
|
||||
openGraph: {
|
||||
title: "Portfolio – Site personnel d'ArthurP",
|
||||
description: "Portfolio de développeur et navigateur passionné par l'auto-hébergement, l'infrastructure et la voile.",
|
||||
url: "https://arthurp.fr/projets/portfolio",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function PortfolioInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="Portfolio ArthurP"
|
||||
description="Le site personnel d'Arthur : développeur passionné par l'auto-hébergement et navigateur de haut niveau en voile."
|
||||
longDescription="Le portfolio d'Arthur est son site vitrine personnel. Il présente son parcours de développeur passionné par l'auto-hébergement et l'infrastructure, mais aussi son côté sportif en tant que navigateur de haut niveau en voile. Le site regroupe ses projets techniques, ses installations homelab, sa galerie de photos de voile et de navigation, et un formulaire de contact. Le design moderne alterne entre mode clair et sombre, avec une présentation élégante sur fond sombre."
|
||||
features={[
|
||||
"Présentation personnelle et parcours de développeur",
|
||||
"Section Projets avec tous les projets récents",
|
||||
"Section Homelab sur l'infrastructure auto-hébergée",
|
||||
"Parcours en voile et compétitions nautiques",
|
||||
"Galerie de photos",
|
||||
"Formulaire de contact",
|
||||
"Mode clair/sombre",
|
||||
]}
|
||||
useCases={[
|
||||
"Découvrir les projets et compétences d'Arthur",
|
||||
"Prendre contact pour une collaboration",
|
||||
"Explorer son parcours en voile de compétition",
|
||||
"S'inspirer pour son propre portfolio de développeur",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Comment contacter Arthur ?", answer: "Le portfolio dispose d'un formulaire de contact dans la section 'Contact' en bas de page." },
|
||||
{ question: "Quels projets Arthur développe-t-il ?", answer: "Arthur développe des outils web (générateurs, bots Discord, apps de productivité), des solutions d'auto-hébergement et des projets d'infrastructure." },
|
||||
{ question: "Qu'est-ce que le Homelab ?", answer: "Le Homelab est l'infrastructure serveur personnelle d'Arthur, hébergée physiquement chez lui, sur laquelle il fait tourner ses propres services." },
|
||||
]}
|
||||
images={["/placeholder-portfolio.webp", "/placeholder-portfolio-2.webp", "/placeholder-portfolio-3.webp"]}
|
||||
url="https://portfolio.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "QCU Physique-Chimie – Révise avec 150+ QCU | ArthurP.fr",
|
||||
description: "Révise la physique-chimie avec plus de 150 QCU configurables et corrigés. Mode aléatoire, filtrage des questions, réponses détaillées.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/qcu" },
|
||||
openGraph: {
|
||||
title: "QCU Physique-Chimie – 150+ QCU corrigés",
|
||||
description: "Révise la physique-chimie avec plus de 150 QCU configurables et corrigés.",
|
||||
url: "https://arthurp.fr/projets/qcu",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function QCUInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="QCU Physique-Chimie"
|
||||
description="Révise la physique-chimie avec plus de 150 QCU configurables et corrigés. Mode aléatoire, filtrage des questions, réponses détaillées."
|
||||
longDescription="QCU Physique-Chimie est une plateforme de révision interactive dédiée aux élèves de lycée. Elle propose plus de 150 questions à choix unique (QCU) couvrant les principaux chapitres du programme de physique-chimie. Chaque question est accompagnée d'une correction détaillée pour comprendre la bonne réponse et progresser. L'outil permet de filtrer les questions par thème, de les mélanger aléatoirement et de suivre sa progression."
|
||||
features={[
|
||||
"Plus de 150 QCU couvrant le programme de physique-chimie",
|
||||
"Mode aléatoire pour varier les révisions à chaque session",
|
||||
"Filtrage par chapitre ou thématique (mécanique, chimie, optique…)",
|
||||
"Corrections détaillées avec explications pédagogiques",
|
||||
"Interface épurée et rapide, sans distraction",
|
||||
"Accessible sur mobile pour réviser partout",
|
||||
]}
|
||||
useCases={[
|
||||
"Réviser avant un contrôle ou un examen de physique-chimie",
|
||||
"S'entraîner régulièrement avec des questions variées",
|
||||
"Identifier ses lacunes grâce aux corrections détaillées",
|
||||
"Compléter ses cours avec un outil de pratique interactive",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Pour quel niveau sont les QCU ?", answer: "Les QCU sont principalement conçus pour les élèves de lycée (seconde, première, terminale) suivant le programme français de physique-chimie." },
|
||||
{ question: "Les questions sont-elles régulièrement mises à jour ?", answer: "Oui, de nouvelles questions sont ajoutées régulièrement pour enrichir la base et couvrir davantage de chapitres." },
|
||||
{ question: "Peut-on utiliser l'outil sur smartphone ?", answer: "Absolument, l'interface est responsive et s'adapte parfaitement aux écrans de téléphone et tablette." },
|
||||
]}
|
||||
images={["/placeholder-qcu.webp", "/placeholder-qcu-2.webp", "/placeholder-qcu-3.webp"]}
|
||||
url="https://qcu.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "QRCode – Générateur de QR codes personnalisés | ArthurP.fr",
|
||||
description: "Générateur de QR codes personnalisés, partageable par URL, sans téléchargement d'image. Configurez vos QR codes comme vous le souhaitez.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/qrcode" },
|
||||
openGraph: {
|
||||
title: "QRCode – Générateur de QR codes personnalisés",
|
||||
description: "Générateur de QR codes personnalisés, partageable par URL, sans téléchargement d'image.",
|
||||
url: "https://arthurp.fr/projets/qrcode",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function QRCodeInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="QRCode"
|
||||
description="Générateur de QR codes personnalisés, partageable par URL, sans téléchargement d'image. Configurez vos QR codes comme vous le souhaitez."
|
||||
longDescription="Ce générateur de QR codes en ligne vous permet de créer des codes QR personnalisés en quelques secondes. Contrairement aux outils classiques, chaque QR code généré est accessible via une URL unique que vous pouvez partager directement, sans avoir à télécharger d'image. Idéal pour les professionnels, les événements ou le quotidien, l'outil offre des options de personnalisation avancées : couleurs, taille, correction d'erreur et contenu embarqué."
|
||||
features={[
|
||||
"Génération instantanée de QR codes à partir de texte, URL ou données",
|
||||
"Partage via URL unique sans besoin de télécharger l'image",
|
||||
"Personnalisation des couleurs (premier plan et arrière-plan)",
|
||||
"Choix du niveau de correction d'erreur (L, M, Q, H)",
|
||||
"Téléchargement optionnel en PNG haute résolution",
|
||||
"Interface responsive utilisable sur mobile et desktop",
|
||||
]}
|
||||
useCases={[
|
||||
"Créer un QR code pour partager un lien Wi-Fi lors d'un événement",
|
||||
"Générer un QR code pour une carte de visite numérique",
|
||||
"Partager un lien rapidement sur un support imprimé (flyer, affiche)",
|
||||
"Intégrer un QR code dans une présentation ou un document",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Les QR codes générés expirent-ils ?", answer: "Non, les QR codes contiennent directement les données encodées. Tant que l'URL ou le texte cible existe, le QR code fonctionne indéfiniment." },
|
||||
{ question: "Peut-on personnaliser les couleurs du QR code ?", answer: "Oui, vous pouvez choisir la couleur du premier plan et de l'arrière-plan pour adapter le QR code à votre charte graphique." },
|
||||
{ question: "Faut-il créer un compte ?", answer: "Non, aucun compte ni inscription n'est nécessaire. L'outil est 100% gratuit et accessible immédiatement." },
|
||||
]}
|
||||
images={["/placeholder-qrcode.webp", "/placeholder-qrcode-2.webp", "/placeholder-qrcode-3.webp"]}
|
||||
url="https://qrcode.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "ReduceLink – Raccourcisseur d'URL gratuit | ArthurP.fr",
|
||||
description: "Transformez vos URLs longues en liens courts et mémorables. Gratuit, sans inscription, avec QR Code et statistiques.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/reducelink" },
|
||||
openGraph: {
|
||||
title: "ReduceLink – Raccourcisseur d'URL gratuit",
|
||||
description: "Transformez vos URLs longues en liens courts et mémorables. Gratuit, sans inscription.",
|
||||
url: "https://arthurp.fr/projets/reducelink",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="ReduceLink"
|
||||
description="Transformez vos URLs longues en liens courts et mémorables. Gratuit, sans inscription, avec QR Code et statistiques."
|
||||
longDescription="ReduceLink est un raccourcisseur d'URL gratuit et sans inscription. Collez n'importe quelle URL longue et obtenez instantanément un lien court, facile à mémoriser et à partager. Chaque lien raccourci est accompagné d'un QR code généré automatiquement et de statistiques de clics en temps réel. L'outil respecte votre vie privée : aucune donnée personnelle n'est collectée, et aucun compte n'est requis."
|
||||
features={[
|
||||
"Raccourcissement d'URL instantané en un clic",
|
||||
"Génération automatique d'un QR code pour chaque lien",
|
||||
"Statistiques de clics en temps réel (nombre, provenance)",
|
||||
"Aucune inscription ni collecte de données personnelles",
|
||||
"Liens courts personnalisables (alias)",
|
||||
"Interface simple et rapide, utilisable sur mobile",
|
||||
]}
|
||||
useCases={[
|
||||
"Raccourcir une URL longue pour la partager sur les réseaux sociaux",
|
||||
"Générer un QR code pour un lien à imprimer sur un support physique",
|
||||
"Suivre le nombre de clics sur un lien partagé",
|
||||
"Créer des liens mémorables pour des campagnes marketing",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS", "PostgreSQL"]}
|
||||
faq={[
|
||||
{ question: "Les liens raccourcis expirent-ils ?", answer: "Non, les liens restent actifs indéfiniment tant que le service est en ligne." },
|
||||
{ question: "Peut-on personnaliser le lien court ?", answer: "Oui, vous pouvez choisir un alias personnalisé pour votre lien court, sous réserve de disponibilité." },
|
||||
{ question: "ReduceLink est-il vraiment gratuit ?", answer: "Oui, le service est 100% gratuit, sans publicité intrusive et sans inscription requise." },
|
||||
]}
|
||||
images={["/placeholder-reducelink.webp", "/placeholder-reducelink-2.webp", "/placeholder-reducelink-3.webp"]}
|
||||
url="https://reducelink.arthurp.fr/"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ProjectInfoPage from '../../../components/ProjectInfoPage';
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Sudoku Generator & Solver – Générez et résolvez des sudokus | ArthurP.fr",
|
||||
description: "Générez des grilles de sudoku de plusieurs niveaux de difficulté, résolvez-les, vérifiez vos solutions et entraînez-vous.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/sudoku" },
|
||||
openGraph: {
|
||||
title: "Sudoku Generator & Solver",
|
||||
description: "Générez des grilles de sudoku de plusieurs niveaux de difficulté, résolvez-les et entraînez-vous.",
|
||||
url: "https://arthurp.fr/projets/sudoku",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function SudokuProjectPage() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="Sudoku Generator & Solver"
|
||||
description="Générez des grilles de sudoku de plusieurs niveaux de difficulté, résolvez-les, vérifiez vos solutions et entraînez-vous."
|
||||
longDescription="Sudoku Generator & Solver est un outil en ligne complet pour les amateurs de sudoku. Générez des grilles aléatoires avec plusieurs niveaux de difficulté (facile, moyen, difficile, expert), résolvez-les directement dans votre navigateur ou utilisez le solveur automatique pour découvrir la solution. L'outil permet également de vérifier vos réponses en temps réel et de vous entraîner à votre rythme. Aucune installation nécessaire, tout se passe dans le navigateur."
|
||||
features={[
|
||||
"Génération de grilles aléatoires avec 4 niveaux de difficulté",
|
||||
"Solveur automatique qui trouve la solution en quelques secondes",
|
||||
"Vérification en temps réel des erreurs pendant la résolution",
|
||||
"Interface intuitive avec navigation au clavier",
|
||||
"Minuteur intégré pour chronométrer vos performances",
|
||||
"Fonctionne hors ligne après le premier chargement",
|
||||
]}
|
||||
useCases={[
|
||||
"S'entraîner au sudoku avec des grilles de difficulté progressive",
|
||||
"Vérifier la solution d'un sudoku commencé sur papier",
|
||||
"Passer le temps avec un jeu de logique stimulant",
|
||||
"Apprendre les techniques de résolution de sudoku",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Combien de grilles différentes peut-on générer ?", answer: "Le générateur produit des grilles aléatoires à chaque fois, offrant une diversité quasi-infinie de puzzles." },
|
||||
{ question: "Le solveur fonctionne-t-il sur toutes les grilles ?", answer: "Oui, le solveur utilise un algorithme de backtracking capable de résoudre n'importe quelle grille de sudoku valide." },
|
||||
{ question: "Peut-on jouer sur téléphone ?", answer: "Oui, l'interface est entièrement responsive et optimisée pour les écrans tactiles." },
|
||||
]}
|
||||
images={["/placeholder-sudoku.webp", "/placeholder-sudoku-2.webp", "/placeholder-sudoku-3.webp"]}
|
||||
url="https://sudoku.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import ProjectInfoPage from "@/components/ProjectInfoPage";
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Visio – Visioconférence simple et gratuite | ArthurP.fr",
|
||||
description: "Créez une salle de visioconférence en un clic et partagez le lien avec vos participants. Aucune inscription requise.",
|
||||
alternates: { canonical: "https://arthurp.fr/projets/visio" },
|
||||
openGraph: {
|
||||
title: "Visio – Visioconférence simple et gratuite",
|
||||
description: "Lancez une visioconférence instantanément sans inscription. Partagez un lien et invitez vos participants.",
|
||||
url: "https://arthurp.fr/projets/visio",
|
||||
siteName: "ArthurP.fr",
|
||||
locale: "fr_FR",
|
||||
type: "website",
|
||||
},
|
||||
};
|
||||
|
||||
export default function VisioInfo() {
|
||||
return (
|
||||
<ProjectInfoPage
|
||||
title="Visio"
|
||||
description="Créez une salle de visioconférence en un clic et partagez le lien avec vos participants. Aucune inscription requise."
|
||||
longDescription="Visio est une application de visioconférence minimaliste et gratuite. En un seul clic sur 'Nouvelle visio', une salle est créée et un lien unique est généré. Il suffit de le partager avec vos participants pour qu'ils puissent rejoindre la conférence sans aucun compte ni installation. L'interface épurée se concentre sur l'essentiel : la connexion rapide entre personnes."
|
||||
features={[
|
||||
"Création de salle en un clic, sans inscription",
|
||||
"Rejoindre une visio existante via un code de salle",
|
||||
"Lien de partage unique généré automatiquement",
|
||||
"Interface minimaliste et intuitive",
|
||||
"Fonctionne directement dans le navigateur",
|
||||
"Gratuit et sans publicité",
|
||||
]}
|
||||
useCases={[
|
||||
"Réunions d'équipe spontanées",
|
||||
"Appels vidéo avec des amis ou collègues",
|
||||
"Sessions de travail collaboratif à distance",
|
||||
"Alternative gratuite à Zoom ou Google Meet pour des réunions ponctuelles",
|
||||
]}
|
||||
techStack={["Next.js", "React", "TypeScript", "WebRTC", "Tailwind CSS"]}
|
||||
faq={[
|
||||
{ question: "Faut-il créer un compte pour utiliser Visio ?", answer: "Non, aucune inscription n'est requise. Créez une salle et partagez le lien directement." },
|
||||
{ question: "Combien de participants peut accueillir une salle ?", answer: "Le nombre de participants dépend de la capacité réseau des utilisateurs, mais l'application est optimisée pour les petits groupes." },
|
||||
{ question: "Les visios sont-elles sécurisées ?", answer: "Oui, les communications utilisent WebRTC qui chiffre les flux audio/vidéo de bout en bout." },
|
||||
]}
|
||||
images={["/placeholder-visio.webp", "/placeholder-visio-2.webp", "/placeholder-visio-3.webp"]}
|
||||
url="https://visio.arthurp.fr"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
const baseUrl = "https://arthurp.fr";
|
||||
|
||||
const staticPages: MetadataRoute.Sitemap = [
|
||||
{
|
||||
url: baseUrl,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: "monthly",
|
||||
priority: 1,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/legal/mentions-legales`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: "yearly",
|
||||
priority: 0.3,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/legal/confidentialite`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: "yearly",
|
||||
priority: 0.3,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/legal/cgu`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: "yearly",
|
||||
priority: 0.3,
|
||||
},
|
||||
];
|
||||
|
||||
const projects = [
|
||||
"lazybot",
|
||||
"qrcode",
|
||||
"qcu",
|
||||
"reducelink",
|
||||
"links",
|
||||
"learn",
|
||||
"sudoku",
|
||||
"clock",
|
||||
"formcraft",
|
||||
"pomodoro",
|
||||
"visio",
|
||||
"doudou",
|
||||
"portfolio",
|
||||
"moon",
|
||||
"calculatrice",
|
||||
"chrono",
|
||||
"blocnote",
|
||||
"imprimersudoku",
|
||||
];
|
||||
|
||||
const projectPages: MetadataRoute.Sitemap = projects.map((slug) => ({
|
||||
url: `${baseUrl}/projets/${slug}`,
|
||||
lastModified: new Date(),
|
||||
changeFrequency: "monthly" as const,
|
||||
priority: 0.8,
|
||||
}));
|
||||
|
||||
return [...staticPages, ...projectPages];
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
interface JsonLdProps {
|
||||
data: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export default function JsonLd({ data }: JsonLdProps) {
|
||||
return (
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import JsonLd from "@/components/JsonLd";
|
||||
|
||||
interface FAQ {
|
||||
question: string;
|
||||
answer: string;
|
||||
}
|
||||
|
||||
interface ProjectInfoPageProps {
|
||||
title: string;
|
||||
description: string;
|
||||
longDescription?: string;
|
||||
features?: string[];
|
||||
useCases?: string[];
|
||||
techStack?: string[];
|
||||
faq?: FAQ[];
|
||||
images: string[];
|
||||
url: string;
|
||||
}
|
||||
|
||||
export default function ProjectInfoPage({
|
||||
title,
|
||||
description,
|
||||
longDescription,
|
||||
features,
|
||||
useCases,
|
||||
techStack,
|
||||
faq,
|
||||
images,
|
||||
url,
|
||||
}: ProjectInfoPageProps) {
|
||||
return (
|
||||
<div className="min-h-screen bg-white font-sans text-zinc-900">
|
||||
<JsonLd
|
||||
data={{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebPage",
|
||||
name: title,
|
||||
description,
|
||||
url,
|
||||
isPartOf: {
|
||||
"@type": "WebSite",
|
||||
name: "ArthurP.fr",
|
||||
url: "https://arthurp.fr",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<JsonLd
|
||||
data={{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "BreadcrumbList",
|
||||
itemListElement: [
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 1,
|
||||
name: "Accueil",
|
||||
item: "https://arthurp.fr",
|
||||
},
|
||||
{
|
||||
"@type": "ListItem",
|
||||
position: 2,
|
||||
name: title,
|
||||
item: url,
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
{faq && faq.length > 0 && (
|
||||
<JsonLd
|
||||
data={{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "FAQPage",
|
||||
mainEntity: faq.map((item) => ({
|
||||
"@type": "Question",
|
||||
name: item.question,
|
||||
acceptedAnswer: {
|
||||
"@type": "Answer",
|
||||
text: item.answer,
|
||||
},
|
||||
})),
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<main className="mx-auto max-w-3xl px-4 py-12">
|
||||
<Link href="/" className="text-blue-600 hover:underline mb-6 inline-block">← Retour au hub</Link>
|
||||
<h1 className="text-3xl font-bold mb-2">{title}</h1>
|
||||
<p className="mb-6 text-lg text-zinc-600">{description}</p>
|
||||
|
||||
<div className="mb-8 overflow-x-auto">
|
||||
<div className="flex gap-4">
|
||||
{images.map((img, idx) => (
|
||||
<div key={idx} className="min-w-75 h-48 relative rounded-xl overflow-hidden border border-zinc-200 bg-zinc-100">
|
||||
<Image src={img} alt={title + ' screenshot ' + (idx+1)} fill className="object-cover" />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-block rounded-lg bg-[#e2d6c2] px-6 py-3 text-[#5a4a2e] font-medium hover:bg-[#d6bfa3] border border-[#d6bfa3] transition-colors"
|
||||
>
|
||||
{"Acc\u00e9der \u00e0 l\u2019outil"}
|
||||
</a>
|
||||
|
||||
{longDescription && (
|
||||
<section className="mt-12">
|
||||
<h2 className="text-2xl font-semibold mb-3">{"\u00c0 propos de "}{title}</h2>
|
||||
<p className="text-zinc-700 leading-relaxed">{longDescription}</p>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{features && features.length > 0 && (
|
||||
<section className="mt-10">
|
||||
<h2 className="text-2xl font-semibold mb-4">{"Fonctionnalit\u00e9s principales"}</h2>
|
||||
<ul className="space-y-2">
|
||||
{features.map((feature, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2 text-zinc-700">
|
||||
<span className="mt-1 text-[#5a4a2e]">{"\u2713"}</span>
|
||||
<span>{feature}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{useCases && useCases.length > 0 && (
|
||||
<section className="mt-10">
|
||||
<h2 className="text-2xl font-semibold mb-4">{"Cas d\u2019utilisation"}</h2>
|
||||
<ul className="space-y-2">
|
||||
{useCases.map((useCase, idx) => (
|
||||
<li key={idx} className="flex items-start gap-2 text-zinc-700">
|
||||
<span className="mt-1">{"\u2192"}</span>
|
||||
<span>{useCase}</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{techStack && techStack.length > 0 && (
|
||||
<section className="mt-10">
|
||||
<h2 className="text-2xl font-semibold mb-4">{"Technologies utilis\u00e9es"}</h2>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{techStack.map((tech, idx) => (
|
||||
<span
|
||||
key={idx}
|
||||
className="rounded-full border border-zinc-200 bg-zinc-50 px-3 py-1 text-sm text-zinc-700"
|
||||
>
|
||||
{tech}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{faq && faq.length > 0 && (
|
||||
<section className="mt-10">
|
||||
<h2 className="text-2xl font-semibold mb-4">{"Questions fr\u00e9quentes"}</h2>
|
||||
<div className="space-y-4">
|
||||
{faq.map((item, idx) => (
|
||||
<details key={idx} className="group rounded-xl border border-zinc-200 bg-zinc-50 px-5 py-4">
|
||||
<summary className="cursor-pointer font-medium text-zinc-800 group-open:mb-2">
|
||||
{item.question}
|
||||
</summary>
|
||||
<p className="text-zinc-600 leading-relaxed">{item.answer}</p>
|
||||
</details>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./src/**/*.{js,ts,jsx,tsx}",
|
||||
"./src/app/**/*.{js,ts,jsx,tsx}",
|
||||
"./src/components/**/*.{js,ts,jsx,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
background: "var(--background)",
|
||||
foreground: "var(--foreground)",
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ["var(--font-geist-sans)", "Arial", "sans-serif"],
|
||||
mono: ["var(--font-geist-mono)", "monospace"],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||