mirror of
https://github.com/theoludwig/theoludwig.git
synced 2026-02-20 03:09:20 +01:00
chore: migrate from ESLint/Prettier to Oxc
This commit is contained in:
10
.github/workflows/chromatic.yml
vendored
10
.github/workflows/chromatic.yml
vendored
@@ -18,23 +18,25 @@ jobs:
|
|||||||
NEXT_TELEMETRY_DISABLED: "1"
|
NEXT_TELEMETRY_DISABLED: "1"
|
||||||
STORYBOOK_DISABLE_TELEMETRY: "1"
|
STORYBOOK_DISABLE_TELEMETRY: "1"
|
||||||
steps:
|
steps:
|
||||||
- uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v6.0.1
|
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6.0.2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- uses: "pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061" # v4.2.0
|
- uses: "pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061" # v4.2.0
|
||||||
|
|
||||||
|
- uses: "pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061" # v4.2.0
|
||||||
|
|
||||||
- name: "Setup Node.js"
|
- name: "Setup Node.js"
|
||||||
uses: "actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f" # v6.1.0
|
uses: "actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238" # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.1"
|
node-version: "24.13.1"
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
|
||||||
- name: "Install dependencies"
|
- name: "Install dependencies"
|
||||||
run: "pnpm install --frozen-lockfile"
|
run: "pnpm install --frozen-lockfile"
|
||||||
|
|
||||||
- name: "Run Chromatic"
|
- name: "Run Chromatic"
|
||||||
uses: "chromaui/action@ac86f2ff0a458ffbce7b40698abd44c0fa34d4b6" # latest
|
uses: "chromaui/action@07791f8243f4cb2698bf4d00426baf4b2d1cb7e0" # latest
|
||||||
with:
|
with:
|
||||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||||
workingDir: "apps/storybook"
|
workingDir: "apps/storybook"
|
||||||
|
|||||||
13
.github/workflows/ci.yml
vendored
13
.github/workflows/ci.yml
vendored
@@ -18,14 +18,14 @@ jobs:
|
|||||||
NEXT_TELEMETRY_DISABLED: "1"
|
NEXT_TELEMETRY_DISABLED: "1"
|
||||||
STORYBOOK_DISABLE_TELEMETRY: "1"
|
STORYBOOK_DISABLE_TELEMETRY: "1"
|
||||||
steps:
|
steps:
|
||||||
- uses: "actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8" # v6.0.1
|
- uses: "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd" # v6.0.2
|
||||||
|
|
||||||
- uses: "pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061" # v4.2.0
|
- uses: "pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061" # v4.2.0
|
||||||
|
|
||||||
- name: "Setup Node.js"
|
- name: "Setup Node.js"
|
||||||
uses: "actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f" # v6.1.0
|
uses: "actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238" # v6.2.0
|
||||||
with:
|
with:
|
||||||
node-version: "24.11.1"
|
node-version: "24.13.1"
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
|
||||||
- name: "Install dependencies"
|
- name: "Install dependencies"
|
||||||
@@ -36,8 +36,9 @@ jobs:
|
|||||||
|
|
||||||
- run: "node --run lint:editorconfig"
|
- run: "node --run lint:editorconfig"
|
||||||
- run: "node --run lint:markdown"
|
- run: "node --run lint:markdown"
|
||||||
- run: "node --run lint:typescript"
|
- run: "node --run lint:turbo"
|
||||||
- run: "node --run lint:eslint"
|
# - run: "node --run lint:typescript" # already covered by oxlint
|
||||||
- run: "node --run lint:prettier"
|
- run: "node --run lint:oxlint"
|
||||||
|
- run: "node --run lint:oxfmt"
|
||||||
- run: "node --run test"
|
- run: "node --run test"
|
||||||
- run: "node --run build"
|
- run: "node --run build"
|
||||||
|
|||||||
9
.oxfmtrc.json
Normal file
9
.oxfmtrc.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/oxfmt/configuration_schema.json",
|
||||||
|
"ignorePatterns": ["pnpm-lock.yaml"],
|
||||||
|
"semi": false,
|
||||||
|
"experimentalTailwindcss": {
|
||||||
|
"stylesheet": "./configs/config-tailwind/styles.css",
|
||||||
|
"functions": ["classNames"]
|
||||||
|
}
|
||||||
|
}
|
||||||
16
.oxlintrc.json
Normal file
16
.oxlintrc.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||||
|
"extends": ["node_modules/eslint-config-conventions/.oxlintrc.json"],
|
||||||
|
"rules": {
|
||||||
|
"import-x/extensions": [
|
||||||
|
"error",
|
||||||
|
"ignorePackages",
|
||||||
|
{
|
||||||
|
"ts": "always",
|
||||||
|
"tsx": "always",
|
||||||
|
"js": "never",
|
||||||
|
"jsx": "never"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"semi": false,
|
|
||||||
"plugins": ["prettier-plugin-tailwindcss"],
|
|
||||||
"tailwindFunctions": ["classNames", "cva"],
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": "pnpm-lock.yaml",
|
|
||||||
"options": {
|
|
||||||
"rangeEnd": 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -1,8 +1,7 @@
|
|||||||
{
|
{
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"editorconfig.editorconfig",
|
"editorconfig.editorconfig",
|
||||||
"prettier.prettier-vscode",
|
"oxc.oxc-vscode",
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"davidanson.vscode-markdownlint",
|
"davidanson.vscode-markdownlint",
|
||||||
"bradlc.vscode-tailwindcss",
|
"bradlc.vscode-tailwindcss",
|
||||||
"antfu.pnpm-catalog-lens",
|
"antfu.pnpm-catalog-lens",
|
||||||
|
|||||||
28
.vscode/settings.json
vendored
28
.vscode/settings.json
vendored
@@ -2,31 +2,29 @@
|
|||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"editor.bracketPairColorization.enabled": true,
|
"editor.bracketPairColorization.enabled": true,
|
||||||
"editor.wordWrap": "on",
|
"editor.wordWrap": "on",
|
||||||
"prettier.configPath": ".prettierrc.json",
|
|
||||||
"editor.defaultFormatter": "prettier.prettier-vscode",
|
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll": "explicit",
|
"source.fixAll": "never",
|
||||||
"source.organizeImports": "never"
|
"source.organizeImports": "never"
|
||||||
},
|
},
|
||||||
"eslint.workingDirectories": [
|
"oxc.enable": true,
|
||||||
{
|
"oxc.typeAware": true,
|
||||||
"mode": "auto"
|
"oxc.unusedDisableDirectives": "deny",
|
||||||
}
|
"editor.defaultFormatter": "oxc.oxc-vscode",
|
||||||
],
|
"editor.formatOnSave": true,
|
||||||
"files.associations": {
|
"typescript.experimental.useTsgo": false,
|
||||||
"*.css": "tailwindcss"
|
|
||||||
},
|
|
||||||
"editor.quickSuggestions": {
|
"editor.quickSuggestions": {
|
||||||
"strings": "on"
|
"strings": "on"
|
||||||
},
|
},
|
||||||
"tailwindCSS.classFunctions": ["classNames", "cva"],
|
"files.associations": {
|
||||||
|
"*.css": "tailwindcss"
|
||||||
|
},
|
||||||
|
"tailwindCSS.classFunctions": ["classNames"],
|
||||||
"tailwindCSS.experimental.configFile": "./configs/config-tailwind/styles.css",
|
"tailwindCSS.experimental.configFile": "./configs/config-tailwind/styles.css",
|
||||||
"i18n-ally.localesPaths": ["./packages/i18n/src/translations/"],
|
"i18n-ally.localesPaths": ["./packages/i18n/src/translations/"],
|
||||||
"i18n-ally.keystyle": "nested",
|
"i18n-ally.keystyle": "nested",
|
||||||
"i18n-ally.sortKeys": false,
|
"i18n-ally.sortKeys": false,
|
||||||
"i18n-ally.sourceLanguage": "en-US",
|
"i18n-ally.sourceLanguage": "fr-FR",
|
||||||
"i18n-ally.displayLanguage": "en-US",
|
"i18n-ally.displayLanguage": "fr-FR",
|
||||||
"i18n-ally.enabledFrameworks": ["next-intl", "general"],
|
"i18n-ally.enabledFrameworks": ["next-intl", "general"],
|
||||||
"i18n-ally.extract.autoDetect": true
|
"i18n-ally.extract.autoDetect": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ The commit message guidelines adheres to [Conventional Commits](https://www.conv
|
|||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- [Node.js](https://nodejs.org/) >= v24.0.0 [(`nvm install 24`)](https://nvm.sh)
|
- [Node.js](https://nodejs.org/) >= v24.0.0 [(`nvm install 24`)](https://nvm.sh)
|
||||||
- [pnpm](https://pnpm.io/) v10.25.0 [(`npm install --global corepack@0.34.5 && corepack enable`)](https://github.com/nodejs/corepack)
|
- [pnpm](https://pnpm.io/) [(`npm install --global corepack@0.34.6 && corepack enable`)](https://github.com/nodejs/corepack)
|
||||||
- [Docker](https://www.docker.com/)
|
- [Docker](https://www.docker.com/)
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
@@ -60,9 +60,10 @@ node --run dev
|
|||||||
# Lint
|
# Lint
|
||||||
node --run lint:editorconfig
|
node --run lint:editorconfig
|
||||||
node --run lint:markdown
|
node --run lint:markdown
|
||||||
node --run lint:typescript
|
node --run lint:turbo
|
||||||
node --run lint:eslint
|
# node --run lint:typescript # already covered by oxlint
|
||||||
node --run lint:prettier
|
node --run lint:oxlint
|
||||||
|
node --run lint:oxfmt
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
node --run test
|
node --run test
|
||||||
|
|||||||
24
README.md
24
README.md
@@ -35,29 +35,9 @@
|
|||||||
"tRPC/oRPC",
|
"tRPC/oRPC",
|
||||||
"PostgreSQL"
|
"PostgreSQL"
|
||||||
],
|
],
|
||||||
"sys-admin": [
|
"sys-admin": ["Docker", "Proxmox", "Caddy", "GitHub Actions", "GitLab CI/CD"],
|
||||||
"Docker",
|
"software-tools": ["GNU/Linux", "Arch Linux", "Visual Studio Code", "Git"],
|
||||||
"Proxmox",
|
|
||||||
"Caddy",
|
|
||||||
"GitHub Actions",
|
|
||||||
"GitLab CI/CD"
|
|
||||||
],
|
|
||||||
"software-tools": [
|
|
||||||
"GNU/Linux",
|
|
||||||
"Arch Linux",
|
|
||||||
"Visual Studio Code",
|
|
||||||
"Git"
|
|
||||||
],
|
|
||||||
"systems-programming": ["C/C++", "Rust", "Go"]
|
"systems-programming": ["C/C++", "Rust", "Go"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
## Statistics
|
|
||||||
|
|
||||||
<p align=center>
|
|
||||||
<img height=175 align="center" src="https://github-readme-stats.vercel.app/api?username=theoludwig&show_icons=true&theme=dark" alt="Théo LUDWIG's GitHub Stats" />
|
|
||||||
<img height=175 align="center" src="https://github-readme-stats.vercel.app/api/top-langs/?username=theoludwig&hide=html,css,javascript&langs_count=8&layout=compact&theme=dark" alt="Théo LUDWIG's Programming Languages" />
|
|
||||||
</p>
|
|
||||||
|
|||||||
@@ -12,11 +12,7 @@ const config: StorybookConfig = {
|
|||||||
"../../../packages/blog/src/**/*.stories.tsx",
|
"../../../packages/blog/src/**/*.stories.tsx",
|
||||||
"../stories/*.mdx",
|
"../stories/*.mdx",
|
||||||
],
|
],
|
||||||
addons: [
|
addons: ["@chromatic-com/storybook", "@storybook/addon-docs", "@storybook/addon-a11y"],
|
||||||
"@chromatic-com/storybook",
|
|
||||||
"@storybook/addon-docs",
|
|
||||||
"@storybook/addon-a11y",
|
|
||||||
],
|
|
||||||
framework: {
|
framework: {
|
||||||
name: "@storybook/nextjs",
|
name: "@storybook/nextjs",
|
||||||
options: {},
|
options: {},
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import typescriptESLint from "typescript-eslint"
|
|
||||||
import { defineConfig } from "eslint/config"
|
|
||||||
import config from "@repo/config-eslint"
|
|
||||||
|
|
||||||
export default defineConfig(...config, {
|
|
||||||
files: ["**/*.ts", "**/*.tsx"],
|
|
||||||
languageOptions: {
|
|
||||||
parser: typescriptESLint.parser,
|
|
||||||
parserOptions: {
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: import.meta.dirname,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -76,9 +76,7 @@ server.listen(
|
|||||||
port,
|
port,
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
console.log(
|
console.log(`HTTP Server is listening at ${util.styleText("cyan", serverURL)}`)
|
||||||
`HTTP Server is listening at ${util.styleText("cyan", serverURL)}`,
|
|
||||||
)
|
|
||||||
console.log(`Serving files from: \`${basePath}\``)
|
console.log(`Serving files from: \`${basePath}\``)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,39 +13,36 @@
|
|||||||
"chromatic": "chromatic"
|
"chromatic": "chromatic"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@repo/blog": "workspace:*",
|
||||||
"@repo/config-tailwind": "workspace:*",
|
"@repo/config-tailwind": "workspace:*",
|
||||||
"@repo/i18n": "workspace:*",
|
"@repo/i18n": "workspace:*",
|
||||||
"@repo/ui": "workspace:*",
|
"@repo/ui": "workspace:*",
|
||||||
"@repo/utils": "workspace:*",
|
"@repo/utils": "workspace:*",
|
||||||
"@repo/blog": "workspace:*",
|
"mime": "catalog:",
|
||||||
"next": "catalog:",
|
"next": "catalog:",
|
||||||
"next-intl": "catalog:",
|
"next-intl": "catalog:",
|
||||||
"next-themes": "catalog:",
|
"next-themes": "catalog:",
|
||||||
"react": "catalog:",
|
"react": "catalog:",
|
||||||
"react-dom": "catalog:",
|
"react-dom": "catalog:"
|
||||||
"mime": "catalog:"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@repo/config-eslint": "workspace:*",
|
|
||||||
"@repo/config-typescript": "workspace:*",
|
|
||||||
"@chromatic-com/storybook": "catalog:",
|
"@chromatic-com/storybook": "catalog:",
|
||||||
"@playwright/test": "catalog:",
|
"@playwright/test": "catalog:",
|
||||||
"@storybook/addon-docs": "catalog:",
|
"@repo/config-typescript": "workspace:*",
|
||||||
"@storybook/addon-a11y": "catalog:",
|
"@storybook/addon-a11y": "catalog:",
|
||||||
|
"@storybook/addon-docs": "catalog:",
|
||||||
"@storybook/addon-themes": "catalog:",
|
"@storybook/addon-themes": "catalog:",
|
||||||
"@storybook/nextjs": "catalog:",
|
"@storybook/nextjs": "catalog:",
|
||||||
"@storybook/test-runner": "catalog:",
|
"@storybook/test-runner": "catalog:",
|
||||||
|
"@tailwindcss/postcss": "catalog:",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"@types/react": "catalog:",
|
"@types/react": "catalog:",
|
||||||
"@types/react-dom": "catalog:",
|
"@types/react-dom": "catalog:",
|
||||||
"chromatic": "catalog:",
|
"chromatic": "catalog:",
|
||||||
"eslint": "catalog:",
|
"postcss": "catalog:",
|
||||||
"start-server-and-test": "catalog:",
|
"start-server-and-test": "catalog:",
|
||||||
"storybook": "catalog:",
|
"storybook": "catalog:",
|
||||||
"postcss": "catalog:",
|
|
||||||
"tailwindcss": "catalog:",
|
"tailwindcss": "catalog:",
|
||||||
"@tailwindcss/postcss": "catalog:",
|
|
||||||
"typescript-eslint": "catalog:",
|
|
||||||
"typescript": "catalog:"
|
"typescript": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
import {
|
import { Meta, Title, ColorPalette, ColorItem } from "@storybook/addon-docs/blocks"
|
||||||
Meta,
|
|
||||||
Title,
|
|
||||||
ColorPalette,
|
|
||||||
ColorItem,
|
|
||||||
} from "@storybook/addon-docs/blocks"
|
|
||||||
import tailwindConfig from "@repo/config-tailwind"
|
import tailwindConfig from "@repo/config-tailwind"
|
||||||
|
|
||||||
<Meta title="Design System/Colors" />
|
<Meta title="Design System/Colors" />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
FROM node:24.11.1-slim@sha256:0afb7822fac7bf9d7c1bf3b6e6c496dee6b2b64d8dfa365501a3c68e8eba94b2 AS node-pnpm
|
FROM node:24.13.1-slim@sha256:a81a03dd965b4052269a57fac857004022b522a4bf06e7a739e25e18bce45af2 AS node-pnpm
|
||||||
ENV PNPM_HOME="/pnpm"
|
ENV PNPM_HOME="/pnpm"
|
||||||
ENV PATH="$PNPM_HOME:$PATH"
|
ENV PATH="$PNPM_HOME:$PATH"
|
||||||
RUN npm install --global corepack@0.34.5 && corepack enable
|
RUN npm install --global corepack@0.34.6 && corepack enable
|
||||||
ENV TURBO_TELEMETRY_DISABLED=1
|
ENV TURBO_TELEMETRY_DISABLED=1
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
ENV DO_NOT_TRACK=1
|
ENV DO_NOT_TRACK=1
|
||||||
@@ -9,7 +9,7 @@ WORKDIR /usr/src/app
|
|||||||
|
|
||||||
FROM node-pnpm AS builder
|
FROM node-pnpm AS builder
|
||||||
COPY ./ ./
|
COPY ./ ./
|
||||||
RUN pnpm install --global turbo@2.6.3
|
RUN pnpm install --global turbo@2.8.9
|
||||||
RUN turbo prune @repo/website --docker
|
RUN turbo prune @repo/website --docker
|
||||||
|
|
||||||
FROM node-pnpm AS installer
|
FROM node-pnpm AS installer
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ interface BlogPostPageProps {
|
|||||||
}>
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateMetadata = async (
|
export const generateMetadata = async (props: BlogPostPageProps): Promise<Metadata> => {
|
||||||
props: BlogPostPageProps,
|
|
||||||
): Promise<Metadata> => {
|
|
||||||
const { slug } = await props.params
|
const { slug } = await props.params
|
||||||
const blogPost = await getBlogPostBySlug(slug)
|
const blogPost = await getBlogPostBySlug(slug)
|
||||||
if (blogPost == null) {
|
if (blogPost == null) {
|
||||||
@@ -37,9 +35,7 @@ export const generateMetadata = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateStaticParams = async (): Promise<
|
export const generateStaticParams = async (): Promise<Array<{ slug: string }>> => {
|
||||||
Array<{ slug: string }>
|
|
||||||
> => {
|
|
||||||
const posts = await getBlogPosts()
|
const posts = await getBlogPosts()
|
||||||
return posts.map((post) => {
|
return posts.map((post) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -2,18 +2,13 @@ import { getBlogPosts } from "@repo/blog"
|
|||||||
import { BlogPosts } from "@repo/blog/BlogPosts"
|
import { BlogPosts } from "@repo/blog/BlogPosts"
|
||||||
import type { LocaleProps } from "@repo/i18n/routing"
|
import type { LocaleProps } from "@repo/i18n/routing"
|
||||||
import { MainLayout } from "@repo/ui/Layout/MainLayout"
|
import { MainLayout } from "@repo/ui/Layout/MainLayout"
|
||||||
import {
|
import { Section, SectionDescription, SectionTitle } from "@repo/ui/Layout/Section"
|
||||||
Section,
|
|
||||||
SectionDescription,
|
|
||||||
SectionTitle,
|
|
||||||
} from "@repo/ui/Layout/Section"
|
|
||||||
import { LOCALE_DEFAULT } from "@repo/utils/constants"
|
import { LOCALE_DEFAULT } from "@repo/utils/constants"
|
||||||
import type { Metadata } from "next"
|
import type { Metadata } from "next"
|
||||||
import { setRequestLocale } from "next-intl/server"
|
import { setRequestLocale } from "next-intl/server"
|
||||||
|
|
||||||
const title = "Blog | Théo LUDWIG"
|
const title = "Blog | Théo LUDWIG"
|
||||||
const description =
|
const description = "The latest news about my journey of learning computer science."
|
||||||
"The latest news about my journey of learning computer science."
|
|
||||||
|
|
||||||
export const generateMetadata = async (): Promise<Metadata> => {
|
export const generateMetadata = async (): Promise<Metadata> => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ interface CurriculumVitaeLayoutProps extends React.PropsWithChildren {
|
|||||||
}>
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
const CurriculumVitaeLayout: React.FC<CurriculumVitaeLayoutProps> = async (
|
const CurriculumVitaeLayout: React.FC<CurriculumVitaeLayoutProps> = async (props) => {
|
||||||
props,
|
|
||||||
) => {
|
|
||||||
const { children, params } = props
|
const { children, params } = props
|
||||||
|
|
||||||
const { locale } = await params
|
const { locale } = await params
|
||||||
|
|||||||
@@ -3,11 +3,7 @@ import type { Locale } from "@repo/utils/constants"
|
|||||||
import { LOCALES } from "@repo/utils/constants"
|
import { LOCALES } from "@repo/utils/constants"
|
||||||
import type { Metadata, Viewport } from "next"
|
import type { Metadata, Viewport } from "next"
|
||||||
import { NextIntlClientProvider } from "next-intl"
|
import { NextIntlClientProvider } from "next-intl"
|
||||||
import {
|
import { getMessages, getTranslations, setRequestLocale } from "next-intl/server"
|
||||||
getMessages,
|
|
||||||
getTranslations,
|
|
||||||
setRequestLocale,
|
|
||||||
} from "next-intl/server"
|
|
||||||
import Script from "next/script"
|
import Script from "next/script"
|
||||||
|
|
||||||
const DOMAIN = "theoludwig.fr"
|
const DOMAIN = "theoludwig.fr"
|
||||||
@@ -85,14 +81,9 @@ const LocaleLayout: React.FC<LocaleLayoutProps> = async (props) => {
|
|||||||
return (
|
return (
|
||||||
<html lang={locale} suppressHydrationWarning>
|
<html lang={locale} suppressHydrationWarning>
|
||||||
<body>
|
<body>
|
||||||
<NextIntlClientProvider messages={messages}>
|
<NextIntlClientProvider messages={messages}>{children}</NextIntlClientProvider>
|
||||||
{children}
|
|
||||||
</NextIntlClientProvider>
|
|
||||||
|
|
||||||
<Script
|
<Script async src="https://analytics.theoludwig.fr/js/pa-MToGPBn2iXgorPLkh6f_s.js" />
|
||||||
async
|
|
||||||
src="https://analytics.theoludwig.fr/js/pa-MToGPBn2iXgorPLkh6f_s.js"
|
|
||||||
/>
|
|
||||||
<Script id="analytics-init">
|
<Script id="analytics-init">
|
||||||
{`
|
{`
|
||||||
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import typescriptESLint from "typescript-eslint"
|
|
||||||
import { defineConfig } from "eslint/config"
|
|
||||||
import config from "@repo/config-eslint"
|
|
||||||
|
|
||||||
export default defineConfig(...config, {
|
|
||||||
files: ["**/*.ts", "**/*.tsx"],
|
|
||||||
languageOptions: {
|
|
||||||
parser: typescriptESLint.parser,
|
|
||||||
parserOptions: {
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: import.meta.dirname,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -14,9 +14,6 @@ const nextConfig: NextConfig = {
|
|||||||
typescript: {
|
typescript: {
|
||||||
ignoreBuildErrors: true,
|
ignoreBuildErrors: true,
|
||||||
},
|
},
|
||||||
experimental: {
|
|
||||||
turbopackFileSystemCacheForDev: true,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const withNextIntl = createNextIntlPlugin({
|
const withNextIntl = createNextIntlPlugin({
|
||||||
|
|||||||
@@ -11,35 +11,31 @@
|
|||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start --port 3000",
|
"start": "next start --port 3000",
|
||||||
"typegen": "next typegen",
|
"typegen": "next typegen",
|
||||||
"lint:eslint": "eslint app --max-warnings 0",
|
|
||||||
"lint:typescript": "next typegen && tsc --noEmit"
|
"lint:typescript": "next typegen && tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@mdx-js/mdx": "catalog:",
|
||||||
"@repo/blog": "workspace:*",
|
"@repo/blog": "workspace:*",
|
||||||
"@repo/config-tailwind": "workspace:*",
|
"@repo/config-tailwind": "workspace:*",
|
||||||
"@repo/utils": "workspace:*",
|
|
||||||
"@repo/i18n": "workspace:*",
|
"@repo/i18n": "workspace:*",
|
||||||
"@repo/ui": "workspace:*",
|
"@repo/ui": "workspace:*",
|
||||||
"@mdx-js/mdx": "catalog:",
|
"@repo/utils": "workspace:*",
|
||||||
"next-mdx-remote": "catalog:",
|
|
||||||
"shiki": "catalog:",
|
|
||||||
"next": "catalog:",
|
"next": "catalog:",
|
||||||
"next-intl": "catalog:",
|
"next-intl": "catalog:",
|
||||||
|
"next-mdx-remote": "catalog:",
|
||||||
"react": "catalog:",
|
"react": "catalog:",
|
||||||
"react-dom": "catalog:"
|
"react-dom": "catalog:",
|
||||||
|
"shiki": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@repo/config-eslint": "workspace:*",
|
|
||||||
"@repo/config-typescript": "workspace:*",
|
"@repo/config-typescript": "workspace:*",
|
||||||
|
"@tailwindcss/postcss": "catalog:",
|
||||||
|
"@total-typescript/ts-reset": "catalog:",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"@types/react": "catalog:",
|
"@types/react": "catalog:",
|
||||||
"@types/react-dom": "catalog:",
|
"@types/react-dom": "catalog:",
|
||||||
"@total-typescript/ts-reset": "catalog:",
|
|
||||||
"eslint": "catalog:",
|
|
||||||
"postcss": "catalog:",
|
"postcss": "catalog:",
|
||||||
"tailwindcss": "catalog:",
|
"tailwindcss": "catalog:",
|
||||||
"@tailwindcss/postcss": "catalog:",
|
|
||||||
"typescript-eslint": "catalog:",
|
|
||||||
"typescript": "catalog:"
|
"typescript": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
import nextPlugin from "@next/eslint-plugin-next"
|
|
||||||
import configConventions from "eslint-config-conventions"
|
|
||||||
import importXPlugin from "eslint-plugin-import-x"
|
|
||||||
import reactPlugin from "eslint-plugin-react"
|
|
||||||
import reactHooks from "eslint-plugin-react-hooks"
|
|
||||||
import { defineConfig, globalIgnores } from "eslint/config"
|
|
||||||
|
|
||||||
export default defineConfig(
|
|
||||||
...configConventions,
|
|
||||||
reactPlugin.configs.flat.recommended,
|
|
||||||
globalIgnores(["**/kysely.config.ts"]),
|
|
||||||
{
|
|
||||||
name: "config-eslint",
|
|
||||||
settings: {
|
|
||||||
react: {
|
|
||||||
version: "19.2.0",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: {
|
|
||||||
"@next/next": nextPlugin,
|
|
||||||
"import-x": importXPlugin,
|
|
||||||
"react-hooks": reactHooks,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
...nextPlugin.configs.recommended.rules,
|
|
||||||
...nextPlugin.configs["core-web-vitals"].rules,
|
|
||||||
...reactHooks.configs.recommended.rules,
|
|
||||||
"@next/next/no-html-link-for-pages": "off",
|
|
||||||
"@next/next/no-img-element": "off",
|
|
||||||
|
|
||||||
"react/jsx-no-target-blank": "off",
|
|
||||||
"react/no-unknown-property": "off",
|
|
||||||
"react/react-in-jsx-scope": "off",
|
|
||||||
"react/prop-types": "off",
|
|
||||||
"react/self-closing-comp": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
component: true,
|
|
||||||
html: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"react/void-dom-elements-no-children": "error",
|
|
||||||
"react/jsx-boolean-value": "error",
|
|
||||||
"react/iframe-missing-sandbox": "off",
|
|
||||||
|
|
||||||
"no-restricted-imports": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
name: "next/navigation",
|
|
||||||
importNames: [
|
|
||||||
"redirect",
|
|
||||||
"permanentRedirect",
|
|
||||||
"useRouter",
|
|
||||||
"usePathname",
|
|
||||||
],
|
|
||||||
message: "Please import from `@repo/i18n/routing` instead.",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"import-x/extensions": [
|
|
||||||
"error",
|
|
||||||
"ignorePackages",
|
|
||||||
{
|
|
||||||
ts: "always",
|
|
||||||
tsx: "always",
|
|
||||||
js: "never",
|
|
||||||
jsx: "never",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
5
configs/config-eslint/index.d.ts
vendored
5
configs/config-eslint/index.d.ts
vendored
@@ -1,5 +0,0 @@
|
|||||||
import type { defineConfig } from "eslint/config"
|
|
||||||
|
|
||||||
declare const eslintConfig: ReturnType<typeof defineConfig>
|
|
||||||
|
|
||||||
export default eslintConfig
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@repo/config-eslint",
|
|
||||||
"version": "0.0.0-develop",
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"types": "./index.d.ts",
|
|
||||||
"import": "./eslint.config.js",
|
|
||||||
"require": "./eslint.config.js",
|
|
||||||
"default": "./eslint.config.js"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"typescript-eslint": "catalog:",
|
|
||||||
"eslint": "catalog:",
|
|
||||||
"eslint-config-conventions": "catalog:",
|
|
||||||
"eslint-plugin-promise": "catalog:",
|
|
||||||
"eslint-plugin-unicorn": "catalog:",
|
|
||||||
"eslint-plugin-import-x": "catalog:",
|
|
||||||
"@next/eslint-plugin-next": "catalog:",
|
|
||||||
"eslint-plugin-react": "catalog:",
|
|
||||||
"eslint-plugin-react-hooks": "catalog:",
|
|
||||||
"typescript": "catalog:",
|
|
||||||
"globals": "catalog:"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import typescriptESLint from "typescript-eslint"
|
|
||||||
import { defineConfig } from "eslint/config"
|
|
||||||
import config from "@repo/config-eslint"
|
|
||||||
|
|
||||||
export default defineConfig(...config, {
|
|
||||||
files: ["**/*.ts", "**/*.tsx"],
|
|
||||||
languageOptions: {
|
|
||||||
parser: typescriptESLint.parser,
|
|
||||||
parserOptions: {
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: import.meta.dirname,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -21,13 +21,10 @@
|
|||||||
"tailwind-merge": "catalog:"
|
"tailwind-merge": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@repo/config-eslint": "workspace:*",
|
|
||||||
"@repo/config-typescript": "workspace:*",
|
"@repo/config-typescript": "workspace:*",
|
||||||
|
"@tailwindcss/postcss": "catalog:",
|
||||||
"@tailwindcss/typography": "catalog:",
|
"@tailwindcss/typography": "catalog:",
|
||||||
"typescript-eslint": "catalog:",
|
|
||||||
"eslint": "catalog:",
|
|
||||||
"postcss": "catalog:",
|
"postcss": "catalog:",
|
||||||
"tailwindcss": "catalog:",
|
"tailwindcss": "catalog:"
|
||||||
"@tailwindcss/postcss": "catalog:"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
@source "../../packages/ui/src";
|
@source "../../packages/ui/src";
|
||||||
@source "../../packages/blog/src";
|
@source "../../packages/blog/src";
|
||||||
|
|
||||||
@import "@fontsource/montserrat/400.css" layer(base);
|
@import "@fontsource/montserrat/400.css";
|
||||||
@import "@fontsource/montserrat/500.css" layer(base);
|
@import "@fontsource/montserrat/500.css";
|
||||||
@import "@fontsource/montserrat/600.css" layer(base);
|
@import "@fontsource/montserrat/600.css";
|
||||||
@import "@fontsource/montserrat/700.css" layer(base);
|
@import "@fontsource/montserrat/700.css";
|
||||||
@import "@fontsource/montserrat/800.css" layer(base);
|
@import "@fontsource/montserrat/800.css";
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
[type="search"]::-webkit-search-decoration,
|
[type="search"]::-webkit-search-decoration,
|
||||||
|
|||||||
31
package.json
31
package.json
@@ -3,30 +3,33 @@
|
|||||||
"version": "0.0.0-develop",
|
"version": "0.0.0-develop",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"packageManager": "pnpm@10.25.0+sha512.5e82639027af37cf832061bcc6d639c219634488e0f2baebe785028a793de7b525ffcd3f7ff574f5e9860654e098fe852ba8ac5dd5cefe1767d23a020a92f501",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=24.0.0"
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "turbo run dev --parallel",
|
"dev": "turbo run dev --parallel",
|
||||||
"start": "turbo run start --parallel",
|
"start": "turbo run start --parallel",
|
||||||
"build": "turbo run build",
|
|
||||||
"test": "turbo run test",
|
|
||||||
"lint:editorconfig": "editorconfig-checker",
|
"lint:editorconfig": "editorconfig-checker",
|
||||||
"lint:markdown": "markdownlint-cli2",
|
"lint:markdown": "markdownlint-cli2",
|
||||||
|
"lint:turbo": "turbo boundaries",
|
||||||
"lint:typescript": "turbo run lint:typescript",
|
"lint:typescript": "turbo run lint:typescript",
|
||||||
"lint:eslint": "turbo run lint:eslint",
|
"lint:oxlint": "turbo run typegen && oxlint . --type-aware --type-check --deny-warnings --report-unused-disable-directives",
|
||||||
"lint:prettier": "prettier . --check"
|
"lint:oxfmt": "oxfmt . --check",
|
||||||
|
"oxfmt": "oxfmt .",
|
||||||
|
"test": "turbo run test",
|
||||||
|
"build": "turbo run build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"editorconfig-checker": "catalog:",
|
"eslint-config-conventions": "catalog:",
|
||||||
"playwright": "catalog:",
|
|
||||||
"prettier": "catalog:",
|
|
||||||
"prettier-plugin-tailwindcss": "catalog:",
|
|
||||||
"markdownlint-cli2": "catalog:",
|
|
||||||
"markdownlint": "catalog:",
|
"markdownlint": "catalog:",
|
||||||
|
"markdownlint-cli2": "catalog:",
|
||||||
"markdownlint-rule-relative-links": "catalog:",
|
"markdownlint-rule-relative-links": "catalog:",
|
||||||
|
"oxfmt": "catalog:",
|
||||||
|
"oxlint": "catalog:",
|
||||||
|
"oxlint-tsgolint": "catalog:",
|
||||||
|
"playwright": "catalog:",
|
||||||
"turbo": "catalog:",
|
"turbo": "catalog:",
|
||||||
"typescript": "catalog:"
|
"typescript": "catalog:"
|
||||||
}
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=24.0.0"
|
||||||
|
},
|
||||||
|
"packageManager": "pnpm@10.29.3+sha512.498e1fb4cca5aa06c1dcf2611e6fafc50972ffe7189998c409e90de74566444298ffe43e6cd2acdc775ba1aa7cc5e092a8b7054c811ba8c5770f84693d33d2dc"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import typescriptESLint from "typescript-eslint"
|
|
||||||
import { defineConfig } from "eslint/config"
|
|
||||||
import config from "@repo/config-eslint"
|
|
||||||
|
|
||||||
export default defineConfig(...config, {
|
|
||||||
files: ["**/*.ts", "**/*.tsx"],
|
|
||||||
languageOptions: {
|
|
||||||
parser: typescriptESLint.parser,
|
|
||||||
parserOptions: {
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: import.meta.dirname,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -9,46 +9,42 @@
|
|||||||
"./BlogPostUI": "./src/BlogPostUI.tsx"
|
"./BlogPostUI": "./src/BlogPostUI.tsx"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint:eslint": "eslint src --max-warnings 0",
|
|
||||||
"lint:typescript": "tsc --noEmit"
|
"lint:typescript": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@giscus/react": "catalog:",
|
||||||
|
"@mdx-js/mdx": "catalog:",
|
||||||
"@repo/config-tailwind": "workspace:*",
|
"@repo/config-tailwind": "workspace:*",
|
||||||
"@repo/utils": "workspace:*",
|
|
||||||
"@repo/i18n": "workspace:*",
|
"@repo/i18n": "workspace:*",
|
||||||
"@repo/ui": "workspace:*",
|
"@repo/ui": "workspace:*",
|
||||||
"@giscus/react": "catalog:",
|
"@repo/utils": "workspace:*",
|
||||||
"@shikijs/rehype": "catalog:",
|
"@shikijs/rehype": "catalog:",
|
||||||
"@mdx-js/mdx": "catalog:",
|
|
||||||
"gray-matter": "catalog:",
|
"gray-matter": "catalog:",
|
||||||
"katex": "catalog:",
|
"katex": "catalog:",
|
||||||
|
"next": "catalog:",
|
||||||
|
"next-intl": "catalog:",
|
||||||
|
"next-mdx-remote": "catalog:",
|
||||||
|
"react": "catalog:",
|
||||||
|
"react-dom": "catalog:",
|
||||||
|
"react-icons": "catalog:",
|
||||||
"rehype-katex": "catalog:",
|
"rehype-katex": "catalog:",
|
||||||
"rehype-raw": "catalog:",
|
"rehype-raw": "catalog:",
|
||||||
"rehype-slug": "catalog:",
|
"rehype-slug": "catalog:",
|
||||||
"remark-gfm": "catalog:",
|
"remark-gfm": "catalog:",
|
||||||
"remark-math": "catalog:",
|
"remark-math": "catalog:",
|
||||||
"shiki": "catalog:",
|
"shiki": "catalog:"
|
||||||
"next": "catalog:",
|
|
||||||
"next-mdx-remote": "catalog:",
|
|
||||||
"next-intl": "catalog:",
|
|
||||||
"react": "catalog:",
|
|
||||||
"react-dom": "catalog:",
|
|
||||||
"react-icons": "catalog:"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@repo/config-eslint": "workspace:*",
|
|
||||||
"@repo/config-typescript": "workspace:*",
|
"@repo/config-typescript": "workspace:*",
|
||||||
|
"@storybook/nextjs": "catalog:",
|
||||||
|
"@tailwindcss/postcss": "catalog:",
|
||||||
|
"@total-typescript/ts-reset": "catalog:",
|
||||||
"@types/node": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"@types/react": "catalog:",
|
"@types/react": "catalog:",
|
||||||
"@types/react-dom": "catalog:",
|
"@types/react-dom": "catalog:",
|
||||||
"@total-typescript/ts-reset": "catalog:",
|
|
||||||
"storybook": "catalog:",
|
|
||||||
"@storybook/nextjs": "catalog:",
|
|
||||||
"eslint": "catalog:",
|
|
||||||
"postcss": "catalog:",
|
"postcss": "catalog:",
|
||||||
|
"storybook": "catalog:",
|
||||||
"tailwindcss": "catalog:",
|
"tailwindcss": "catalog:",
|
||||||
"@tailwindcss/postcss": "catalog:",
|
|
||||||
"typescript-eslint": "catalog:",
|
|
||||||
"typescript": "catalog:"
|
"typescript": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,10 +173,7 @@ We have to keep it as simple as possible, not to implement features that are not
|
|||||||
import fs from "node:fs"
|
import fs from "node:fs"
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
|
|
||||||
const createFile = async (
|
const createFile = async (name: string, isTemporary: boolean = false): Promise<void> => {
|
||||||
name: string,
|
|
||||||
isTemporary: boolean = false,
|
|
||||||
): Promise<void> => {
|
|
||||||
if (isTemporary) {
|
if (isTemporary) {
|
||||||
return await fs.promises.writeFile(path.join("temporary", name), "")
|
return await fs.promises.writeFile(path.join("temporary", name), "")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ export const BLOG_POST_MOCK = {
|
|||||||
"\nHello, world! 👋\n\n## Introduction\n\nThis blog is here to document my journey of learning computer science.",
|
"\nHello, world! 👋\n\n## Introduction\n\nThis blog is here to document my journey of learning computer science.",
|
||||||
frontmatter: {
|
frontmatter: {
|
||||||
title: "👋 Hello, world!",
|
title: "👋 Hello, world!",
|
||||||
description:
|
description: "First post of the blog, introduction and explanation of how this blog is made.",
|
||||||
"First post of the blog, introduction and explanation of how this blog is made.",
|
|
||||||
isPublished: true,
|
isPublished: true,
|
||||||
publishedOn: "2022-02-20T08:00:18.758Z",
|
publishedOn: "2022-02-20T08:00:18.758Z",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,10 +14,9 @@ import "katex/dist/katex.min.css"
|
|||||||
import { BlogPostComments } from "./BlogPostComments.tsx"
|
import { BlogPostComments } from "./BlogPostComments.tsx"
|
||||||
|
|
||||||
const Heading: React.FC<
|
const Heading: React.FC<
|
||||||
React.DetailedHTMLProps<
|
React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement> & {
|
||||||
React.HTMLAttributes<HTMLHeadingElement>,
|
as: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"
|
||||||
HTMLHeadingElement
|
}
|
||||||
> & { as: "h1" | "h2" | "h3" | "h4" | "h5" | "h6" }
|
|
||||||
> = (props) => {
|
> = (props) => {
|
||||||
const { children, as, id = "", ...rest } = props
|
const { children, as, id = "", ...rest } = props
|
||||||
|
|
||||||
@@ -37,9 +36,7 @@ export interface BlogPostContentProps {
|
|||||||
content: string
|
content: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BlogPostContent: React.FC<BlogPostContentProps> = async (
|
export const BlogPostContent: React.FC<BlogPostContentProps> = async (props) => {
|
||||||
props,
|
|
||||||
) => {
|
|
||||||
const { content } = props
|
const { content } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -90,13 +87,7 @@ export const BlogPostContent: React.FC<BlogPostContentProps> = async (
|
|||||||
const source = src.replace("../../../apps/website/public/", "/")
|
const source = src.replace("../../../apps/website/public/", "/")
|
||||||
return (
|
return (
|
||||||
<span className="flex flex-col items-center justify-center">
|
<span className="flex flex-col items-center justify-center">
|
||||||
<Image
|
<Image src={source} alt={alt} width={1000} height={1000} className="size-auto" />
|
||||||
src={source}
|
|
||||||
alt={alt}
|
|
||||||
width={1000}
|
|
||||||
height={1000}
|
|
||||||
className="size-auto"
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -109,9 +100,7 @@ export const BlogPostContent: React.FC<BlogPostContentProps> = async (
|
|||||||
if (hrefString.startsWith("../posts/")) {
|
if (hrefString.startsWith("../posts/")) {
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
href={hrefString
|
href={hrefString.replace("../posts/", "/blog/").replace(".md", "")}
|
||||||
.replace("../posts/", "/blog/")
|
|
||||||
.replace(".md", "")}
|
|
||||||
{...rest}
|
{...rest}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -19,9 +19,7 @@ export const BlogPostUI: React.FC<BlogPostUIProps> = (props) => {
|
|||||||
<Typography variant="h2" as="h1">
|
<Typography variant="h2" as="h1">
|
||||||
{blogPost.frontmatter.title}
|
{blogPost.frontmatter.title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<p className="mt-2">
|
<p className="mt-2">{getISODate(new Date(blogPost.frontmatter.publishedOn))}</p>
|
||||||
{getISODate(new Date(blogPost.frontmatter.publishedOn))}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<BlogPostContent content={blogPost.content} />
|
<BlogPostContent content={blogPost.content} />
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|||||||
@@ -14,9 +14,7 @@ export const BlogPosts: React.FC<BlogPostsProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<ul className="list-none">
|
<ul className="list-none">
|
||||||
{posts.map((post) => {
|
{posts.map((post) => {
|
||||||
const postPublishedOn = getISODate(
|
const postPublishedOn = getISODate(new Date(post.frontmatter.publishedOn))
|
||||||
new Date(post.frontmatter.publishedOn),
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={post.slug}>
|
<li key={post.slug}>
|
||||||
|
|||||||
@@ -4,14 +4,7 @@ import path from "node:path"
|
|||||||
import matter from "gray-matter"
|
import matter from "gray-matter"
|
||||||
import type { BlogPost, FrontMatter } from "./BlogPost.tsx"
|
import type { BlogPost, FrontMatter } from "./BlogPost.tsx"
|
||||||
|
|
||||||
export const BLOG_POSTS_PATH = path.join(
|
export const BLOG_POSTS_PATH = path.join(process.cwd(), "..", "..", "packages", "blog", "posts")
|
||||||
process.cwd(),
|
|
||||||
"..",
|
|
||||||
"..",
|
|
||||||
"packages",
|
|
||||||
"blog",
|
|
||||||
"posts",
|
|
||||||
)
|
|
||||||
|
|
||||||
export const getBlogPosts = async (): Promise<BlogPost[]> => {
|
export const getBlogPosts = async (): Promise<BlogPost[]> => {
|
||||||
const blogPosts = await fs.promises.readdir(BLOG_POSTS_PATH)
|
const blogPosts = await fs.promises.readdir(BLOG_POSTS_PATH)
|
||||||
@@ -48,9 +41,7 @@ export const getBlogPosts = async (): Promise<BlogPost[]> => {
|
|||||||
return blogPostsSortedByPublicationDate
|
return blogPostsSortedByPublicationDate
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getBlogPostBySlug = async (
|
export const getBlogPostBySlug = async (slug: string): Promise<BlogPost | undefined> => {
|
||||||
slug: string,
|
|
||||||
): Promise<BlogPost | undefined> => {
|
|
||||||
const blogPosts = await getBlogPosts()
|
const blogPosts = await getBlogPosts()
|
||||||
const blogPost = blogPosts.find((blogPost) => {
|
const blogPost = blogPosts.find((blogPost) => {
|
||||||
return blogPost.slug === slug
|
return blogPost.slug === slug
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
"extends": "@repo/config-typescript/tsconfig.json",
|
"extends": "@repo/config-typescript/tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
||||||
"types": [
|
"types": ["@total-typescript/ts-reset", "@types/node", "@repo/i18n/messages.d.ts"]
|
||||||
"@total-typescript/ts-reset",
|
|
||||||
"@types/node",
|
|
||||||
"@repo/i18n/messages.d.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import typescriptESLint from "typescript-eslint"
|
|
||||||
import { defineConfig } from "eslint/config"
|
|
||||||
import config from "@repo/config-eslint"
|
|
||||||
|
|
||||||
export default defineConfig(...config, {
|
|
||||||
files: ["**/*.ts", "**/*.tsx"],
|
|
||||||
languageOptions: {
|
|
||||||
parser: typescriptESLint.parser,
|
|
||||||
parserOptions: {
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: import.meta.dirname,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
"./routing": "./src/routing.ts"
|
"./routing": "./src/routing.ts"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint:eslint": "eslint src --max-warnings 0",
|
|
||||||
"lint:typescript": "tsc --noEmit"
|
"lint:typescript": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -21,13 +20,10 @@
|
|||||||
"react-dom": "catalog:"
|
"react-dom": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@repo/config-eslint": "workspace:*",
|
|
||||||
"@repo/config-typescript": "workspace:*",
|
"@repo/config-typescript": "workspace:*",
|
||||||
|
"@total-typescript/ts-reset": "catalog:",
|
||||||
"@types/react": "catalog:",
|
"@types/react": "catalog:",
|
||||||
"@types/react-dom": "catalog:",
|
"@types/react-dom": "catalog:",
|
||||||
"@total-typescript/ts-reset": "catalog:",
|
|
||||||
"eslint": "catalog:",
|
|
||||||
"typescript-eslint": "catalog:",
|
|
||||||
"typescript": "catalog:"
|
"typescript": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,18 +8,11 @@ import { deepMerge } from "@repo/utils/objects"
|
|||||||
|
|
||||||
export default getRequestConfig(async ({ requestLocale }) => {
|
export default getRequestConfig(async ({ requestLocale }) => {
|
||||||
const requested = await requestLocale
|
const requested = await requestLocale
|
||||||
const locale = hasLocale(routing.locales, requested)
|
const locale = hasLocale(routing.locales, requested) ? requested : routing.defaultLocale
|
||||||
? requested
|
|
||||||
: routing.defaultLocale
|
|
||||||
|
|
||||||
const userMessages = (await import(`./translations/${locale}.json`)).default
|
const userMessages = (await import(`./translations/${locale}.json`)).default
|
||||||
const defaultMessages = (
|
const defaultMessages = (await import(`./translations/${LOCALE_DEFAULT}.json`)).default
|
||||||
await import(`./translations/${LOCALE_DEFAULT}.json`)
|
const messages = deepMerge<AbstractIntlMessages>(defaultMessages, userMessages)
|
||||||
).default
|
|
||||||
const messages = deepMerge<AbstractIntlMessages>(
|
|
||||||
defaultMessages,
|
|
||||||
userMessages,
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
locale,
|
locale,
|
||||||
|
|||||||
@@ -23,11 +23,5 @@ export const routing = defineRouting({
|
|||||||
localePrefix: LOCALE_PREFIX,
|
localePrefix: LOCALE_PREFIX,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const {
|
export const { Link, redirect, usePathname, useRouter, getPathname, permanentRedirect } =
|
||||||
Link,
|
createNavigation(routing)
|
||||||
redirect,
|
|
||||||
usePathname,
|
|
||||||
useRouter,
|
|
||||||
getPathname,
|
|
||||||
permanentRedirect,
|
|
||||||
} = createNavigation(routing)
|
|
||||||
|
|||||||
@@ -164,13 +164,7 @@
|
|||||||
"name": "Backend",
|
"name": "Backend",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"keywords": [
|
"keywords": ["GNU/Linux", "Arch Linux", "Visual Studio Code", "Git", "Docker"],
|
||||||
"GNU/Linux",
|
|
||||||
"Arch Linux",
|
|
||||||
"Visual Studio Code",
|
|
||||||
"Git",
|
|
||||||
"Docker",
|
|
||||||
],
|
|
||||||
"name": "Logiciels et outils",
|
"name": "Logiciels et outils",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import typescriptESLint from "typescript-eslint"
|
|
||||||
import { defineConfig } from "eslint/config"
|
|
||||||
import config from "@repo/config-eslint"
|
|
||||||
|
|
||||||
export default defineConfig(...config, {
|
|
||||||
files: ["**/*.ts", "**/*.tsx"],
|
|
||||||
languageOptions: {
|
|
||||||
parser: typescriptESLint.parser,
|
|
||||||
parserOptions: {
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: import.meta.dirname,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -23,14 +23,12 @@
|
|||||||
"./Layout/Section": "./src/Layout/Section/Section.tsx"
|
"./Layout/Section": "./src/Layout/Section/Section.tsx"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint:eslint": "eslint src --max-warnings 0",
|
|
||||||
"lint:typescript": "tsc --noEmit"
|
"lint:typescript": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@repo/config-tailwind": "workspace:*",
|
"@repo/config-tailwind": "workspace:*",
|
||||||
"@repo/utils": "workspace:*",
|
|
||||||
"@repo/i18n": "workspace:*",
|
"@repo/i18n": "workspace:*",
|
||||||
"cva": "catalog:",
|
"@repo/utils": "workspace:*",
|
||||||
"next": "catalog:",
|
"next": "catalog:",
|
||||||
"next-intl": "catalog:",
|
"next-intl": "catalog:",
|
||||||
"next-themes": "catalog:",
|
"next-themes": "catalog:",
|
||||||
@@ -39,18 +37,15 @@
|
|||||||
"react-icons": "catalog:"
|
"react-icons": "catalog:"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@repo/config-eslint": "workspace:*",
|
|
||||||
"@repo/config-typescript": "workspace:*",
|
"@repo/config-typescript": "workspace:*",
|
||||||
|
"@storybook/nextjs": "catalog:",
|
||||||
|
"@tailwindcss/postcss": "catalog:",
|
||||||
|
"@total-typescript/ts-reset": "catalog:",
|
||||||
"@types/react": "catalog:",
|
"@types/react": "catalog:",
|
||||||
"@types/react-dom": "catalog:",
|
"@types/react-dom": "catalog:",
|
||||||
"@total-typescript/ts-reset": "catalog:",
|
|
||||||
"storybook": "catalog:",
|
|
||||||
"@storybook/nextjs": "catalog:",
|
|
||||||
"eslint": "catalog:",
|
|
||||||
"postcss": "catalog:",
|
"postcss": "catalog:",
|
||||||
|
"storybook": "catalog:",
|
||||||
"tailwindcss": "catalog:",
|
"tailwindcss": "catalog:",
|
||||||
"@tailwindcss/postcss": "catalog:",
|
|
||||||
"typescript-eslint": "catalog:",
|
|
||||||
"typescript": "catalog:"
|
"typescript": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import { CurriculumVitaeSection } from "./CurriculumVitaeSection.tsx"
|
|||||||
|
|
||||||
export interface CurriculumVitaeEducationProps {}
|
export interface CurriculumVitaeEducationProps {}
|
||||||
|
|
||||||
export const CurriculumVitaeEducation: React.FC<
|
export const CurriculumVitaeEducation: React.FC<CurriculumVitaeEducationProps> = () => {
|
||||||
CurriculumVitaeEducationProps
|
|
||||||
> = () => {
|
|
||||||
const t = useTranslations()
|
const t = useTranslations()
|
||||||
|
|
||||||
const educations = [
|
const educations = [
|
||||||
@@ -27,20 +25,15 @@ export const CurriculumVitaeEducation: React.FC<
|
|||||||
title: t("curriculum-vitae.education.iut.years.2021-2022.title"),
|
title: t("curriculum-vitae.education.iut.years.2021-2022.title"),
|
||||||
courses: [
|
courses: [
|
||||||
t("curriculum-vitae.education.iut.years.2021-2022.courses.java"),
|
t("curriculum-vitae.education.iut.years.2021-2022.courses.java"),
|
||||||
t(
|
t("curriculum-vitae.education.iut.years.2021-2022.courses.systems-c"),
|
||||||
"curriculum-vitae.education.iut.years.2021-2022.courses.systems-c",
|
|
||||||
),
|
|
||||||
// t(
|
// t(
|
||||||
// "curriculum-vitae.education.iut.years.2021-2022.courses.windows-forms",
|
// "curriculum-vitae.education.iut.years.2021-2022.courses.windows-forms",
|
||||||
// ),
|
// ),
|
||||||
t.rich(
|
t.rich("curriculum-vitae.education.iut.years.2021-2022.courses.sql", {
|
||||||
"curriculum-vitae.education.iut.years.2021-2022.courses.sql",
|
|
||||||
{
|
|
||||||
strong: (children) => {
|
strong: (children) => {
|
||||||
return <strong>{children}</strong>
|
return <strong>{children}</strong>
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -48,49 +41,35 @@ export const CurriculumVitaeEducation: React.FC<
|
|||||||
title: t("curriculum-vitae.education.iut.years.2022-2023.title"),
|
title: t("curriculum-vitae.education.iut.years.2022-2023.title"),
|
||||||
courses: [
|
courses: [
|
||||||
t("curriculum-vitae.education.iut.years.2022-2023.courses.web"),
|
t("curriculum-vitae.education.iut.years.2022-2023.courses.web"),
|
||||||
t.rich(
|
t.rich("curriculum-vitae.education.iut.years.2022-2023.courses.tests", {
|
||||||
"curriculum-vitae.education.iut.years.2022-2023.courses.tests",
|
|
||||||
{
|
|
||||||
strong: (children) => {
|
strong: (children) => {
|
||||||
return <strong>{children}</strong>
|
return <strong>{children}</strong>
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
t.rich("curriculum-vitae.education.iut.years.2022-2023.courses.clean-code", {
|
||||||
t.rich(
|
|
||||||
"curriculum-vitae.education.iut.years.2022-2023.courses.clean-code",
|
|
||||||
{
|
|
||||||
strong: (children) => {
|
strong: (children) => {
|
||||||
return <strong>{children}</strong>
|
return <strong>{children}</strong>
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
// t("curriculum-vitae.education.iut.years.2022-2023.courses.sql-security"),
|
// t("curriculum-vitae.education.iut.years.2022-2023.courses.sql-security"),
|
||||||
t.rich(
|
t.rich("curriculum-vitae.education.iut.years.2022-2023.courses.systems-c", {
|
||||||
"curriculum-vitae.education.iut.years.2022-2023.courses.systems-c",
|
|
||||||
{
|
|
||||||
strong: (children) => {
|
strong: (children) => {
|
||||||
return <strong>{children}</strong>
|
return <strong>{children}</strong>
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
year: t("curriculum-vitae.education.iut.years.2023-2024.description"),
|
year: t("curriculum-vitae.education.iut.years.2023-2024.description"),
|
||||||
title: t("curriculum-vitae.education.iut.years.2023-2024.title"),
|
title: t("curriculum-vitae.education.iut.years.2023-2024.title"),
|
||||||
courses: [
|
courses: [
|
||||||
t.rich(
|
t.rich("curriculum-vitae.education.iut.years.2023-2024.courses.web", {
|
||||||
"curriculum-vitae.education.iut.years.2023-2024.courses.web",
|
|
||||||
{
|
|
||||||
strong: (children) => {
|
strong: (children) => {
|
||||||
return <strong>{children}</strong>
|
return <strong>{children}</strong>
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
t("curriculum-vitae.education.iut.years.2023-2024.courses.ci-cd"),
|
t("curriculum-vitae.education.iut.years.2023-2024.courses.ci-cd"),
|
||||||
t(
|
t("curriculum-vitae.education.iut.years.2023-2024.courses.complexity-algorithms"),
|
||||||
"curriculum-vitae.education.iut.years.2023-2024.courses.complexity-algorithms",
|
|
||||||
),
|
|
||||||
t("curriculum-vitae.education.iut.years.2023-2024.courses.no-sql"),
|
t("curriculum-vitae.education.iut.years.2023-2024.courses.no-sql"),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import { CurriculumVitaeSection } from "./CurriculumVitaeSection.tsx"
|
|||||||
|
|
||||||
export interface CurriculumVitaeInterestsProps {}
|
export interface CurriculumVitaeInterestsProps {}
|
||||||
|
|
||||||
export const CurriculumVitaeInterests: React.FC<
|
export const CurriculumVitaeInterests: React.FC<CurriculumVitaeInterestsProps> = () => {
|
||||||
CurriculumVitaeInterestsProps
|
|
||||||
> = () => {
|
|
||||||
const t = useTranslations()
|
const t = useTranslations()
|
||||||
|
|
||||||
const interests = [
|
const interests = [
|
||||||
@@ -16,22 +14,14 @@ export const CurriculumVitaeInterests: React.FC<
|
|||||||
},
|
},
|
||||||
"link-github": (children) => {
|
"link-github": (children) => {
|
||||||
return (
|
return (
|
||||||
<a
|
<a href="https://github.com/theoludwig" target="_blank" className="font-semibold">
|
||||||
href="https://github.com/theoludwig"
|
|
||||||
target="_blank"
|
|
||||||
className="font-semibold"
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
"link-leon": (children) => {
|
"link-leon": (children) => {
|
||||||
return (
|
return (
|
||||||
<a
|
<a href="https://github.com/leon-ai/leon" target="_blank" className="font-semibold">
|
||||||
href="https://github.com/leon-ai/leon"
|
|
||||||
target="_blank"
|
|
||||||
className="font-semibold"
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,9 +6,7 @@ import { Locales } from "../Layout/Header/Locales/Locales.tsx"
|
|||||||
|
|
||||||
export interface CurriculumVitaeProfileProps {}
|
export interface CurriculumVitaeProfileProps {}
|
||||||
|
|
||||||
export const CurriculumVitaeProfile: React.FC<
|
export const CurriculumVitaeProfile: React.FC<CurriculumVitaeProfileProps> = () => {
|
||||||
CurriculumVitaeProfileProps
|
|
||||||
> = () => {
|
|
||||||
const t = useTranslations()
|
const t = useTranslations()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -30,9 +28,7 @@ export const CurriculumVitaeProfile: React.FC<
|
|||||||
<h1 className="h3 my-1!">
|
<h1 className="h3 my-1!">
|
||||||
<strong>{t("meta.title")}</strong>
|
<strong>{t("meta.title")}</strong>
|
||||||
</h1>
|
</h1>
|
||||||
<h2 className="text-muted h5 font-semibold">
|
<h2 className="text-muted h5 font-semibold">{t("curriculum-vitae.description")}</h2>
|
||||||
{t("curriculum-vitae.description")}
|
|
||||||
</h2>
|
|
||||||
<h2 className="text-muted h5">
|
<h2 className="text-muted h5">
|
||||||
<BirthDate />
|
<BirthDate />
|
||||||
</h2>
|
</h2>
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ export interface CurriculumVitaeSectionProps extends React.PropsWithChildren {
|
|||||||
title: string
|
title: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CurriculumVitaeSection: React.FC<CurriculumVitaeSectionProps> = (
|
export const CurriculumVitaeSection: React.FC<CurriculumVitaeSectionProps> = (props) => {
|
||||||
props,
|
|
||||||
) => {
|
|
||||||
const { id, icon, title, children } = props
|
const { id, icon, title, children } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import { useTranslations } from "next-intl"
|
import { useTranslations } from "next-intl"
|
||||||
import { FaToolbox } from "react-icons/fa"
|
import { FaToolbox } from "react-icons/fa"
|
||||||
import {
|
import { SKILL_CATEGORIES, SKILL_NAMES_BY_CATEGORY } from "../Home/Skills/skills.ts"
|
||||||
SKILL_CATEGORIES,
|
|
||||||
SKILL_NAMES_BY_CATEGORY,
|
|
||||||
} from "../Home/Skills/skills.ts"
|
|
||||||
import { CurriculumVitaeSection } from "./CurriculumVitaeSection.tsx"
|
import { CurriculumVitaeSection } from "./CurriculumVitaeSection.tsx"
|
||||||
|
|
||||||
export interface CurriculumVitaeSkillsProps {}
|
export interface CurriculumVitaeSkillsProps {}
|
||||||
|
|
||||||
export const CurriculumVitaeSkills: React.FC<
|
export const CurriculumVitaeSkills: React.FC<CurriculumVitaeSkillsProps> = () => {
|
||||||
CurriculumVitaeSkillsProps
|
|
||||||
> = () => {
|
|
||||||
const t = useTranslations()
|
const t = useTranslations()
|
||||||
|
|
||||||
const skills = [
|
const skills = [
|
||||||
@@ -23,11 +18,7 @@ export const CurriculumVitaeSkills: React.FC<
|
|||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
category: "others",
|
category: "others",
|
||||||
skillNames: [
|
skillNames: [t("fr-FR-main"), t("locales.en-US"), t("home.skills.driving-license")],
|
||||||
t("fr-FR-main"),
|
|
||||||
t("locales.en-US"),
|
|
||||||
t("home.skills.driving-license"),
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
|
|||||||
@@ -136,10 +136,7 @@ export const LinkWithIcons: Story = {
|
|||||||
<Button leftIcon={<FaCheck size={18} />} {...(args as ButtonLinkProps)}>
|
<Button leftIcon={<FaCheck size={18} />} {...(args as ButtonLinkProps)}>
|
||||||
Link Left Icon
|
Link Left Icon
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button rightIcon={<FaCheck size={18} />} {...(args as ButtonLinkProps)}>
|
||||||
rightIcon={<FaCheck size={18} />}
|
|
||||||
{...(args as ButtonLinkProps)}
|
|
||||||
>
|
|
||||||
Link Right Icon
|
Link Right Icon
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonContainer>
|
</ButtonContainer>
|
||||||
|
|||||||
@@ -1,32 +1,37 @@
|
|||||||
import { classNames } from "@repo/config-tailwind/classNames"
|
import { classNames } from "@repo/config-tailwind/classNames"
|
||||||
import { Link as NextLink } from "@repo/i18n/routing"
|
import { Link as NextLink } from "@repo/i18n/routing"
|
||||||
import type { VariantProps } from "cva"
|
|
||||||
import { cva } from "cva"
|
|
||||||
|
|
||||||
import { Spinner } from "../Spinner/Spinner.tsx"
|
import { Spinner } from "../Spinner/Spinner.tsx"
|
||||||
import { Ripple } from "./Ripple.tsx"
|
import { Ripple } from "./Ripple.tsx"
|
||||||
|
|
||||||
const buttonVariants = cva({
|
const BUTTON_VARIANTS = ["solid", "outline"] as const
|
||||||
base: "relative inline-flex items-center justify-center overflow-hidden rounded-md text-base font-semibold transition duration-150 ease-in-out focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
type ButtonVariant = (typeof BUTTON_VARIANTS)[number]
|
||||||
variants: {
|
|
||||||
variant: {
|
const BUTTON_SIZES = ["small", "medium", "large"] as const
|
||||||
solid: "bg-primary hover:bg-primary/80 text-white",
|
type ButtonSize = (typeof BUTTON_SIZES)[number]
|
||||||
outline:
|
|
||||||
"dark:border-primary-dark/60 dark:text-primary-dark dark:hover:border-primary-dark border-primary/60 text-primary hover:border-primary hover:bg-primary border bg-transparent hover:text-white",
|
const buttonVariants = (options?: { variant?: ButtonVariant; size?: ButtonSize }): string => {
|
||||||
},
|
const { variant = "solid", size = "medium" } = options ?? {}
|
||||||
size: {
|
return classNames(
|
||||||
small: "h-9 rounded-md px-3",
|
"relative inline-flex items-center justify-center overflow-hidden rounded-md text-base font-semibold transition duration-150 ease-in-out focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
medium: "h-10 px-4 py-2",
|
{
|
||||||
large: "h-11 rounded-md px-8",
|
"bg-primary text-white hover:bg-primary/80": variant === "solid",
|
||||||
},
|
|
||||||
},
|
"border border-primary/60 bg-transparent text-primary hover:border-primary hover:bg-primary hover:text-white dark:border-primary-dark/60 dark:text-primary-dark dark:hover:border-primary-dark":
|
||||||
defaultVariants: {
|
variant === "outline",
|
||||||
variant: "solid",
|
},
|
||||||
size: "medium",
|
{
|
||||||
},
|
"h-9 rounded-md px-3": size === "small",
|
||||||
})
|
"h-10 px-4 py-2": size === "medium",
|
||||||
|
"h-11 rounded-md px-8": size === "large",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ButtonBaseProps {
|
||||||
|
variant?: ButtonVariant
|
||||||
|
size?: ButtonSize
|
||||||
|
|
||||||
interface ButtonBaseProps extends VariantProps<typeof buttonVariants> {
|
|
||||||
leftIcon?: React.ReactNode
|
leftIcon?: React.ReactNode
|
||||||
rightIcon?: React.ReactNode
|
rightIcon?: React.ReactNode
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
@@ -34,14 +39,10 @@ interface ButtonBaseProps extends VariantProps<typeof buttonVariants> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ButtonElementProps extends React.ComponentPropsWithoutRef<"button"> {}
|
interface ButtonElementProps extends React.ComponentPropsWithoutRef<"button"> {}
|
||||||
interface LinkElementProps extends React.ComponentPropsWithoutRef<
|
interface LinkElementProps extends React.ComponentPropsWithoutRef<typeof NextLink> {}
|
||||||
typeof NextLink
|
|
||||||
> {}
|
|
||||||
|
|
||||||
export type ButtonLinkProps = ButtonBaseProps &
|
export type ButtonLinkProps = ButtonBaseProps & LinkElementProps & { href: string }
|
||||||
LinkElementProps & { href: string }
|
export type ButtonButtonProps = ButtonBaseProps & ButtonElementProps & { href?: never }
|
||||||
export type ButtonButtonProps = ButtonBaseProps &
|
|
||||||
ButtonElementProps & { href?: never }
|
|
||||||
|
|
||||||
export type ButtonProps = ButtonButtonProps | ButtonLinkProps
|
export type ButtonProps = ButtonButtonProps | ButtonLinkProps
|
||||||
|
|
||||||
@@ -51,18 +52,13 @@ export type ButtonProps = ButtonButtonProps | ButtonLinkProps
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const Button: React.FC<ButtonProps> = (props) => {
|
export const Button: React.FC<ButtonProps> = (props) => {
|
||||||
const rippleColor =
|
const rippleColor = props.variant === "outline" ? "rgb(30, 64, 175)" : "rgb(229, 231, 235)"
|
||||||
props.variant === "outline" ? "rgb(30, 64, 175)" : "rgb(229, 231, 235)"
|
|
||||||
|
|
||||||
if (typeof props.href === "string") {
|
if (typeof props.href === "string") {
|
||||||
const { variant, size, leftIcon, rightIcon, className, children, ...rest } =
|
const { variant, size, leftIcon, rightIcon, className, children, ...rest } = props
|
||||||
props
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NextLink
|
<NextLink className={classNames(buttonVariants({ variant, size }), className)} {...rest}>
|
||||||
className={classNames(buttonVariants({ variant, size }), className)}
|
|
||||||
{...rest}
|
|
||||||
>
|
|
||||||
{leftIcon != null ? <span className="mr-2">{leftIcon}</span> : null}
|
{leftIcon != null ? <span className="mr-2">{leftIcon}</span> : null}
|
||||||
<span>{children}</span>
|
<span>{children}</span>
|
||||||
{rightIcon != null ? <span className="ml-2">{rightIcon}</span> : null}
|
{rightIcon != null ? <span className="ml-2">{rightIcon}</span> : null}
|
||||||
@@ -98,13 +94,9 @@ export const Button: React.FC<ButtonProps> = (props) => {
|
|||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
{leftIconElement != null ? (
|
{leftIconElement != null ? <span className="mr-2">{leftIconElement}</span> : null}
|
||||||
<span className="mr-2">{leftIconElement}</span>
|
|
||||||
) : null}
|
|
||||||
<span>{children}</span>
|
<span>{children}</span>
|
||||||
{rightIcon != null && !isLoading ? (
|
{rightIcon != null && !isLoading ? <span className="ml-2">{rightIcon}</span> : null}
|
||||||
<span className="ml-2">{rightIcon}</span>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<Ripple color={rippleColor} />
|
<Ripple color={rippleColor} />
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export const Link: React.FC<LinkProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<NextLink
|
<NextLink
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"text-primary dark:text-primary-dark inline-flex items-center gap-1 font-semibold hover:underline focus:rounded-md focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
|
"inline-flex items-center gap-1 font-semibold text-primary hover:underline focus:rounded-md focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none dark:text-primary-dark",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
target={target}
|
target={target}
|
||||||
@@ -25,11 +25,7 @@ export const Link: React.FC<LinkProps> = (props) => {
|
|||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
||||||
{target === "_blank" && isExternal ? (
|
{target === "_blank" && isExternal ? <FiExternalLink size={16} strokeWidth={2.5} /> : <></>}
|
||||||
<FiExternalLink size={16} strokeWidth={2.5} />
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
</NextLink>
|
</NextLink>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const Spinner: React.FC<SpinnerProps> = (props) => {
|
|||||||
height: size,
|
height: size,
|
||||||
}}
|
}}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"text-primary dark:text-primary-dark flex animate-spin rounded-full border-2 border-current border-t-transparent",
|
"flex animate-spin rounded-full border-2 border-current border-t-transparent text-primary dark:text-primary-dark",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
role="status"
|
role="status"
|
||||||
|
|||||||
@@ -67,8 +67,7 @@ export const Variants: Story = {
|
|||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography as="p" variant="text1">
|
<Typography as="p" variant="text1">
|
||||||
<abbr title="Cascading Style Sheets">CSS</abbr> (Abbreviation or
|
<abbr title="Cascading Style Sheets">CSS</abbr> (Abbreviation or Acronym)
|
||||||
Acronym)
|
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography as="p" variant="text1">
|
<Typography as="p" variant="text1">
|
||||||
@@ -76,8 +75,8 @@ export const Variants: Story = {
|
|||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography as="p" variant="text1">
|
<Typography as="p" variant="text1">
|
||||||
A <dfn id="def-validator">validator</dfn> is a program that checks for
|
A <dfn id="def-validator">validator</dfn> is a program that checks for syntax errors in
|
||||||
syntax errors in code or documents. (Definition)
|
code or documents. (Definition)
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography as="blockquote" variant="text1">
|
<Typography as="blockquote" variant="text1">
|
||||||
|
|||||||
@@ -1,26 +1,27 @@
|
|||||||
import { classNames } from "@repo/config-tailwind/classNames"
|
import { classNames } from "@repo/config-tailwind/classNames"
|
||||||
import type { VariantProps } from "cva"
|
|
||||||
import { cva } from "cva"
|
|
||||||
|
|
||||||
const typographyVariants = cva({
|
const TYPOGRAPHY_VARIANTS = ["h1", "h2", "h3", "h4", "h5", "h6", "text1", "text2"] as const
|
||||||
variants: {
|
type TypographyVariant = (typeof TYPOGRAPHY_VARIANTS)[number]
|
||||||
variant: {
|
|
||||||
h1: "text-primary dark:text-primary-dark text-4xl font-semibold",
|
const typographyVariants = (options?: { variant?: TypographyVariant }): string => {
|
||||||
h2: "text-primary dark:text-primary-dark text-3xl font-semibold",
|
const { variant = "text1" } = options ?? {}
|
||||||
h3: "text-primary dark:text-primary-dark text-2xl font-semibold",
|
return classNames({
|
||||||
h4: "text-primary dark:text-primary-dark text-xl font-semibold",
|
"text-4xl font-semibold text-primary dark:text-primary-dark": variant === "h1",
|
||||||
h5: "text-primary dark:text-primary-dark text-xl font-medium",
|
"text-3xl font-semibold text-primary dark:text-primary-dark": variant === "h2",
|
||||||
h6: "text-primary dark:text-primary-dark text-lg font-medium",
|
"text-2xl font-semibold text-primary dark:text-primary-dark": variant === "h3",
|
||||||
text1: "text-base break-words",
|
"text-xl font-semibold text-primary dark:text-primary-dark": variant === "h4",
|
||||||
text2: "text-sm break-words",
|
"text-xl font-medium text-primary dark:text-primary-dark": variant === "h5",
|
||||||
},
|
"text-lg font-medium text-primary dark:text-primary-dark": variant === "h6",
|
||||||
},
|
"text-base wrap-break-word": variant === "text1",
|
||||||
})
|
"text-sm wrap-break-word": variant === "text2",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export type TypographyProps<Component extends React.ElementType = "p"> = {
|
export type TypographyProps<Component extends React.ElementType = "p"> = {
|
||||||
as?: Component
|
as?: Component
|
||||||
} & React.ComponentPropsWithoutRef<Component> &
|
} & React.ComponentPropsWithoutRef<Component> & {
|
||||||
VariantProps<typeof typographyVariants>
|
variant?: TypographyVariant
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typography and styling abstraction component used to ensure consistency and standardize text throughout your application.
|
* Typography and styling abstraction component used to ensure consistency and standardize text throughout your application.
|
||||||
@@ -35,10 +36,7 @@ export const Typography = <Component extends React.ElementType = "p">(
|
|||||||
const ComponentAs = as
|
const ComponentAs = as
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ComponentAs
|
<ComponentAs className={classNames(typographyVariants({ variant }), className)} {...rest}>
|
||||||
className={classNames(typographyVariants({ variant }), className)}
|
|
||||||
{...rest}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</ComponentAs>
|
</ComponentAs>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ export const ErrorNotFound: React.FC<ErrorNotFoundProps> = () => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography variant="text1" as="p" className="mt-4">
|
<Typography variant="text1" as="p" className="mt-4">
|
||||||
{t("errors.page-doesnt-exist")}{" "}
|
{t("errors.page-doesnt-exist")} <Link href="/">{t("errors.return-to-home-page")}</Link>
|
||||||
<Link href="/">{t("errors.return-to-home-page")}</Link>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</Section>
|
</Section>
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const AboutDescription: React.FC<AboutDescriptionProps> = () => {
|
|||||||
const t = useTranslations()
|
const t = useTranslations()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dark:text-gray-lighter my-6 max-w-md text-center text-black">
|
<div className="my-6 max-w-md text-center text-black dark:text-gray-lighter">
|
||||||
<Typography as="p" variant="text1" className="my-6">
|
<Typography as="p" variant="text1" className="my-6">
|
||||||
{t.rich("home.about.description", {
|
{t.rich("home.about.description", {
|
||||||
strong: (children) => {
|
strong: (children) => {
|
||||||
|
|||||||
@@ -9,10 +9,8 @@ export const AboutItem: React.FC<AboutItemProps> = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="flex items-center justify-between sm:justify-start">
|
<li className="flex items-center justify-between sm:justify-start">
|
||||||
<strong className="w-24 text-sm text-black lg:w-32 dark:text-white">
|
<strong className="w-24 text-sm text-black lg:w-32 dark:text-white">{label}</strong>
|
||||||
{label}
|
<span className="block text-sm font-normal text-black dark:text-gray-lighter">
|
||||||
</strong>
|
|
||||||
<span className="dark:text-gray-lighter block text-sm font-normal text-black">
|
|
||||||
{link != null ? (
|
{link != null ? (
|
||||||
<a className="hover:underline" href={link}>
|
<a className="hover:underline" href={link}>
|
||||||
{value}
|
{value}
|
||||||
|
|||||||
@@ -9,14 +9,8 @@ export const AboutList: React.FC<AboutListProps> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ul className="my-6 list-none space-y-3">
|
<ul className="my-6 list-none space-y-3">
|
||||||
<AboutItem
|
<AboutItem label={t("home.about.pronouns.label")} value={t("home.about.pronouns.value")} />
|
||||||
label={t("home.about.pronouns.label")}
|
<AboutItem label={t("home.about.birth-date.label")} value={<BirthDate />} />
|
||||||
value={t("home.about.pronouns.value")}
|
|
||||||
/>
|
|
||||||
<AboutItem
|
|
||||||
label={t("home.about.birth-date.label")}
|
|
||||||
value={<BirthDate />}
|
|
||||||
/>
|
|
||||||
<AboutItem
|
<AboutItem
|
||||||
label={t("home.about.nationality.label")}
|
label={t("home.about.nationality.label")}
|
||||||
value={t("home.about.nationality.value")}
|
value={t("home.about.nationality.value")}
|
||||||
|
|||||||
@@ -8,13 +8,7 @@ export const AboutLogo: React.FC<AboutLogoProps> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-h-[370px] max-w-[370px] px-2 py-6">
|
<div className="max-h-[370px] max-w-[370px] px-2 py-6">
|
||||||
<Image
|
<Image src="/images/logo.webp" alt={t("meta.title")} width={800} height={800} priority />
|
||||||
src="/images/logo.webp"
|
|
||||||
alt={t("meta.title")}
|
|
||||||
width={800}
|
|
||||||
height={800}
|
|
||||||
priority
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ export const Icon: React.FC<React.SVGProps<SVGSVGElement>> = (props) => {
|
|||||||
<svg
|
<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
className={classNames(
|
className={classNames("size-8 fill-current text-black dark:text-white", className)}
|
||||||
"size-8 fill-current text-black dark:text-white",
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -24,24 +24,15 @@ export const SocialMediaList: React.FC<SocialMediaListProps> = () => {
|
|||||||
<NPMIcon />
|
<NPMIcon />
|
||||||
</SocialMediaItem>
|
</SocialMediaItem>
|
||||||
|
|
||||||
<SocialMediaItem
|
<SocialMediaItem link="https://twitter.com/theoludwig_" ariaLabel="X/Twitter">
|
||||||
link="https://twitter.com/theoludwig_"
|
|
||||||
ariaLabel="X/Twitter"
|
|
||||||
>
|
|
||||||
<TwitterIcon />
|
<TwitterIcon />
|
||||||
</SocialMediaItem>
|
</SocialMediaItem>
|
||||||
|
|
||||||
<SocialMediaItem
|
<SocialMediaItem link="https://www.youtube.com/@theo_ludwig" ariaLabel="YouTube">
|
||||||
link="https://www.youtube.com/@theo_ludwig"
|
|
||||||
ariaLabel="YouTube"
|
|
||||||
>
|
|
||||||
<YouTubeIcon />
|
<YouTubeIcon />
|
||||||
</SocialMediaItem>
|
</SocialMediaItem>
|
||||||
|
|
||||||
<SocialMediaItem
|
<SocialMediaItem link="https://www.twitch.tv/theoludwig" ariaLabel="Twitch">
|
||||||
link="https://www.twitch.tv/theoludwig"
|
|
||||||
ariaLabel="Twitch"
|
|
||||||
>
|
|
||||||
<TwitchIcon />
|
<TwitchIcon />
|
||||||
</SocialMediaItem>
|
</SocialMediaItem>
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,7 @@ export const InterestItem: React.FC<InterestItemProps> = (props) => {
|
|||||||
{title}
|
{title}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
<Typography
|
<Typography as="p" variant="text1" className="my-2 text-black dark:text-gray-lighter">
|
||||||
as="p"
|
|
||||||
variant="text1"
|
|
||||||
className="dark:text-gray-lighter my-2 text-black"
|
|
||||||
>
|
|
||||||
{description}
|
{description}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,11 +2,7 @@ import { GIT_REPO_LINK } from "@repo/utils/constants"
|
|||||||
import { useTranslations } from "next-intl"
|
import { useTranslations } from "next-intl"
|
||||||
import { FaGit, FaMicrochip } from "react-icons/fa"
|
import { FaGit, FaMicrochip } from "react-icons/fa"
|
||||||
import { Link } from "../../Design/Link/Link.tsx"
|
import { Link } from "../../Design/Link/Link.tsx"
|
||||||
import {
|
import { Section, SectionContent, SectionTitle } from "../../Layout/Section/Section.tsx"
|
||||||
Section,
|
|
||||||
SectionContent,
|
|
||||||
SectionTitle,
|
|
||||||
} from "../../Layout/Section/Section.tsx"
|
|
||||||
import { InterestItem } from "./InterestItem.tsx"
|
import { InterestItem } from "./InterestItem.tsx"
|
||||||
|
|
||||||
export interface InterestsProps {}
|
export interface InterestsProps {}
|
||||||
@@ -59,13 +55,7 @@ export const Interests: React.FC<InterestsProps> = () => {
|
|||||||
<SectionContent shadowContainer>
|
<SectionContent shadowContainer>
|
||||||
<div className="max-w-full">
|
<div className="max-w-full">
|
||||||
{items.map((item) => {
|
{items.map((item) => {
|
||||||
return (
|
return <InterestItem key={item.id} title={item.title} description={item.description} />
|
||||||
<InterestItem
|
|
||||||
key={item.id}
|
|
||||||
title={item.title}
|
|
||||||
description={item.description}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -74,7 +64,7 @@ export const Interests: React.FC<InterestsProps> = () => {
|
|||||||
{items.map((item) => {
|
{items.map((item) => {
|
||||||
return (
|
return (
|
||||||
<li className="m-2 size-8" key={item.id} title={item.title}>
|
<li className="m-2 size-8" key={item.id} title={item.title}>
|
||||||
<item.Icon className="text-primary dark:text-primary-dark block size-full" />
|
<item.Icon className="block size-full text-primary dark:text-primary-dark" />
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
import { useTranslations } from "next-intl"
|
import { useTranslations } from "next-intl"
|
||||||
import {
|
import { Section, SectionDescription, SectionTitle } from "../../Layout/Section/Section.tsx"
|
||||||
Section,
|
|
||||||
SectionDescription,
|
|
||||||
SectionTitle,
|
|
||||||
} from "../../Layout/Section/Section.tsx"
|
|
||||||
import { Repository } from "./Repository.tsx"
|
import { Repository } from "./Repository.tsx"
|
||||||
|
|
||||||
export interface OpenSourceProps {}
|
export interface OpenSourceProps {}
|
||||||
@@ -14,9 +10,7 @@ export const OpenSource: React.FC<OpenSourceProps> = () => {
|
|||||||
return (
|
return (
|
||||||
<Section verticalSpacing horizontalSpacing id="open-source">
|
<Section verticalSpacing horizontalSpacing id="open-source">
|
||||||
<SectionTitle>{t("home.open-source.title")}</SectionTitle>
|
<SectionTitle>{t("home.open-source.title")}</SectionTitle>
|
||||||
<SectionDescription>
|
<SectionDescription>{t("home.open-source.description")}</SectionDescription>
|
||||||
{t("home.open-source.description")}
|
|
||||||
</SectionDescription>
|
|
||||||
|
|
||||||
<div className="flex max-w-full flex-col items-center">
|
<div className="flex max-w-full flex-col items-center">
|
||||||
<ul className="grid list-none grid-cols-1 gap-6 md:w-10/12 md:grid-cols-2">
|
<ul className="grid list-none grid-cols-1 gap-6 md:w-10/12 md:grid-cols-2">
|
||||||
|
|||||||
@@ -20,9 +20,7 @@ export const Repository: React.FC<RepositoryProps> = (props) => {
|
|||||||
>
|
>
|
||||||
<Typography as="h3" variant="text1" className="flex items-center">
|
<Typography as="h3" variant="text1" className="flex items-center">
|
||||||
<GitHubIcon className="mr-2 h-6" />
|
<GitHubIcon className="mr-2 h-6" />
|
||||||
<span className="text-primary dark:text-primary-dark font-semibold">
|
<span className="font-semibold text-primary dark:text-primary-dark">{name}</span>
|
||||||
{name}
|
|
||||||
</span>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
<p className="mt-4">{description}</p>
|
<p className="mt-4">{description}</p>
|
||||||
</SectionContent>
|
</SectionContent>
|
||||||
|
|||||||
@@ -26,10 +26,7 @@ export const PortfolioItem: React.FC<PortfolioItemProps> = (props) => {
|
|||||||
href={link}
|
href={link}
|
||||||
aria-label={title}
|
aria-label={title}
|
||||||
>
|
>
|
||||||
<SectionContent
|
<SectionContent className="relative cursor-pointer items-center p-0 sm:p-0" shadowContainer>
|
||||||
className="relative cursor-pointer items-center p-0 sm:p-0"
|
|
||||||
shadowContainer
|
|
||||||
>
|
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<Image
|
<Image
|
||||||
className="size-[300px] rounded-xl transition-opacity duration-500 group-hover:opacity-15 dark:group-hover:opacity-5"
|
className="size-[300px] rounded-xl transition-opacity duration-500 group-hover:opacity-15 dark:group-hover:opacity-5"
|
||||||
|
|||||||
@@ -13,19 +13,14 @@ export const Footer: React.FC<FooterProps> = (props) => {
|
|||||||
const t = useTranslations()
|
const t = useTranslations()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className="bg-background dark:bg-background-dark border-gray-darker dark:border-gray-darker-dark flex flex-col items-center justify-center border-t-2 p-6 text-lg">
|
<footer className="flex flex-col items-center justify-center border-t-2 border-gray-darker bg-background p-6 text-lg dark:border-gray-darker-dark dark:bg-background-dark">
|
||||||
<p>
|
<p>
|
||||||
<Link href="/">{t("meta.title")}</Link> |{" "}
|
<Link href="/">{t("meta.title")}</Link> | {t("footer.all-rights-reserved")}
|
||||||
{t("footer.all-rights-reserved")}
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Version{" "}
|
Version{" "}
|
||||||
<Link
|
<Link href={`${GIT_REPO_LINK}/releases/tag/v${version}`} target="_blank" isExternal={false}>
|
||||||
href={`${GIT_REPO_LINK}/releases/tag/v${version}`}
|
|
||||||
target="_blank"
|
|
||||||
isExternal={false}
|
|
||||||
>
|
|
||||||
{version}
|
{version}
|
||||||
</Link>
|
</Link>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export const Header: React.FC<HeaderProps> = () => {
|
|||||||
const t = useTranslations()
|
const t = useTranslations()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="bg-background dark:bg-background-dark border-gray-darker dark:border-gray-darker-dark sticky top-0 z-50 flex w-full justify-between gap-4 border-b-2 px-6 py-2">
|
<header className="sticky top-0 z-50 flex w-full justify-between gap-4 border-b-2 border-gray-darker bg-background px-6 py-2 dark:border-gray-darker-dark dark:bg-background-dark">
|
||||||
<h1>
|
<h1>
|
||||||
<Link href="/" className="flex items-center justify-center">
|
<Link href="/" className="flex items-center justify-center">
|
||||||
<Image
|
<Image
|
||||||
@@ -21,9 +21,7 @@ export const Header: React.FC<HeaderProps> = () => {
|
|||||||
alt={`${t("meta.title")} Logo`}
|
alt={`${t("meta.title")} Logo`}
|
||||||
priority
|
priority
|
||||||
/>
|
/>
|
||||||
<strong className="ml-1 hidden sm:block sm:text-xl">
|
<strong className="ml-1 hidden sm:block sm:text-xl">{t("meta.title")}</strong>
|
||||||
{t("meta.title")}
|
|
||||||
</strong>
|
|
||||||
</Link>
|
</Link>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
export const Arrow: React.FC = () => {
|
export const Arrow: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg width="12" height="8" viewBox="0 0 12 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
width="12"
|
|
||||||
height="8"
|
|
||||||
viewBox="0 0 12 8"
|
|
||||||
fill="none"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
>
|
|
||||||
<path
|
<path
|
||||||
className="fill-current text-black dark:text-white"
|
className="fill-current text-black dark:text-white"
|
||||||
d="M9.8024 0.292969L5.61855 4.58597L1.43469 0.292969L0.0566406 1.70697L5.61855 7.41397L11.1805 1.70697L9.8024 0.292969Z"
|
d="M9.8024 0.292969L5.61855 4.58597L1.43469 0.292969L0.0566406 1.70697L5.61855 7.41397L11.1805 1.70697L9.8024 0.292969Z"
|
||||||
|
|||||||
@@ -17,11 +17,7 @@ export const Locales: React.FC<LocalesProps> = () => {
|
|||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
const localeCurrent = useLocale()
|
const localeCurrent = useLocale()
|
||||||
|
|
||||||
const {
|
const { value: isVisibleMenu, toggle: toggleMenu, setFalse: hideMenu } = useBoolean()
|
||||||
value: isVisibleMenu,
|
|
||||||
toggle: toggleMenu,
|
|
||||||
setFalse: hideMenu,
|
|
||||||
} = useBoolean()
|
|
||||||
const languageClickRef = useRef<HTMLButtonElement | null>(null)
|
const languageClickRef = useRef<HTMLButtonElement | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -47,18 +43,14 @@ export const Locales: React.FC<LocalesProps> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col items-center justify-center">
|
<div className="flex flex-col items-center justify-center">
|
||||||
<button
|
<button ref={languageClickRef} className="flex items-center" onClick={toggleMenu}>
|
||||||
ref={languageClickRef}
|
|
||||||
className="flex items-center"
|
|
||||||
onClick={toggleMenu}
|
|
||||||
>
|
|
||||||
<LocaleFlag locale={localeCurrent} />
|
<LocaleFlag locale={localeCurrent} />
|
||||||
<Arrow />
|
<Arrow />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<ul
|
<ul
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"shadow-lightFlag dark:shadow-darkFlag bg-background dark:bg-background-dark absolute top-14 z-10 mt-2 flex w-32 list-none flex-col items-center justify-center rounded-lg p-0",
|
"absolute top-14 z-10 mt-2 flex w-32 list-none flex-col items-center justify-center rounded-lg bg-background p-0 shadow-lightFlag dark:bg-background-dark dark:shadow-darkFlag",
|
||||||
{ hidden: !isVisibleMenu },
|
{ hidden: !isVisibleMenu },
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -3,10 +3,7 @@
|
|||||||
import { classNames } from "@repo/config-tailwind/classNames"
|
import { classNames } from "@repo/config-tailwind/classNames"
|
||||||
import type { Theme } from "@repo/utils/constants"
|
import type { Theme } from "@repo/utils/constants"
|
||||||
import { THEME_DEFAULT } from "@repo/utils/constants"
|
import { THEME_DEFAULT } from "@repo/utils/constants"
|
||||||
import {
|
import { ThemeProvider as NextThemeProvider, useTheme as useNextTheme } from "next-themes"
|
||||||
ThemeProvider as NextThemeProvider,
|
|
||||||
useTheme as useNextTheme,
|
|
||||||
} from "next-themes"
|
|
||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
export interface ThemeProviderProps extends React.PropsWithChildren {
|
export interface ThemeProviderProps extends React.PropsWithChildren {
|
||||||
@@ -38,7 +35,6 @@ export const useTheme = (): UseThemeOutput => {
|
|||||||
const [isMounted, setIsMounted] = useState(false)
|
const [isMounted, setIsMounted] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
||||||
setIsMounted(true)
|
setIsMounted(true)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@@ -73,9 +69,7 @@ export const SwitchTheme: React.FC<SwitchThemeProps> = () => {
|
|||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="relative flex size-[10px] items-center justify-center">
|
<span className="relative flex size-[10px] items-center justify-center">🌜</span>
|
||||||
🌜
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
@@ -86,9 +80,7 @@ export const SwitchTheme: React.FC<SwitchThemeProps> = () => {
|
|||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span className="relative flex size-[10px] items-center justify-center">
|
<span className="relative flex size-[10px] items-center justify-center">🌞</span>
|
||||||
🌞
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -9,8 +9,7 @@ export const RevealFade: React.FC<RevealFadeProps> = (props) => {
|
|||||||
|
|
||||||
const htmlElement = useRef<HTMLDivElement | null>(null)
|
const htmlElement = useRef<HTMLDivElement | null>(null)
|
||||||
|
|
||||||
const className =
|
const className = "opacity-100 visible translate-y-0 transition-all duration-700 ease-in-out"
|
||||||
"opacity-100 visible translate-y-0 transition-all duration-700 ease-in-out"
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const observer = new window.IntersectionObserver(
|
const observer = new window.IntersectionObserver(
|
||||||
|
|||||||
@@ -10,12 +10,7 @@ export interface SectionProps extends React.ComponentPropsWithoutRef<"section">
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Section: React.FC<SectionProps> = (props) => {
|
export const Section: React.FC<SectionProps> = (props) => {
|
||||||
const {
|
const { className, verticalSpacing = false, horizontalSpacing = false, ...rest } = props
|
||||||
className,
|
|
||||||
verticalSpacing = false,
|
|
||||||
horizontalSpacing = false,
|
|
||||||
...rest
|
|
||||||
} = props
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
@@ -48,9 +43,7 @@ export const SectionTitle: React.FC<SectionTitleProps> = (props) => {
|
|||||||
|
|
||||||
export interface SectionDescriptionProps extends TypographyProps<"p"> {}
|
export interface SectionDescriptionProps extends TypographyProps<"p"> {}
|
||||||
|
|
||||||
export const SectionDescription: React.FC<SectionDescriptionProps> = (
|
export const SectionDescription: React.FC<SectionDescriptionProps> = (props) => {
|
||||||
props,
|
|
||||||
) => {
|
|
||||||
const { className, ...rest } = props
|
const { className, ...rest } = props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -75,7 +68,7 @@ export const SectionContent: React.FC<SectionContentProps> = (props) => {
|
|||||||
className={classNames(
|
className={classNames(
|
||||||
"size-full max-w-full px-6 py-4 break-words sm:px-16",
|
"size-full max-w-full px-6 py-4 break-words sm:px-16",
|
||||||
{
|
{
|
||||||
"shadow-light dark:shadow-dark max-w-full rounded-2xl border border-solid border-black":
|
"max-w-full rounded-2xl border border-solid border-black shadow-light dark:shadow-dark":
|
||||||
shadowContainer,
|
shadowContainer,
|
||||||
},
|
},
|
||||||
className,
|
className,
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import typescriptESLint from "typescript-eslint"
|
|
||||||
import { defineConfig } from "eslint/config"
|
|
||||||
import config from "@repo/config-eslint"
|
|
||||||
|
|
||||||
export default defineConfig(...config, {
|
|
||||||
files: ["**/*.ts", "**/*.tsx"],
|
|
||||||
languageOptions: {
|
|
||||||
parser: typescriptESLint.parser,
|
|
||||||
parserOptions: {
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: import.meta.dirname,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -12,17 +12,13 @@
|
|||||||
"./urls": "./src/urls.ts"
|
"./urls": "./src/urls.ts"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint:eslint": "eslint src --max-warnings 0",
|
|
||||||
"lint:typescript": "tsc --noEmit",
|
"lint:typescript": "tsc --noEmit",
|
||||||
"test": "node --test"
|
"test": "node --test"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@repo/config-eslint": "workspace:*",
|
|
||||||
"@repo/config-typescript": "workspace:*",
|
"@repo/config-typescript": "workspace:*",
|
||||||
"@types/node": "catalog:",
|
|
||||||
"@total-typescript/ts-reset": "catalog:",
|
"@total-typescript/ts-reset": "catalog:",
|
||||||
"eslint": "catalog:",
|
"@types/node": "catalog:",
|
||||||
"typescript-eslint": "catalog:",
|
|
||||||
"typescript": "catalog:"
|
"typescript": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ export const TIMEZONE = process.env["TZ"] ?? "Europe/Paris"
|
|||||||
export const BIRTH_DATE_DAY = "31"
|
export const BIRTH_DATE_DAY = "31"
|
||||||
export const BIRTH_DATE_MONTH = "03"
|
export const BIRTH_DATE_MONTH = "03"
|
||||||
export const BIRTH_DATE_YEAR = "2003"
|
export const BIRTH_DATE_YEAR = "2003"
|
||||||
export const BIRTH_DATE_STRING =
|
export const BIRTH_DATE_STRING = `${BIRTH_DATE_DAY}/${BIRTH_DATE_MONTH}/${BIRTH_DATE_YEAR}` as const
|
||||||
`${BIRTH_DATE_DAY}/${BIRTH_DATE_MONTH}/${BIRTH_DATE_YEAR}` as const
|
|
||||||
export const BIRTH_DATE_ISO_8601 =
|
export const BIRTH_DATE_ISO_8601 =
|
||||||
`${BIRTH_DATE_YEAR}-${BIRTH_DATE_MONTH}-${BIRTH_DATE_DAY}` as const
|
`${BIRTH_DATE_YEAR}-${BIRTH_DATE_MONTH}-${BIRTH_DATE_DAY}` as const
|
||||||
export const BIRTH_DATE = new Date(BIRTH_DATE_ISO_8601)
|
export const BIRTH_DATE = new Date(BIRTH_DATE_ISO_8601)
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
export const deepMerge = <
|
export const deepMerge = <Object1 extends object, Object2 extends object = Object1>(
|
||||||
Object1 extends object,
|
|
||||||
Object2 extends object = Object1,
|
|
||||||
>(
|
|
||||||
object1: Object1,
|
object1: Object1,
|
||||||
object2: Object2,
|
object2: Object2,
|
||||||
): Object1 & Object2 => {
|
): Object1 & Object2 => {
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
* Matches any [primitive value](https://developer.mozilla.org/en-US/docs/Glossary/Primitive).
|
||||||
*/
|
*/
|
||||||
export type Primitive =
|
export type Primitive = null | undefined | string | number | boolean | symbol | bigint
|
||||||
| null
|
|
||||||
| undefined
|
|
||||||
| string
|
|
||||||
| number
|
|
||||||
| boolean
|
|
||||||
| symbol
|
|
||||||
| bigint
|
|
||||||
|
|
||||||
export type Satisfies<U, T extends U> = T
|
export type Satisfies<U, T extends U> = T
|
||||||
|
|
||||||
|
|||||||
5770
pnpm-lock.yaml
generated
5770
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -7,30 +7,35 @@ catalogMode: "strict"
|
|||||||
|
|
||||||
catalog:
|
catalog:
|
||||||
# Turborepo
|
# Turborepo
|
||||||
"turbo": "2.6.3"
|
"turbo": "2.8.9"
|
||||||
|
|
||||||
# TypeScript
|
# TypeScript/Linting
|
||||||
"typescript": "5.9.3"
|
"typescript": "5.9.3"
|
||||||
|
"@types/node": "25.2.3"
|
||||||
"@total-typescript/ts-reset": "0.6.1"
|
"@total-typescript/ts-reset": "0.6.1"
|
||||||
"@types/node": "24.10.3"
|
"oxlint": "1.47.0"
|
||||||
|
"oxlint-tsgolint": "0.12.2"
|
||||||
|
"oxfmt": "0.32.0"
|
||||||
|
"eslint-config-conventions": "21.2.0"
|
||||||
|
"editorconfig-checker": "6.1.1"
|
||||||
|
|
||||||
# Utils
|
# Utils
|
||||||
"mime": "4.1.0"
|
"mime": "4.1.0"
|
||||||
|
|
||||||
# React.js/Next.js
|
# React.js/Next.js
|
||||||
"next": &next "16.0.10"
|
"next": "16.1.6"
|
||||||
"next-intl": "4.6.0"
|
"next-intl": "4.8.3"
|
||||||
"next-themes": "0.4.6"
|
"next-themes": "0.4.6"
|
||||||
"react": "19.2.3"
|
"react": "19.2.4"
|
||||||
"react-dom": "19.2.3"
|
"react-dom": "19.2.4"
|
||||||
"@types/react": "19.2.7"
|
"@types/react": "19.2.14"
|
||||||
"@types/react-dom": "19.2.3"
|
"@types/react-dom": "19.2.3"
|
||||||
"react-icons": "5.5.0"
|
"react-icons": "5.5.0"
|
||||||
|
|
||||||
# Blog
|
# Blog
|
||||||
"@giscus/react": "3.1.0"
|
"@giscus/react": "3.1.0"
|
||||||
"gray-matter": "4.0.3"
|
"gray-matter": "4.0.3"
|
||||||
"katex": "0.16.27"
|
"katex": "0.16.28"
|
||||||
"next-mdx-remote": "5.0.0"
|
"next-mdx-remote": "5.0.0"
|
||||||
"@mdx-js/mdx": "3.1.1"
|
"@mdx-js/mdx": "3.1.1"
|
||||||
"rehype-katex": "7.0.1"
|
"rehype-katex": "7.0.1"
|
||||||
@@ -42,39 +47,22 @@ catalog:
|
|||||||
"@shikijs/rehype": "1.24.0"
|
"@shikijs/rehype": "1.24.0"
|
||||||
|
|
||||||
# Markdown Lint
|
# Markdown Lint
|
||||||
"markdownlint-cli2": "0.20.0"
|
"markdownlint-cli2": "0.21.0"
|
||||||
"markdownlint": "0.40.0"
|
"markdownlint": "0.40.0"
|
||||||
"markdownlint-rule-relative-links": "4.2.0"
|
"markdownlint-rule-relative-links": "5.0.1"
|
||||||
|
|
||||||
# ESLint
|
|
||||||
"globals": "16.5.0"
|
|
||||||
"typescript-eslint": "8.49.0"
|
|
||||||
"eslint": "9.39.1"
|
|
||||||
"eslint-config-conventions": "21.1.1"
|
|
||||||
"eslint-plugin-promise": "7.2.1"
|
|
||||||
"eslint-plugin-unicorn": "62.0.0"
|
|
||||||
"eslint-plugin-import-x": "4.16.1"
|
|
||||||
"@next/eslint-plugin-next": *next
|
|
||||||
"eslint-plugin-react": "7.37.5"
|
|
||||||
"eslint-plugin-react-hooks": "7.0.1"
|
|
||||||
|
|
||||||
# Prettier
|
|
||||||
"prettier": "3.7.4"
|
|
||||||
"prettier-plugin-tailwindcss": "0.7.2"
|
|
||||||
"editorconfig-checker": "6.1.1"
|
|
||||||
|
|
||||||
# Storybook
|
# Storybook
|
||||||
"storybook": &storybook "10.1.8"
|
"storybook": &storybook "10.2.8"
|
||||||
"@storybook/addon-docs": *storybook
|
"@storybook/addon-docs": *storybook
|
||||||
"@storybook/addon-a11y": *storybook
|
"@storybook/addon-a11y": *storybook
|
||||||
"@storybook/nextjs": *storybook
|
"@storybook/nextjs": *storybook
|
||||||
"@storybook/addon-themes": *storybook
|
"@storybook/addon-themes": *storybook
|
||||||
"@storybook/test-runner": "0.24.2"
|
"@storybook/test-runner": "0.24.2"
|
||||||
"@chromatic-com/storybook": "4.1.3"
|
"@chromatic-com/storybook": "5.0.1"
|
||||||
"chromatic": "13.3.4"
|
"chromatic": "15.1.0"
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
"playwright": &playwright "1.57.0"
|
"playwright": &playwright "1.58.2"
|
||||||
"@playwright/test": *playwright
|
"@playwright/test": *playwright
|
||||||
"start-server-and-test": "2.1.3"
|
"start-server-and-test": "2.1.3"
|
||||||
|
|
||||||
@@ -83,20 +71,14 @@ catalog:
|
|||||||
"@tailwindcss/postcss": "4.1.18"
|
"@tailwindcss/postcss": "4.1.18"
|
||||||
"@tailwindcss/typography": "0.5.19"
|
"@tailwindcss/typography": "0.5.19"
|
||||||
"tailwindcss": "4.1.18"
|
"tailwindcss": "4.1.18"
|
||||||
"tailwind-merge": "3.4.0"
|
"tailwind-merge": "3.4.1"
|
||||||
"clsx": "2.1.1"
|
"clsx": "2.1.1"
|
||||||
"cva": "1.0.0-beta.4"
|
|
||||||
"@fontsource/montserrat": "5.2.8"
|
"@fontsource/montserrat": "5.2.8"
|
||||||
|
|
||||||
onlyBuiltDependencies:
|
allowBuilds:
|
||||||
- "@swc/core"
|
"@swc/core": true
|
||||||
- "@tailwindcss/oxide"
|
"@parcel/watcher": true
|
||||||
- "core-js-pure"
|
"sharp": true
|
||||||
- "esbuild"
|
"unrs-resolver": true
|
||||||
- "sharp"
|
"core-js-pure": true
|
||||||
- "unrs-resolver"
|
"esbuild": true
|
||||||
- "@parcel/watcher"
|
|
||||||
|
|
||||||
publicHoistPattern:
|
|
||||||
- "*eslint*"
|
|
||||||
- "*prettier*"
|
|
||||||
|
|||||||
16
turbo.json
16
turbo.json
@@ -7,23 +7,12 @@
|
|||||||
"inputs": ["$TURBO_DEFAULT$", ".env*"],
|
"inputs": ["$TURBO_DEFAULT$", ".env*"],
|
||||||
"env": ["IS_STANDALONE"],
|
"env": ["IS_STANDALONE"],
|
||||||
"dependsOn": ["^build"],
|
"dependsOn": ["^build"],
|
||||||
"outputs": [
|
"outputs": ["build/**", "storybook-static/**", ".next/**", "!.next/cache/**"]
|
||||||
"build/**",
|
|
||||||
"storybook-static/**",
|
|
||||||
".next/**",
|
|
||||||
"!.next/cache/**"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"test": {
|
"test": {
|
||||||
"dependsOn": ["^test"],
|
"dependsOn": ["^test"],
|
||||||
"outputs": []
|
"outputs": []
|
||||||
},
|
},
|
||||||
"lint:eslint-transit-node": {
|
|
||||||
"dependsOn": ["^lint:eslint-transit-node"]
|
|
||||||
},
|
|
||||||
"lint:eslint": {
|
|
||||||
"dependsOn": ["lint:eslint-transit-node"]
|
|
||||||
},
|
|
||||||
"lint:typescript-transit-node": {
|
"lint:typescript-transit-node": {
|
||||||
"dependsOn": ["^lint:typescript-transit-node"]
|
"dependsOn": ["^lint:typescript-transit-node"]
|
||||||
},
|
},
|
||||||
@@ -32,7 +21,8 @@
|
|||||||
},
|
},
|
||||||
"typegen": {
|
"typegen": {
|
||||||
"dependsOn": ["^typegen"],
|
"dependsOn": ["^typegen"],
|
||||||
"outputs": []
|
"outputs": [],
|
||||||
|
"cache": false
|
||||||
},
|
},
|
||||||
"dev": {
|
"dev": {
|
||||||
"cache": false,
|
"cache": false,
|
||||||
|
|||||||
Reference in New Issue
Block a user