1
1
mirror of https://github.com/theoludwig/theoludwig.git synced 2024-12-08 00:44:30 +01:00

Compare commits

...

2 Commits

Author SHA1 Message Date
59153a7a69
style: fix ESLint 2024-10-13 00:00:44 +02:00
0a7094005c
chore: config updates 2024-10-12 23:51:58 +02:00
37 changed files with 2798 additions and 2710 deletions

View File

@ -1 +1,2 @@
TZ=UTC
WEBSITE_PORT=3000 WEBSITE_PORT=3000

View File

@ -11,14 +11,14 @@ jobs:
timeout-minutes: 30 timeout-minutes: 30
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
steps: steps:
- uses: "actions/checkout@v4.1.7" - uses: "actions/checkout@v4.2.1"
with: with:
fetch-depth: 0 fetch-depth: 0
- uses: "pnpm/action-setup@v4.0.0" - uses: "pnpm/action-setup@v4.0.0"
- name: "Setup Node.js" - name: "Setup Node.js"
uses: "actions/setup-node@v4.0.3" uses: "actions/setup-node@v4.0.4"
with: with:
node-version: "22.x" node-version: "22.x"
cache: "pnpm" cache: "pnpm"

View File

@ -11,12 +11,12 @@ jobs:
timeout-minutes: 30 timeout-minutes: 30
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
steps: steps:
- uses: "actions/checkout@v4.1.7" - uses: "actions/checkout@v4.2.1"
- uses: "pnpm/action-setup@v4.0.0" - uses: "pnpm/action-setup@v4.0.0"
- name: "Setup Node.js" - name: "Setup Node.js"
uses: "actions/setup-node@v4.0.3" uses: "actions/setup-node@v4.0.4"
with: with:
node-version: "22.x" node-version: "22.x"
cache: "pnpm" cache: "pnpm"
@ -29,15 +29,15 @@ 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:prettier"
- run: "node --run lint:eslint"
- run: "node --run lint:typescript" - run: "node --run lint:typescript"
- run: "node --run lint:eslint"
- run: "node --run lint:prettier"
- run: "node --run test" - run: "node --run test"
- run: "node --run build" - run: "node --run build"
commitlint: commitlint:
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
steps: steps:
- uses: "actions/checkout@v4.1.7" - uses: "actions/checkout@v4.2.1"
- uses: "wagoid/commitlint-github-action@v6.1.2" - uses: "wagoid/commitlint-github-action@v6.1.2"

View File

@ -14,7 +14,7 @@ jobs:
pull-requests: "write" pull-requests: "write"
id-token: "write" id-token: "write"
steps: steps:
- uses: "actions/checkout@v4.1.7" - uses: "actions/checkout@v4.2.1"
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
@ -29,7 +29,7 @@ jobs:
- uses: "pnpm/action-setup@v4.0.0" - uses: "pnpm/action-setup@v4.0.0"
- name: "Setup Node.js" - name: "Setup Node.js"
uses: "actions/setup-node@v4.0.3" uses: "actions/setup-node@v4.0.4"
with: with:
node-version: "22.x" node-version: "22.x"
cache: "pnpm" cache: "pnpm"

1
.npmrc
View File

@ -1 +0,0 @@
save-exact = true

View File

@ -3,9 +3,11 @@
"editorconfig.editorconfig", "editorconfig.editorconfig",
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"dbaeumer.vscode-eslint", "dbaeumer.vscode-eslint",
"davidanson.vscode-markdownlint",
"bradlc.vscode-tailwindcss", "bradlc.vscode-tailwindcss",
"mikestead.dotenv", "mikestead.dotenv",
"davidanson.vscode-markdownlint", "ms-azuretools.vscode-docker",
"ms-azuretools.vscode-docker" "antfu.pnpm-catalog-lens",
"Lokalise.i18n-ally"
] ]
} }

View File

@ -16,5 +16,12 @@
"tailwindCSS.experimental.classRegex": [ "tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"], ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"] ["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
] ],
"i18n-ally.localesPaths": ["./packages/i18n/src/translations/"],
"i18n-ally.keystyle": "nested",
"i18n-ally.sortKeys": true,
"i18n-ally.sourceLanguage": "en-US",
"i18n-ally.displayLanguage": "en-US",
"i18n-ally.enabledFrameworks": ["next-intl", "general"],
"i18n-ally.extract.autoDetect": true
} }

View File

