From c9a8b3eaa5d539ed217d45096fc7ff356f2abab9 Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Thu, 24 Apr 2025 10:42:16 -0400 Subject: [PATCH] initial tailwind conversion --- .devcontainer/devcontainer.json | 11 +- .npmrc | 1 - .prettierrc.mjs | 7 +- .stylelintrc.mjs | 19 - .vscode/extensions.json | 8 + .vscode/settings.json | 16 + app/contact/form.tsx | 2 +- app/fonts.ts | 4 +- app/globals.css | 155 ++- app/layout.module.css | 26 - app/layout.tsx | 27 +- app/notes/[slug]/page.tsx | 11 +- app/page.module.css | 84 -- app/page.tsx | 169 +-- app/projects/page.module.css | 94 -- app/projects/page.tsx | 86 +- app/zip/page.tsx | 4 +- components/Blockquote/Blockquote.module.css | 6 - components/Blockquote/Blockquote.tsx | 6 +- components/Footer/Footer.module.css | 88 -- components/Footer/Footer.tsx | 31 +- components/Header/Header.module.css | 83 -- components/Header/Header.tsx | 30 +- components/HeadingAnchor/HeadingAnchor.tsx | 2 +- components/Link/Link.module.css | 25 - components/Link/Link.tsx | 15 +- components/Menu/Menu.module.css | 36 - components/Menu/Menu.tsx | 16 +- components/MenuItem/MenuItem.module.css | 43 - components/MenuItem/MenuItem.tsx | 16 +- components/PageTitle/PageTitle.module.css | 15 - components/PageTitle/PageTitle.tsx | 11 +- components/ThemeToggle/ThemeToggle.module.css | 26 - components/ThemeToggle/ThemeToggle.tsx | 8 +- lib/config/constants.ts | 2 +- lib/helpers/classnames.ts | 8 + package.json | 14 +- pnpm-lock.yaml | 1108 +++++++---------- postcss.config.mjs | 7 + renovate.json | 8 +- 40 files changed, 785 insertions(+), 1543 deletions(-) delete mode 100644 .stylelintrc.mjs create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json delete mode 100644 app/layout.module.css delete mode 100644 app/page.module.css delete mode 100644 app/projects/page.module.css delete mode 100644 components/Blockquote/Blockquote.module.css delete mode 100644 components/Footer/Footer.module.css delete mode 100644 components/Header/Header.module.css delete mode 100644 components/Link/Link.module.css delete mode 100644 components/Menu/Menu.module.css delete mode 100644 components/MenuItem/MenuItem.module.css delete mode 100644 components/PageTitle/PageTitle.module.css delete mode 100644 components/ThemeToggle/ThemeToggle.module.css create mode 100644 lib/helpers/classnames.ts create mode 100644 postcss.config.mjs diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index e298a1ba..bc720ea2 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -16,15 +16,18 @@ "git.fetchOnPull": true, "git.rebaseWhenSync": true, "telemetry.telemetryLevel": "off", + "javascript.updateImportsOnFileMove.enabled": "always", "typescript.preferences.importModuleSpecifierEnding": "minimal", - "typescript.tsdk": "node_modules/typescript/lib" + "typescript.surveys.enabled": false, + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.tsserver.log": "off", + "typescript.updateImportsOnFileMove.enabled": "always" }, "extensions": [ + "bradlc.vscode-tailwindcss", "dbaeumer.vscode-eslint", - "EditorConfig.EditorConfig", - "unifiedjs.vscode-mdx", "esbenp.prettier-vscode", - "stylelint.vscode-stylelint" + "unifiedjs.vscode-mdx" ] } }, diff --git a/.npmrc b/.npmrc index 6f07069f..d93a75a6 100644 --- a/.npmrc +++ b/.npmrc @@ -1,3 +1,2 @@ public-hoist-pattern[]=*eslint* public-hoist-pattern[]=*prettier* -public-hoist-pattern[]=*stylelint* diff --git a/.prettierrc.mjs b/.prettierrc.mjs index 49b1fa75..1be2c63a 100644 --- a/.prettierrc.mjs +++ b/.prettierrc.mjs @@ -1,12 +1,13 @@ /** @type {import("prettier").Config} */ const config = { - singleQuote: false, + plugins: ["prettier-plugin-tailwindcss"], jsxSingleQuote: false, printWidth: 120, - tabWidth: 2, - useTabs: false, quoteProps: "as-needed", + singleQuote: false, + tabWidth: 2, trailingComma: "es5", + useTabs: false, }; export default config; diff --git a/.stylelintrc.mjs b/.stylelintrc.mjs deleted file mode 100644 index dd849dc0..00000000 --- a/.stylelintrc.mjs +++ /dev/null @@ -1,19 +0,0 @@ -/* eslint-disable import/no-anonymous-default-export */ - -/** @type {import("stylelint").Config} */ -export default { - extends: ["stylelint-config-standard", "stylelint-config-css-modules", "stylelint-prettier/recommended"], - rules: { - "selector-class-pattern": null, - "custom-property-pattern": null, - "media-feature-range-notation": null, - "rule-empty-line-before": [ - "always-multi-line", - { - except: ["after-single-line-comment"], - ignore: ["inside-block"], - }, - ], - "color-hex-length": "long", - }, -}; diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..2229ccd0 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "bradlc.vscode-tailwindcss", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "unifiedjs.vscode-mdx" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..fe47dfc4 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "editor.tabSize": 2, + "editor.rulers": [ + 120 + ], + "files.associations": { + "*.css": "tailwindcss", + "*.mdx": "markdown" + }, + "javascript.updateImportsOnFileMove.enabled": "always", + "typescript.preferences.importModuleSpecifierEnding": "minimal", + "typescript.surveys.enabled": false, + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.tsserver.log": "off", + "typescript.updateImportsOnFileMove.enabled": "always" +} diff --git a/app/contact/form.tsx b/app/contact/form.tsx index 28ed5910..7cab7590 100644 --- a/app/contact/form.tsx +++ b/app/contact/form.tsx @@ -97,7 +97,7 @@ const ContactForm = () => { Markdown syntax {" "} is allowed here, e.g.: **bold**, _italics_, [ - + links ](https://jarv.is), and `code`. diff --git a/app/fonts.ts b/app/fonts.ts index 548cac31..2ef1555a 100644 --- a/app/fonts.ts +++ b/app/fonts.ts @@ -11,7 +11,7 @@ export const GeistSans = GeistSansLoader({ "system-ui", "sans-serif", ], - variable: "--fonts-sans", + variable: "--font-geist-sans", preload: true, }); @@ -29,6 +29,6 @@ export const GeistMono = GeistMonoLoader({ "monospace", ], adjustFontFallback: false, - variable: "--fonts-mono", + variable: "--font-geist-mono", preload: true, }); diff --git a/app/globals.css b/app/globals.css index b1046191..bdc52bbf 100644 --- a/app/globals.css +++ b/app/globals.css @@ -1,69 +1,100 @@ -/*! - * modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize/tree/v3.0.1 - */ +@import "tailwindcss"; -*, -::before, -::after { - box-sizing: border-box; +@theme inline { + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); } -html { - line-height: 1.15; - tab-size: 4; - /* stylelint-disable-next-line property-no-vendor-prefix */ - -webkit-text-size-adjust: 100%; +@theme { + --container-default: var(--container-4xl); + + --color-*: initial; + --color-background-inner: #ffffff; + --color-background-outer: #fcfcfc; + --color-text: #202020; + --color-medium-dark: #515151; + --color-medium: #5e5e5e; + --color-medium-light: #757575; + --color-light: #d2d2d2; + --color-kinda-light: #e3e3e3; + --color-super-light: #f4f4f4; + --color-super-duper-light: #fbfbfb; + --color-link: #0e6dc2; + --color-success: #44a248; + --color-error: #ff1b1b; + --color-warning: #f78200; + + --animate-wave: wave 5s ease 1s infinite; + --animate-heartbeat: heartbeat 10s ease 7.5s infinite; + + @keyframes wave { + 0% { + transform: rotate(0deg); + } + 5% { + transform: rotate(14deg); + } + 10% { + transform: rotate(-8deg); + } + 15% { + transform: rotate(14deg); + } + 20% { + transform: rotate(-4deg); + } + 25% { + transform: rotate(10deg); + } + 30% { + transform: rotate(0deg); + } + + /* pause for ~9 out of 10 seconds */ + 100% { + transform: rotate(0deg); + } + } + + @keyframes heartbeat { + 0% { + transform: scale(1); + } + 2% { + transform: scale(1.25); + } + 4% { + transform: scale(1); + } + 6% { + transform: scale(1.2); + } + 8% { + transform: scale(1); + } + + /* pause for ~9 out of 10 seconds */ + 100% { + transform: scale(1); + } + } } -body { - margin: 0; - font-family: var(--fonts-sans); - background-color: var(--colors-background-inner); -} +@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *)); -code, -kbd, -samp, -pre { - font-size: 1em; - font-family: var(--fonts-mono); - font-variant-ligatures: none; /* i hate them. fwiw. */ -} - -small { - font-size: 80%; -} - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -button, -input, -select, -textarea { - font-family: inherit; - font-size: 100%; - line-height: 1.15; - margin: 0; -} - -button, -[type="button"], -[type="reset"], -[type="submit"] { - /* stylelint-disable-next-line property-no-vendor-prefix */ - -webkit-appearance: button; +[data-theme="dark"] { + --color-background-inner: #1e1e1e; + --color-background-outer: #252525; + --color-text: #f1f1f1; + --color-medium-dark: #d7d7d7; + --color-medium: #b1b1b1; + --color-medium-light: #959595; + --color-light: #646464; + --color-kinda-light: #535353; + --color-super-light: #272727; + --color-super-duper-light: #1f1f1f; + --color-link: #88c7ff; + --color-success: #78df55; + --color-error: #ff5151; + --color-warning: #f2b702; } diff --git a/app/layout.module.css b/app/layout.module.css deleted file mode 100644 index acb47ca0..00000000 --- a/app/layout.module.css +++ /dev/null @@ -1,26 +0,0 @@ -.layout { - display: flex; - flex-direction: column; - min-height: 100vh; -} - -.default { - width: 100%; - padding: 1.5em; - font-size: 0.9em; - line-height: 1.7; - color: var(--colors-text); -} - -.container { - width: 100%; - max-width: var(--max-width); - margin: 0 auto; -} - -@media (max-width: 768px) { - .default { - font-size: 0.925em; - line-height: 1.85; - } -} diff --git a/app/layout.tsx b/app/layout.tsx index 37bd982c..96bc51d5 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,27 +1,27 @@ import { env } from "../lib/env"; import { JsonLd } from "react-schemaorg"; import { Analytics } from "@vercel/analytics/next"; -import clsx from "clsx"; import { ThemeProvider, ThemeScript } from "../contexts/ThemeContext"; import Header from "../components/Header"; import Footer from "../components/Footer"; import { SkipNavLink, SkipNavTarget } from "../components/SkipNav"; +import cn from "../lib/helpers/classnames"; import { defaultMetadata } from "../lib/helpers/metadata"; import * as config from "../lib/config"; -import { MAX_WIDTH } from "../lib/config/constants"; import type { Person, WebSite } from "schema-dts"; import { GeistMono, GeistSans } from "./fonts"; import "./globals.css"; -import "./themes.css"; - -import styles from "./layout.module.css"; export const metadata = defaultMetadata; const RootLayout = ({ children }: Readonly<{ children: React.ReactNode }>) => { return ( - + @@ -62,21 +62,16 @@ const RootLayout = ({ children }: Readonly<{ children: React.ReactNode }>) => { /> - + -
+
-
-
- - {children} -
+
+ +
{children}