@ -32,7 +32,8 @@ The commit message guidelines adheres to [Conventional Commits](https://www.conv
### Prerequisites ### Prerequisites
- [Node.js](https://nodejs.org/) >= 22.0.0 - [Node.js](https://nodejs.org/) >= 22.0.0
- [pnpm](https://pnpm.io/) >= 9.10.0 - [pnpm](https://pnpm.io/) >= 9.12.1 [(`corepack enable`)](https://nodejs.org/docs/latest-v22.x/api/corepack.html)
- [Docker](https://www.docker.com/)
### Installation ### Installation
@ -63,15 +64,19 @@ node --run dev
# Lint # Lint
node --run lint:editorconfig node --run lint:editorconfig
node --run lint:markdown node --run lint:markdown
node --run lint:prettier
node --run lint:eslint
node --run lint:typescript node --run lint:typescript
node --run lint:eslint
node --run lint:prettier
# Tests # Tests
node --run test node --run test
# Build # Build
node --run build node --run build
# To execute a command in a specific package (e.g: packages/utils)
cd packages/utils
node --run test
``` ```
### Production environment with [Docker](https://www.docker.com/) ### Production environment with [Docker](https://www.docker.com/)

View File

@ -7,7 +7,11 @@ const config: StorybookConfig = {
docs: { docs: {
defaultName: "Documentation", defaultName: "Documentation",
}, },
stories: ["../../../packages/**/*.stories.tsx", "../stories/*.mdx"], stories: [
"../../../packages/ui/src/**/*.stories.tsx",
"../../../packages/blog/src/**/*.stories.tsx",
"../stories/*.mdx",
],
addons: [ addons: [
"@storybook/addon-essentials", "@storybook/addon-essentials",
"@storybook/addon-storysource", "@storybook/addon-storysource",

View File

@ -1,7 +1,7 @@
import "@repo/config-tailwind/styles.css" import "@repo/config-tailwind/styles.css"
import { defaultTranslationValues } from "@repo/i18n/config" import { defaultTranslationValues } from "@repo/i18n/config"
import i18nMessagesEnglish from "@repo/i18n/translations/en-US.json" import i18nMessagesEnglish from "@repo/i18n/translations/en-US.json"
import type { Locale } from "@repo/utils/constants" import { LOCALE_DEFAULT } from "@repo/utils/constants"
import type { Preview } from "@storybook/react" import type { Preview } from "@storybook/react"
import { NextIntlClientProvider } from "next-intl" import { NextIntlClientProvider } from "next-intl"
import { ThemeProvider as NextThemeProvider } from "next-themes" import { ThemeProvider as NextThemeProvider } from "next-themes"
@ -25,6 +25,7 @@ const preview: Preview = {
stylePreview: true, stylePreview: true,
}, },
controls: { controls: {
disableSaveFromUI: true,
matchers: { matchers: {
color: /(background|color)$/i, color: /(background|color)$/i,
date: /Date$/i, date: /Date$/i,
@ -33,14 +34,13 @@ const preview: Preview = {
}, },
decorators: [ decorators: [
(Story) => { (Story) => {
const locale = "en-US" satisfies Locale
return ( return (
<NextThemeProvider enableColorScheme={false}> <NextThemeProvider enableColorScheme={false}>
<NextIntlClientProvider <NextIntlClientProvider
messages={i18nMessagesEnglish} messages={i18nMessagesEnglish}
locale={locale} locale={LOCALE_DEFAULT}
defaultTranslationValues={defaultTranslationValues} defaultTranslationValues={defaultTranslationValues}
timeZone={process.env["TZ"] ?? "UTC"}
> >
<Story /> <Story />
</NextIntlClientProvider> </NextIntlClientProvider>

View File

@ -7,9 +7,9 @@
"build": "storybook build", "build": "storybook build",
"dev": "storybook dev --port 6006 --no-open", "dev": "storybook dev --port 6006 --no-open",
"start": "http-server \"storybook-static\" --port 6006 --silent", "start": "http-server \"storybook-static\" --port 6006 --silent",
"test": "start-server-and-test \"dev\" http://127.0.0.1:6006 \"test:storybook\"", "test": "start-server-and-test \"start\" http://127.0.0.1:6006 \"test:storybook\"",
"test:storybook": "test-storybook", "test:dev": "start-server-and-test \"dev\" http://127.0.0.1:6006 \"test:storybook\"",
"test:storybook-coverage": "test-storybook --coverage", "test:storybook": "test-storybook --testTimeout=60000 --maxWorkers=2",
"chromatic": "chromatic" "chromatic": "chromatic"
}, },
"dependencies": { "dependencies": {

View File

@ -2,7 +2,11 @@ import sharedConfig from "@repo/config-tailwind"
/** @type {Pick<import('tailwindcss').Config, "presets" | "content">} */ /** @type {Pick<import('tailwindcss').Config, "presets" | "content">} */
const config = { const config = {
content: [".storybook/preview.tsx", "../../packages/*/src/**/*.tsx"], content: [
".storybook/preview.tsx",
"../../packages/ui/src/**/*.tsx",
"../../packages/blog/src/**/*.tsx",
],
presets: [sharedConfig], presets: [sharedConfig],
} }

View File

@ -0,0 +1,9 @@
{
"$schema": "https://turbo.build/schema.json",
"extends": ["//"],
"tasks": {
"test": {
"dependsOn": ["^test", "build"]
}
}
}

View File

@ -7,7 +7,7 @@
"plugins": ["@typescript-eslint"], "plugins": ["@typescript-eslint"],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"project": true "projectService": true
} }
} }
] ]

View File

@ -8,7 +8,7 @@ WORKDIR /usr/src/app
FROM node-pnpm AS builder FROM node-pnpm AS builder
COPY ./ ./ COPY ./ ./
RUN pnpm install --global turbo@2.1.1 RUN pnpm install --global turbo@2.1.3
RUN turbo prune @repo/website --docker RUN turbo prune @repo/website --docker
FROM node-pnpm AS installer FROM node-pnpm AS installer

View File

@ -1,6 +1,6 @@
import { getBlogPosts } from "@repo/blog" import { getBlogPosts } from "@repo/blog"
import { BlogPosts } from "@repo/blog/BlogPosts" import { BlogPosts } from "@repo/blog/BlogPosts"
import { type LocaleProps } from "@repo/i18n/config" import type { LocaleProps } from "@repo/i18n/config"
import { MainLayout } from "@repo/ui/Layout/MainLayout" import { MainLayout } from "@repo/ui/Layout/MainLayout"
import { import {
Section, Section,

View File

@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information. // see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.

View File

@ -5,6 +5,10 @@ const IS_STANDALONE = process.env.IS_STANDALONE === "true"
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
output: IS_STANDALONE ? "standalone" : undefined, output: IS_STANDALONE ? "standalone" : undefined,
images: {
unoptimized: true,
},
compress: false,
// https://github.com/hashicorp/next-mdx-remote/issues/436#issuecomment-2066971842 // https://github.com/hashicorp/next-mdx-remote/issues/436#issuecomment-2066971842
transpilePackages: ["next-mdx-remote", "shiki"], transpilePackages: ["next-mdx-remote", "shiki"],

View File

@ -22,8 +22,7 @@
"next": "catalog:", "next": "catalog:",
"next-intl": "catalog:", "next-intl": "catalog:",
"react": "catalog:", "react": "catalog:",
"react-dom": "catalog:", "react-dom": "catalog:"
"sharp": "catalog:"
}, },
"devDependencies": { "devDependencies": {
"@repo/eslint-config": "workspace:*", "@repo/eslint-config": "workspace:*",

View File

@ -2,7 +2,11 @@ import sharedConfig from "@repo/config-tailwind"
/** @type {Pick<import('tailwindcss').Config, "presets" | "content">} */ /** @type {Pick<import('tailwindcss').Config, "presets" | "content">} */
const config = { const config = {
content: ["./app/**/*.tsx", "../../packages/*/src/**/*.tsx"], content: [
"./app/**/*.tsx",
"../../packages/ui/src/**/*.tsx",
"../../packages/blog/src/**/*.tsx",
],
presets: [sharedConfig], presets: [sharedConfig],
} }

View File

@ -3,10 +3,10 @@
"version": "4.0.0", "version": "4.0.0",
"private": true, "private": true,
"type": "module", "type": "module",
"packageManager": "pnpm@9.10.0+sha512.73a29afa36a0d092ece5271de5177ecbf8318d454ecd701343131b8ebc0c1a91c487da46ab77c8e596d6acf1461e3594ced4becedf8921b074fbd8653ed7051c", "packageManager": "pnpm@9.12.1+sha512.e5a7e52a4183a02d5931057f7a0dbff9d5e9ce3161e33fa68ae392125b79282a8a8a470a51dfc8a0ed86221442eb2fb57019b0990ed24fab519bf0e1bc5ccfc4",
"engines": { "engines": {
"node": ">=22.0.0", "node": ">=22.0.0",
"pnpm": ">=9.10.0" "pnpm": ">=9.12.1"
}, },
"scripts": { "scripts": {
"build": "turbo run build", "build": "turbo run build",
@ -15,25 +15,25 @@
"test": "turbo run test", "test": "turbo run test",
"lint:editorconfig": "editorconfig-checker", "lint:editorconfig": "editorconfig-checker",
"lint:markdown": "markdownlint-cli2", "lint:markdown": "markdownlint-cli2",
"lint:prettier": "prettier . --check",
"lint:eslint": "turbo run lint:eslint",
"lint:typescript": "turbo run lint:typescript", "lint:typescript": "turbo run lint:typescript",
"lint:eslint": "turbo run lint:eslint",
"lint:prettier": "prettier . --check",
"release": "semantic-release" "release": "semantic-release"
}, },
"devDependencies": { "devDependencies": {
"@saithodev/semantic-release-backmerge": "4.0.1", "@saithodev/semantic-release-backmerge": "catalog:",
"@semantic-release/exec": "6.0.3", "@semantic-release/exec": "catalog:",
"@semantic-release/git": "10.0.1", "@semantic-release/git": "catalog:",
"editorconfig-checker": "5.1.8", "editorconfig-checker": "catalog:",
"playwright": "catalog:", "playwright": "catalog:",
"prettier": "3.3.3", "prettier": "catalog:",
"prettier-plugin-tailwindcss": "0.6.6", "prettier-plugin-tailwindcss": "catalog:",
"markdownlint-cli2": "0.14.0", "markdownlint-cli2": "catalog:",
"markdownlint": "0.35.0", "markdownlint": "catalog:",
"markdownlint-rule-relative-links": "3.0.0", "markdownlint-rule-relative-links": "catalog:",
"replace-in-files-cli": "3.0.0", "replace-in-files-cli": "catalog:",
"semantic-release": "23.1.1", "semantic-release": "catalog:",
"turbo": "2.1.1", "turbo": "catalog:",
"typescript": "catalog:" "typescript": "catalog:"
} }
} }

View File

@ -7,7 +7,7 @@
"plugins": ["@typescript-eslint"], "plugins": ["@typescript-eslint"],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"project": true "projectService": true
} }
} }
] ]

View File

@ -20,6 +20,7 @@
"js": "never", "js": "never",
"jsx": "never" "jsx": "never"
} }
] ],
"import-x/consistent-type-specifier-style": ["error", "prefer-top-level"]
} }
} }

View File

@ -7,7 +7,7 @@
"plugins": ["@typescript-eslint"], "plugins": ["@typescript-eslint"],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"project": true "projectService": true
} }
} }
] ]

View File

@ -8,7 +8,6 @@
"noImplicitReturns": true, "noImplicitReturns": true,
"noImplicitThis": true, "noImplicitThis": true,
"noImplicitAny": true, "noImplicitAny": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true, "noUncheckedIndexedAccess": true,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,

View File

@ -7,7 +7,7 @@
"plugins": ["@typescript-eslint"], "plugins": ["@typescript-eslint"],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"project": true "projectService": true
} }
} }
] ]

View File

@ -1,162 +1,162 @@
{ {
"meta": {
"title": "Théo LUDWIG",
"description": "Developer Full Stack • Open-Source Enthusiast"
},
"locales": {
"en-US": "English",
"fr-FR": "French"
},
"footer": {
"all-rights-reserved": "All rights reserved"
},
"errors": {
"error": "Error",
"page-doesnt-exist": "This page doesn't exist!",
"not-found": "Not Found",
"server-error": "Internal Server Error!",
"return-to-home-page": "Return to the home page?",
"try-again": "Try again?"
},
"home": {
"about": {
"pronouns": {
"label": "Pronouns",
"value": "He/Him"
},
"birth-date": {
"label": "Birth date",
"value": "{birthDate} ({age} years old)"
},
"nationality": {
"label": "Nationality",
"value": "Alsace, France"
},
"email": {
"label": "Email",
"value": "{email}"
},
"description": "I constantly wonder how to <strong>improve our present, to make our future better</strong>, particularly thanks to the advancements in <strong>computer science</strong>."
},
"interests": {
"title": "Interests",
"code": {
"title": "Developer Full Stack",
"description": "My priority is to craft <strong>intuitive user experiences (<abbr-ux>UX</abbr-ux>)</strong>, that meet the needs of the users <strong>in the most efficient way possible</strong>. <br></br> Mainly focused on the development of <strong>Web solutions</strong>. <br></br> I am also interested in mobile and desktop application development, among other areas within the field of computer science."
},
"open-source": {
"title": "Open-Source Enthusiast",
"description": "I value the <strong>sharing of knowledge and collaboration</strong> to collectively resolve problems. <br></br> The source code of the website is available on <github-link>GitHub</github-link>."
}
},
"skills": {
"title": "Skills",
"programming-languages": "Programming languages",
"frontend": "Frontend",
"backend": "Backend",
"software-tools": "Software and tools",
"others": "Others",
"driving-license": "Driving license"
},
"portfolio": {
"title": "Portfolio",
"carolo": {
"title": "Carolo",
"description": "Strategy board game similar to chess which allows grandiose moves (only available in French)."
},
"leon": {
"title": "Leon",
"description": "Leon is your open-source personal assistant."
}
},
"open-source": {
"title": "Open-Source",
"description": "Most famous open source projects I contributed to."
}
},
"curriculum-vitae": { "curriculum-vitae": {
"description": "Developer Full Stack • Student",
"about": { "about": {
"title": "About", "description": "I constantly wonder how to improve our present, to make our future better, particularly thanks to the advancements in computer science. <br></br> My priority is to craft intuitive user experiences (UX), that meet the needs of the users in the most efficient way possible.",
"description": "I constantly wonder how to improve our present, to make our future better, particularly thanks to the advancements in computer science. <br></br> My priority is to craft intuitive user experiences (UX), that meet the needs of the users in the most efficient way possible." "title": "About"
}, },
"description": "Developer Full Stack • Student",
"education": { "education": {
"title": "Studies",
"cnam": { "cnam": {
"study-type": "Engineer in Computer Science and Information Systems (IS)",
"institution": "Conservatoire National des Arts et Métiers (CNAM), in Eckbolsheim - UIMM Alsace - ITII Alsace", "institution": "Conservatoire National des Arts et Métiers (CNAM), in Eckbolsheim - UIMM Alsace - ITII Alsace",
"study-type": "Engineer in Computer Science and Information Systems (IS)",
"years": { "years": {
"2024-2025": { "2024-2025": {
"title": "2024 - 2025", "courses": {},
"description": "1st year", "description": "1st year",
"courses": {} "title": "2024 - 2025"
} }
} }
}, },
"iut": { "iut": {
"study-type": "University Bachelor of Technology (BUT) Computer Science",
"institution": "IUT Robert Schuman in Illkirch-Graffenstaden", "institution": "IUT Robert Schuman in Illkirch-Graffenstaden",
"study-type": "University Bachelor of Technology (BUT) Computer Science",
"years": { "years": {
"2023-2024": {
"title": "2023 - 2024",
"description": "3rd year",
"courses": {
"web": "Web development in Node.js and React.js",
"ci-cd": "Continuous Integration/Deployment (CI/CD) and Docker",
"complexity-algorithms": "Theoretical and Practical Algorithmic Complexity in C++",
"no-sql": "NoSQL database (Redis, MongoDB, Cassandra)"
}
},
"2022-2023": {
"title": "2022 - 2023",
"description": "2nd year",
"courses": {
"web": "Web development with the Laravel framework in PHP",
"tests": "Development Quality and Automated Testing",
"clean-code": "Design Patterns and Principles (Maintainable and Reusable Code) in UML",
"systems-c": "Systems programming in C (Multi-Thread, Server/Client UDP/TCP)",
"sql-security": "Securing database access and PL/SQL"
}
},
"2021-2022": { "2021-2022": {
"title": "2021 - 2022",
"description": "1st year",
"courses": { "courses": {
"java": "Object Oriented Development in Java", "java": "Object Oriented Development in Java",
"sql": "Relational database and SQL language",
"systems-c": "Systems programming in C (Memory allocation, Pointers, Structures)", "systems-c": "Systems programming in C (Memory allocation, Pointers, Structures)",
"windows-forms": "Windows Forms (.NET Framework) Application Development in C#", "windows-forms": "Windows Forms (.NET Framework) Application Development in C#"
"sql": "Relational database and SQL language" },
} "description": "1st year",
"title": "2021 - 2022"
},
"2022-2023": {
"courses": {
"clean-code": "Design Patterns and Principles (Maintainable and Reusable Code) in UML",
"sql-security": "Securing database access and PL/SQL",
"systems-c": "Systems programming in C (Multi-Thread, Server/Client UDP/TCP)",
"tests": "Development Quality and Automated Testing",
"web": "Web development with the Laravel framework in PHP"
},
"description": "2nd year",
"title": "2022 - 2023"
},
"2023-2024": {
"courses": {
"ci-cd": "Continuous Integration/Deployment (CI/CD) and Docker",
"complexity-algorithms": "Theoretical and Practical Algorithmic Complexity in C++",
"no-sql": "NoSQL database (Redis, MongoDB, Cassandra)",
"web": "Web development in Node.js and React.js"
},
"description": "3rd year",
"title": "2023 - 2024"
} }
} }
}, },
"lycee": { "lycee": {
"study-type": "General Baccalaureate (Mathematics and Computer Science)",
"institution": "Heinrich Nessel High School in Haguenau", "institution": "Heinrich Nessel High School in Haguenau",
"score": "Mention Quite Good", "score": "Mention Quite Good",
"study-type": "General Baccalaureate (Mathematics and Computer Science)",
"years": { "years": {
"2019-2021": { "2019-2021": {
"title": "2019 - 2021" "title": "2019 - 2021"
} }
} }
} },
"title": "Studies"
},
"interests": {
"high-tech": "Passionate about High-Tech",
"open-source": "Open-Source Enthusiast"
}, },
"work": { "work": {
"title": "Work experiences",
"ircad": { "ircad": {
"summary": "Development of WebSurg, a virtual university dedicated to medical-surgical training, in React.js/Next.js and API Platform with Symfony.", "duration": "4 ans",
"position": "Full Stack Web Developer Apprentice", "position": "Full Stack Web Developer Apprentice",
"duration": "4 ans" "summary": "Development of WebSurg, a virtual university dedicated to medical-surgical training, in React.js/Next.js and API Platform with Symfony."
}, },
"numerize": { "numerize": {
"summary": "Development of an DMS (Document Management System) tool in React.js, Laravel and GraphQL.", "duration": "4 months",
"position": "Full Stack Web Developer Intern", "position": "Full Stack Web Developer Intern",
"duration": "4 months" "summary": "Development of an DMS (Document Management System) tool in React.js, Laravel and GraphQL."
},
"title": "Work experiences"
}
},
"errors": {
"error": "Error",
"not-found": "Not Found",
"page-doesnt-exist": "This page doesn't exist!",
"return-to-home-page": "Return to the home page?",
"server-error": "Internal Server Error!",
"try-again": "Try again?"
},
"footer": {
"all-rights-reserved": "All rights reserved"
},
"home": {
"about": {
"birth-date": {
"label": "Birth date",
"value": "{birthDate} ({age} years old)"
},
"description": "I constantly wonder how to <strong>improve our present, to make our future better</strong>, particularly thanks to the advancements in <strong>computer science</strong>.",
"email": {
"label": "Email",
"value": "{email}"
},
"nationality": {
"label": "Nationality",
"value": "Alsace, France"
},
"pronouns": {
"label": "Pronouns",
"value": "He/Him"
} }
}, },
"interests": { "interests": {
"open-source": "Open-Source Enthusiast", "code": {
"high-tech": "Passionate about High-Tech" "description": "My priority is to craft <strong>intuitive user experiences (<abbr-ux>UX</abbr-ux>)</strong>, that meet the needs of the users <strong>in the most efficient way possible</strong>. <br></br> Mainly focused on the development of <strong>Web solutions</strong>. <br></br> I am also interested in mobile and desktop application development, among other areas within the field of computer science.",
"title": "Developer Full Stack"
},
"open-source": {
"description": "I value the <strong>sharing of knowledge and collaboration</strong> to collectively resolve problems. <br></br> The source code of the website is available on <github-link>GitHub</github-link>.",
"title": "Open-Source Enthusiast"
},
"title": "Interests"
},
"open-source": {
"description": "Most famous open source projects I contributed to.",
"title": "Open-Source"
},
"portfolio": {
"carolo": {
"description": "Strategy board game similar to chess which allows grandiose moves (only available in French).",
"title": "Carolo"
},
"leon": {
"description": "Leon is your open-source personal assistant.",
"title": "Leon"
},
"title": "Portfolio"
},
"skills": {
"backend": "Backend",
"driving-license": "Driving license",
"frontend": "Frontend",
"others": "Others",
"programming-languages": "Programming languages",
"software-tools": "Software and tools",
"title": "Skills"
} }
},
"locales": {
"en-US": "English",
"fr-FR": "French"
},
"meta": {
"description": "Developer Full Stack • Open-Source Enthusiast",
"title": "Théo LUDWIG"
} }
} }

View File

@ -1,162 +1,162 @@
{ {
"meta": {
"title": "Théo LUDWIG",
"description": "Développeur Full Stack • Enthousiaste de l'Open-Source"
},
"locales": {
"en-US": "Anglais",
"fr-FR": "Français"
},
"footer": {
"all-rights-reserved": "Tous droits réservés"
},
"errors": {
"error": "Erreur",
"page-doesnt-exist": "Cette page n'existe pas !",
"not-found": "Introuvable",
"server-error": "Erreur interne du serveur !",
"return-to-home-page": "Retour à la page d'accueil ?",
"try-again": "Réessayer ?"
},
"home": {
"about": {
"pronouns": {
"label": "Pronoms",
"value": "Il/Lui"
},
"birth-date": {
"label": "Date de naissance",
"value": "{birthDate} ({age} ans)"
},
"nationality": {
"label": "Nationalité",
"value": "Alsace, France"
},
"email": {
"label": "Email",
"value": "{email}"
},
"description": "Je me demande constamment comment <strong>améliorer notre présent, afin de rendre notre futur meilleur</strong>, particulièrement grâce aux progrès de <strong>l'informatique</strong>."
},
"interests": {
"title": "Intérêts",
"code": {
"title": "Développeur Full Stack",
"description": "Ma priorité réside dans la création <strong>d'expériences utilisateurs (<abbr-ux>UX</abbr-ux>) intuitives</strong>, répondant aux besoins des utilisateurs de la <strong>manière la plus efficace que possible</strong>. <br></br> Principalement axé sur l'élaboration de <strong>solutions en Développement Web</strong>. <br></br> Je suis également intéressé par le développement d'applications mobiles parmis d'autres domaines de l'informatique."
},
"open-source": {
"title": "Enthousiaste de l'Open-Source",
"description": "J'apprécie le <strong>partage des connaissances et la collaboration</strong> pour résoudre des défis collectivement. <br></br> Le code source du site est accessible sur <github-link>GitHub</github-link>."
}
},
"skills": {
"title": "Compétences",
"programming-languages": "Langages de programmation",
"frontend": "Frontend",
"backend": "Backend",
"software-tools": "Logiciels et outils",
"others": "Autres",
"driving-license": "Permis B"
},
"portfolio": {
"title": "Portfolio",
"carolo": {
"title": "Carolo",
"description": "Jeu de plateau stratégique similaire aux échecs qui permet des coups grandioses, reposant sur des enchaînements remarquables."
},
"leon": {
"title": "Leon",
"description": "Leon est votre assistant personnel open source."
}
},
"open-source": {
"title": "Open-Source",
"description": "Projets open source les plus célèbres auxquels j'ai contribué."
}
},
"curriculum-vitae": { "curriculum-vitae": {
"description": "Développeur Full Stack • Étudiant",
"about": { "about": {
"title": "À propos", "description": "Je me demande constamment comment améliorer notre présent, afin de rendre notre futur meilleur, particulièrement grâce aux progrès de l'informatique. <br></br> Ma priorité réside dans la création d'expériences utilisateurs (UX) intuitives, répondant aux besoins des utilisateurs de la manière la plus efficace que possible.",
"description": "Je me demande constamment comment améliorer notre présent, afin de rendre notre futur meilleur, particulièrement grâce aux progrès de l'informatique. <br></br> Ma priorité réside dans la création d'expériences utilisateurs (UX) intuitives, répondant aux besoins des utilisateurs de la manière la plus efficace que possible." "title": "À propos"
}, },
"description": "Développeur Full Stack • Étudiant",
"education": { "education": {
"title": "Études",
"cnam": { "cnam": {
"study-type": "Ingénieur en Informatique et Systèmes d'Information (SI)",
"institution": "Conservatoire National des Arts et Métiers (CNAM) à Eckbolsheim - UIMM Alsace - ITII Alsace", "institution": "Conservatoire National des Arts et Métiers (CNAM) à Eckbolsheim - UIMM Alsace - ITII Alsace",
"study-type": "Ingénieur en Informatique et Systèmes d'Information (SI)",
"years": { "years": {
"2024-2025": { "2024-2025": {
"title": "2024 - 2025", "courses": {},
"description": "1ère année", "description": "1ère année",
"courses": {} "title": "2024 - 2025"
} }
} }
}, },
"iut": { "iut": {
"study-type": "Bachelor Universitaire de Technologie (BUT) Informatique",
"institution": "IUT Robert Schuman à Illkirch-Graffenstaden", "institution": "IUT Robert Schuman à Illkirch-Graffenstaden",
"study-type": "Bachelor Universitaire de Technologie (BUT) Informatique",
"years": { "years": {
"2023-2024": {
"title": "2023 - 2024",
"description": "3ème année",
"courses": {
"web": "Développement Web en Node.js et React.js",
"ci-cd": "Intégration/Déploiement Continue et Docker",
"complexity-algorithms": "Complexité Algorithmique Théorique et Pratique en C++",
"no-sql": "Base de données NoSQL (Redis, MongoDB, Cassandra)"
}
},
"2022-2023": {
"title": "2022 - 2023",
"description": "2ème année",
"courses": {
"web": "Développement Web avec le framework Laravel en PHP",
"tests": "Qualité de développement et Tests automatisés",
"clean-code": "Patrons et Principes de conceptions (Code maintenable et réutilisable) en UML",
"systems-c": "Programmation systèmes en C (Multi-Thread, Serveur/Client UDP/TCP)",
"sql-security": "Sécurisation des accès à la base de données et PL/SQL"
}
},
"2021-2022": { "2021-2022": {
"title": "2021 - 2022",
"description": "1ère année",
"courses": { "courses": {
"java": "Développement Orientée Objet en Java", "java": "Développement Orientée Objet en Java",
"sql": "Base de données relationnelles et langage SQL",
"systems-c": "Programmation systèmes en C (Allocation mémoire, Pointeurs, Structures)", "systems-c": "Programmation systèmes en C (Allocation mémoire, Pointeurs, Structures)",
"windows-forms": "Développement d'application Windows Forms (.NET Framework) en C#", "windows-forms": "Développement d'application Windows Forms (.NET Framework) en C#"
"sql": "Base de données relationnelles et langage SQL" },
} "description": "1ère année",
"title": "2021 - 2022"
},
"2022-2023": {
"courses": {
"clean-code": "Patrons et Principes de conceptions (Code maintenable et réutilisable) en UML",
"sql-security": "Sécurisation des accès à la base de données et PL/SQL",
"systems-c": "Programmation systèmes en C (Multi-Thread, Serveur/Client UDP/TCP)",
"tests": "Qualité de développement et Tests automatisés",
"web": "Développement Web avec le framework Laravel en PHP"
},
"description": "2ème année",
"title": "2022 - 2023"
},
"2023-2024": {
"courses": {
"ci-cd": "Intégration/Déploiement Continue et Docker",
"complexity-algorithms": "Complexité Algorithmique Théorique et Pratique en C++",
"no-sql": "Base de données NoSQL (Redis, MongoDB, Cassandra)",
"web": "Développement Web en Node.js et React.js"
},
"description": "3ème année",
"title": "2023 - 2024"
} }
} }
}, },
"lycee": { "lycee": {
"study-type": "Baccalauréat Général (Mathématiques et Numériques Sciences Informatiques)",
"institution": "Lycée Heinrich Nessel à Haguenau", "institution": "Lycée Heinrich Nessel à Haguenau",
"score": "Mention Assez Bien", "score": "Mention Assez Bien",
"study-type": "Baccalauréat Général (Mathématiques et Numériques Sciences Informatiques)",
"years": { "years": {
"2019-2021": { "2019-2021": {
"title": "2019 - 2021" "title": "2019 - 2021"
} }
} }
} },
"title": "Études"
},
"interests": {
"high-tech": "Passionné de High-Tech",
"open-source": "Enthousiaste de l'Open-Source"
}, },
"work": { "work": {
"title": "Expériences professionnelles",
"ircad": { "ircad": {
"summary": "Développement de WebSurg, une université virtuelle consacrée à la formation médico-chirurgicale, en React.js/Next.js et API Platform avec Symfony.", "duration": "4 ans",
"position": "Apprenti Développeur Web Full Stack", "position": "Apprenti Développeur Web Full Stack",
"duration": "4 ans" "summary": "Développement de WebSurg, une université virtuelle consacrée à la formation médico-chirurgicale, en React.js/Next.js et API Platform avec Symfony."
}, },
"numerize": { "numerize": {
"summary": "Développement d'un outil GED (Gestion Électronique de Documents) en React.js, Laravel et GraphQL.", "duration": "4 mois",
"position": "Stagiaire Développeur Web Full Stack", "position": "Stagiaire Développeur Web Full Stack",
"duration": "4 mois" "summary": "Développement d'un outil GED (Gestion Électronique de Documents) en React.js, Laravel et GraphQL."
},
"title": "Expériences professionnelles"
}
},
"errors": {
"error": "Erreur",
"not-found": "Introuvable",
"page-doesnt-exist": "Cette page n'existe pas !",
"return-to-home-page": "Retour à la page d'accueil ?",
"server-error": "Erreur interne du serveur !",
"try-again": "Réessayer ?"
},
"footer": {
"all-rights-reserved": "Tous droits réservés"
},
"home": {
"about": {
"birth-date": {
"label": "Date de naissance",
"value": "{birthDate} ({age} ans)"
},
"description": "Je me demande constamment comment <strong>améliorer notre présent, afin de rendre notre futur meilleur</strong>, particulièrement grâce aux progrès de <strong>l'informatique</strong>.",
"email": {
"label": "Email",
"value": "{email}"
},
"nationality": {
"label": "Nationalité",
"value": "Alsace, France"
},
"pronouns": {
"label": "Pronoms",
"value": "Il/Lui"
} }
}, },
"interests": { "interests": {
"open-source": "Enthousiaste de l'Open-Source", "code": {
"high-tech": "Passionné de High-Tech" "description": "Ma priorité réside dans la création <strong>d'expériences utilisateurs (<abbr-ux>UX</abbr-ux>) intuitives</strong>, répondant aux besoins des utilisateurs de la <strong>manière la plus efficace que possible</strong>. <br></br> Principalement axé sur l'élaboration de <strong>solutions en Développement Web</strong>. <br></br> Je suis également intéressé par le développement d'applications mobiles parmis d'autres domaines de l'informatique.",
"title": "Développeur Full Stack"
},
"open-source": {
"description": "J'apprécie le <strong>partage des connaissances et la collaboration</strong> pour résoudre des défis collectivement. <br></br> Le code source du site est accessible sur <github-link>GitHub</github-link>.",
"title": "Enthousiaste de l'Open-Source"
},
"title": "Intérêts"
},
"open-source": {
"description": "Projets open source les plus célèbres auxquels j'ai contribué.",
"title": "Open-Source"
},
"portfolio": {
"carolo": {
"description": "Jeu de plateau stratégique similaire aux échecs qui permet des coups grandioses, reposant sur des enchaînements remarquables.",
"title": "Carolo"
},
"leon": {
"description": "Leon est votre assistant personnel open source.",
"title": "Leon"
},
"title": "Portfolio"
},
"skills": {
"backend": "Backend",
"driving-license": "Permis B",
"frontend": "Frontend",
"others": "Autres",
"programming-languages": "Langages de programmation",
"software-tools": "Logiciels et outils",
"title": "Compétences"
} }
},
"locales": {
"en-US": "Anglais",
"fr-FR": "Français"
},
"meta": {
"description": "Développeur Full Stack • Enthousiaste de l'Open-Source",
"title": "Théo LUDWIG"
} }
} }

View File

@ -7,7 +7,7 @@
"plugins": ["@typescript-eslint"], "plugins": ["@typescript-eslint"],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"project": true "projectService": true
} }
} }
] ]

View File

@ -7,7 +7,7 @@
"plugins": ["@typescript-eslint"], "plugins": ["@typescript-eslint"],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"project": true "projectService": true
} }
} }
] ]

View File

@ -1,7 +1,8 @@
"use client" "use client"
import { useRouter } from "@repo/i18n/navigation"
import { useTranslations } from "next-intl" import { useTranslations } from "next-intl"
import { useEffect } from "react" import { useEffect, useTransition } from "react"
import { Button } from "../../Design/Button/Button.tsx" import { Button } from "../../Design/Button/Button.tsx"
import { Typography } from "../../Design/Typography/Typography.tsx" import { Typography } from "../../Design/Typography/Typography.tsx"
import { MainLayout } from "../../Layout/MainLayout/MainLayout.tsx" import { MainLayout } from "../../Layout/MainLayout/MainLayout.tsx"
@ -15,6 +16,9 @@ export interface ErrorServerProps {
export const ErrorServer: React.FC<ErrorServerProps> = (props) => { export const ErrorServer: React.FC<ErrorServerProps> = (props) => {
const { error, reset } = props const { error, reset } = props
const [isPending, startTransition] = useTransition()
const router = useRouter()
const t = useTranslations() const t = useTranslations()
useEffect(() => { useEffect(() => {
@ -29,7 +33,17 @@ export const ErrorServer: React.FC<ErrorServerProps> = (props) => {
</Typography> </Typography>
<Typography variant="text1" as="p" className="mt-4"> <Typography variant="text1" as="p" className="mt-4">
<Button onClick={reset}>{t("errors.try-again")}</Button> <Button
isLoading={isPending}
onClick={() => {
startTransition(() => {
router.refresh()
reset()
})
}}
>
{t("errors.try-again")}
</Button>
</Typography> </Typography>
</Section> </Section>
</MainLayout> </MainLayout>

View File

@ -1,6 +1,7 @@
import { useTranslations } from "next-intl" import { useTranslations } from "next-intl"
import { Section, SectionTitle } from "../../Layout/Section/Section.tsx" import { Section, SectionTitle } from "../../Layout/Section/Section.tsx"
import { PortfolioItem, type PortfolioProject } from "./PortfolioItem.tsx" import type { PortfolioProject } from "./PortfolioItem.tsx"
import { PortfolioItem } from "./PortfolioItem.tsx"
export interface PortfolioProps {} export interface PortfolioProps {}

View File

@ -33,7 +33,7 @@ export const PortfolioItem: React.FC<PortfolioItemProps> = (props) => {
<div className="flex justify-center"> <div className="flex justify-center">
<Image <Image
quality={100} quality={100}
className="size-auto transition-opacity duration-500 group-hover:opacity-20 dark:group-hover:opacity-5" className="size-[300px] transition-opacity duration-500 group-hover:opacity-20 dark:group-hover:opacity-5"
width={300} width={300}
height={300} height={300}
src={image} src={image}

View File

@ -7,7 +7,7 @@
"plugins": ["@typescript-eslint"], "plugins": ["@typescript-eslint"],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"project": true "projectService": true
} }
} }
] ]

4754
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -3,19 +3,26 @@ packages:
- "packages/*" - "packages/*"
catalog: catalog:
# Turborepo and Releases
"turbo": "2.1.3"
"@saithodev/semantic-release-backmerge": "4.0.1"
"@semantic-release/exec": "6.0.3"
"@semantic-release/git": "10.0.1"
"semantic-release": "23.1.1"
"replace-in-files-cli": "3.0.0"
# Utils # Utils
"deepmerge": "4.3.1" "deepmerge": "4.3.1"
# React.js/Next.js # React.js/Next.js
"next": "14.2.7" "next": "14.2.15"
"next-intl": "3.19.1" "next-intl": "3.21.1"
"next-themes": "0.3.0" "next-themes": "0.3.0"
"react": "18.3.1" "react": "18.3.1"
"react-dom": "18.3.1" "react-dom": "18.3.1"
"react-icons": "5.3.0" "react-icons": "5.3.0"
"@types/react": "18.3.5" "@types/react": "18.3.11"
"@types/react-dom": "18.3.0" "@types/react-dom": "18.3.1"
"sharp": "0.33.5"
# Blog # Blog
"@giscus/react": "3.0.0" "@giscus/react": "3.0.0"
@ -28,60 +35,70 @@ catalog:
"rehype-slug": "6.0.0" "rehype-slug": "6.0.0"
"remark-gfm": "4.0.0" "remark-gfm": "4.0.0"
"remark-math": "6.0.0" "remark-math": "6.0.0"
"shiki": "1.17.0" "shiki": "1.22.0"
"@shikijs/rehype": "1.17.0" "@shikijs/rehype": "1.22.0"
# TypeScript # TypeScript
"typescript": "5.5.4" "typescript": "5.5.4"
"@total-typescript/ts-reset": "0.6.1" "@total-typescript/ts-reset": "0.6.1"
"@types/node": "22.5.4" "@types/node": "22.7.5"
# ESLint # ESLint
"@typescript-eslint/eslint-plugin": "7.18.0" "@typescript-eslint/eslint-plugin": "8.8.1"
"@typescript-eslint/parser": "7.18.0" "@typescript-eslint/parser": "8.8.1"
"eslint": "8.57.0" "eslint": "8.57.1"
"eslint-config-conventions": "14.4.0" "eslint-config-conventions": "16.0.1"
"eslint-plugin-promise": "7.1.0" "eslint-plugin-promise": "7.1.0"
"eslint-plugin-unicorn": "55.0.0" "eslint-plugin-unicorn": "55.0.0"
"eslint-config-next": "14.2.7" "eslint-config-next": "14.2.15"
"eslint-plugin-storybook": "0.8.0" "eslint-plugin-storybook": "0.9.0"
"eslint-plugin-tailwindcss": "3.17.4" "eslint-plugin-tailwindcss": "3.17.5"
"eslint-plugin-import-x": "3.1.0" "eslint-plugin-import-x": "4.3.1"
# Prettier
"prettier": "3.3.3"
"prettier-plugin-tailwindcss": "0.6.8"
"editorconfig-checker": "6.0.0"
# Markdown Lint
"markdownlint-cli2": "0.14.0"
"markdownlint": "0.35.0"
"markdownlint-rule-relative-links": "3.0.0"
# Storybook # Storybook
"@chromatic-com/storybook": "2.0.1" "@chromatic-com/storybook": "2.0.2"
"@storybook/addon-a11y": "8.3.0" "@storybook/addon-a11y": "8.3.5"
"@storybook/addon-essentials": "8.3.0" "@storybook/addon-essentials": "8.3.5"
"@storybook/addon-interactions": "8.3.0" "@storybook/addon-interactions": "8.3.5"
"@storybook/addon-links": "8.3.0" "@storybook/addon-links": "8.3.5"
"@storybook/addon-storysource": "8.3.0" "@storybook/addon-storysource": "8.3.5"
"@storybook/addon-themes": "8.3.0" "@storybook/addon-themes": "8.3.5"
"@storybook/blocks": "8.3.0" "@storybook/blocks": "8.3.5"
"@storybook/nextjs": "8.3.0" "@storybook/nextjs": "8.3.5"
"@storybook/react": "8.3.0" "@storybook/react": "8.3.5"
"@storybook/test": "8.3.0" "@storybook/test": "8.3.5"
"@storybook/test-runner": "0.19.1" "@storybook/test-runner": "0.19.1"
"chromatic": "11.9.0" "chromatic": "11.12.5"
"http-server": "14.1.1" "http-server": "14.1.1"
"storybook": "8.3.0" "storybook": "8.3.5"
"storybook-dark-mode": "4.0.2" "storybook-dark-mode": "4.0.2"
# Testing # Testing
"playwright": "1.47.0" "playwright": "1.48.0"
"@playwright/test": "1.47.0" "@playwright/test": "1.48.0"
"axe-playwright": "2.0.2" "axe-playwright": "2.0.3"
"start-server-and-test": "2.0.7" "start-server-and-test": "2.0.8"
"@vitest/browser": "2.0.5" "@vitest/browser": "2.1.2"
"@vitest/coverage-istanbul": "2.0.5" "@vitest/coverage-istanbul": "2.1.2"
"@vitest/ui": "2.0.5" "@vitest/ui": "2.1.2"
"vitest": "2.0.5" "vitest": "2.1.2"
"@testing-library/react": "16.0.1" "@testing-library/react": "16.0.1"
# CSS # CSS
"postcss": "8.4.45" "postcss": "8.4.47"
"tailwindcss": "3.4.11" "tailwindcss": "3.4.13"
"tailwind-merge": "2.5.3"
"@tailwindcss/typography": "0.5.15" "@tailwindcss/typography": "0.5.15"
"@fontsource/montserrat": "5.0.20" "@fontsource/montserrat": "5.1.0"
"clsx": "2.1.0" "clsx": "2.1.0"
"cva": "1.0.0-beta.1" "cva": "1.0.0-beta.1"
"tailwind-merge": "2.5.2"

View File

@ -17,11 +17,17 @@
"dependsOn": ["^test"], "dependsOn": ["^test"],
"outputs": ["coverage/**"] "outputs": ["coverage/**"]
}, },
"lint:eslint-transit-node": {
"dependsOn": ["^lint:eslint-transit-node"]
},
"lint:eslint": { "lint:eslint": {
"dependsOn": ["^lint:eslint"] "dependsOn": ["lint:eslint-transit-node"]
},
"lint:typescript-transit-node": {
"dependsOn": ["^lint:typescript-transit-node"]
}, },
"lint:typescript": { "lint:typescript": {
"dependsOn": ["^lint:typescript"] "dependsOn": ["lint:typescript-transit-node"]
}, },
"dev": { "dev": {
"cache": false, "cache": false,