button-component #29

Merged
stne3960 merged 22 commits from button-component into main 2025-12-12 11:52:31 +01:00
24 changed files with 1116 additions and 4 deletions

6
.gitattributes vendored
View File

@ -8,3 +8,9 @@
*.jpg binary *.jpg binary
*.png binary *.png binary
*.jar binary *.jar binary
*.woff binary
*.woff2 binary
*.ttf binary
*.otf binary
*.eot binary

View File

@ -8,6 +8,7 @@
"name": "frontend", "name": "frontend",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"clsx": "^2.1.1",
"openapi-fetch": "^0.13.5", "openapi-fetch": "^0.13.5",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
@ -15,6 +16,7 @@
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.21.0", "@eslint/js": "^9.21.0",
"@tailwindcss/vite": "^4.1.16",
"@types/react": "^19.0.10", "@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4", "@types/react-dom": "^19.0.4",
"@vitejs/plugin-react-swc": "^3.8.0", "@vitejs/plugin-react-swc": "^3.8.0",
@ -25,6 +27,7 @@
"globals": "^15.15.0", "globals": "^15.15.0",
"openapi-typescript": "^7.6.1", "openapi-typescript": "^7.6.1",
"prettier": "3.5.3", "prettier": "3.5.3",
"tailwindcss": "^4.1.16",
"typescript": "~5.7.2", "typescript": "~5.7.2",
"typescript-eslint": "^8.24.1", "typescript-eslint": "^8.24.1",
"vite": "^6.2.0" "vite": "^6.2.0"
@ -700,6 +703,56 @@
"url": "https://github.com/sponsors/nzakas" "url": "https://github.com/sponsors/nzakas"
} }
}, },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/remapping": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
"integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.5", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@ -1320,6 +1373,338 @@
"@swc/counter": "^0.1.3" "@swc/counter": "^0.1.3"
} }
}, },
"node_modules/@tailwindcss/node": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.16.tgz",
"integrity": "sha512-BX5iaSsloNuvKNHRN3k2RcCuTEgASTo77mofW0vmeHkfrDWaoFAFvNHpEgtu0eqyypcyiBkDWzSMxJhp3AUVcw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/remapping": "^2.3.4",
"enhanced-resolve": "^5.18.3",
"jiti": "^2.6.1",
"lightningcss": "1.30.2",
"magic-string": "^0.30.19",
"source-map-js": "^1.2.1",
"tailwindcss": "4.1.16"
}
},
"node_modules/@tailwindcss/oxide": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.16.tgz",
"integrity": "sha512-2OSv52FRuhdlgyOQqgtQHuCgXnS8nFSYRp2tJ+4WZXKgTxqPy7SMSls8c3mPT5pkZ17SBToGM5LHEJBO7miEdg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 10"
},
"optionalDependencies": {
"@tailwindcss/oxide-android-arm64": "4.1.16",
"@tailwindcss/oxide-darwin-arm64": "4.1.16",
"@tailwindcss/oxide-darwin-x64": "4.1.16",
"@tailwindcss/oxide-freebsd-x64": "4.1.16",
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.16",
"@tailwindcss/oxide-linux-arm64-gnu": "4.1.16",
"@tailwindcss/oxide-linux-arm64-musl": "4.1.16",
"@tailwindcss/oxide-linux-x64-gnu": "4.1.16",
"@tailwindcss/oxide-linux-x64-musl": "4.1.16",
"@tailwindcss/oxide-wasm32-wasi": "4.1.16",
"@tailwindcss/oxide-win32-arm64-msvc": "4.1.16",
"@tailwindcss/oxide-win32-x64-msvc": "4.1.16"
}
},
"node_modules/@tailwindcss/oxide-android-arm64": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.16.tgz",
"integrity": "sha512-8+ctzkjHgwDJ5caq9IqRSgsP70xhdhJvm+oueS/yhD5ixLhqTw9fSL1OurzMUhBwE5zK26FXLCz2f/RtkISqHA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.16.tgz",
"integrity": "sha512-C3oZy5042v2FOALBZtY0JTDnGNdS6w7DxL/odvSny17ORUnaRKhyTse8xYi3yKGyfnTUOdavRCdmc8QqJYwFKA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-darwin-x64": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.16.tgz",
"integrity": "sha512-vjrl/1Ub9+JwU6BP0emgipGjowzYZMjbWCDqwA2Z4vCa+HBSpP4v6U2ddejcHsolsYxwL5r4bPNoamlV0xDdLg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.16.tgz",
"integrity": "sha512-TSMpPYpQLm+aR1wW5rKuUuEruc/oOX3C7H0BTnPDn7W/eMw8W+MRMpiypKMkXZfwH8wqPIRKppuZoedTtNj2tg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.16.tgz",
"integrity": "sha512-p0GGfRg/w0sdsFKBjMYvvKIiKy/LNWLWgV/plR4lUgrsxFAoQBFrXkZ4C0w8IOXfslB9vHK/JGASWD2IefIpvw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.16.tgz",
"integrity": "sha512-DoixyMmTNO19rwRPdqviTrG1rYzpxgyYJl8RgQvdAQUzxC1ToLRqtNJpU/ATURSKgIg6uerPw2feW0aS8SNr/w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.16.tgz",
"integrity": "sha512-H81UXMa9hJhWhaAUca6bU2wm5RRFpuHImrwXBUvPbYb+3jo32I9VIwpOX6hms0fPmA6f2pGVlybO6qU8pF4fzQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.16.tgz",
"integrity": "sha512-ZGHQxDtFC2/ruo7t99Qo2TTIvOERULPl5l0K1g0oK6b5PGqjYMga+FcY1wIUnrUxY56h28FxybtDEla+ICOyew==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.16.tgz",
"integrity": "sha512-Oi1tAaa0rcKf1Og9MzKeINZzMLPbhxvm7rno5/zuP1WYmpiG0bEHq4AcRUiG2165/WUzvxkW4XDYCscZWbTLZw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.16.tgz",
"integrity": "sha512-B01u/b8LteGRwucIBmCQ07FVXLzImWESAIMcUU6nvFt/tYsQ6IHz8DmZ5KtvmwxD+iTYBtM1xwoGXswnlu9v0Q==",
"bundleDependencies": [
"@napi-rs/wasm-runtime",
"@emnapi/core",
"@emnapi/runtime",
"@tybys/wasm-util",
"@emnapi/wasi-threads",
"tslib"
],
"cpu": [
"wasm32"
],
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.5.0",
"@emnapi/runtime": "^1.5.0",
"@emnapi/wasi-threads": "^1.1.0",
"@napi-rs/wasm-runtime": "^1.0.7",
"@tybys/wasm-util": "^0.10.1",
"tslib": "^2.4.0"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
"version": "1.5.0",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.1.0",
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
"version": "1.5.0",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
"version": "1.1.0",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
"version": "1.0.7",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.5.0",
"@emnapi/runtime": "^1.5.0",
"@tybys/wasm-util": "^0.10.1"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
"version": "0.10.1",
"dev": true,
"inBundle": true,
"license": "MIT",
"optional": true,
"dependencies": {
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
"version": "2.8.1",
"dev": true,
"inBundle": true,
"license": "0BSD",
"optional": true
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.16.tgz",
"integrity": "sha512-zX+Q8sSkGj6HKRTMJXuPvOcP8XfYON24zJBRPlszcH1Np7xuHXhWn8qfFjIujVzvH3BHU+16jBXwgpl20i+v9A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.16.tgz",
"integrity": "sha512-m5dDFJUEejbFqP+UXVstd4W/wnxA4F61q8SoL+mqTypId2T2ZpuxosNSgowiCnLp2+Z+rivdU0AqpfgiD7yCBg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/vite": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.16.tgz",
"integrity": "sha512-bbguNBcDxsRmi9nnlWJxhfDWamY3lmcyACHcdO1crxfzuLpOhHLLtEIN/nCbbAtj5rchUgQD17QVAKi1f7IsKg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@tailwindcss/node": "4.1.16",
"@tailwindcss/oxide": "4.1.16",
"tailwindcss": "4.1.16"
},
"peerDependencies": {
"vite": "^5.2.0 || ^6 || ^7"
}
},
"node_modules/@types/estree": { "node_modules/@types/estree": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
@ -1721,6 +2106,15 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/color-convert": { "node_modules/color-convert": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@ -1811,6 +2205,30 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=8"
}
},
"node_modules/enhanced-resolve": {
"version": "5.18.3",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
"integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
"dev": true,
"license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/esbuild": { "node_modules/esbuild": {
"version": "0.25.1", "version": "0.25.1",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
@ -2222,6 +2640,13 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true,
"license": "ISC"
},
"node_modules/graphemer": { "node_modules/graphemer": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
@ -2343,6 +2768,16 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/jiti": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
"dev": true,
"license": "MIT",
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
},
"node_modules/js-levenshtein": { "node_modules/js-levenshtein": {
"version": "1.1.6", "version": "1.1.6",
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
@ -2418,6 +2853,267 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/lightningcss": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
"integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==",
"dev": true,
"license": "MPL-2.0",
"dependencies": {
"detect-libc": "^2.0.3"
},
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"lightningcss-android-arm64": "1.30.2",
"lightningcss-darwin-arm64": "1.30.2",
"lightningcss-darwin-x64": "1.30.2",
"lightningcss-freebsd-x64": "1.30.2",
"lightningcss-linux-arm-gnueabihf": "1.30.2",
"lightningcss-linux-arm64-gnu": "1.30.2",
"lightningcss-linux-arm64-musl": "1.30.2",
"lightningcss-linux-x64-gnu": "1.30.2",
"lightningcss-linux-x64-musl": "1.30.2",
"lightningcss-win32-arm64-msvc": "1.30.2",
"lightningcss-win32-x64-msvc": "1.30.2"
}
},
"node_modules/lightningcss-android-arm64": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz",
"integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-darwin-arm64": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz",
"integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-darwin-x64": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz",
"integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-freebsd-x64": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz",
"integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm-gnueabihf": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz",
"integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-gnu": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz",
"integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-musl": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz",
"integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-gnu": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz",
"integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==",
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-musl": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz",
"integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-arm64-msvc": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz",
"integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-x64-msvc": {
"version": "1.30.2",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz",
"integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MPL-2.0",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/locate-path": { "node_modules/locate-path": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@ -2441,6 +3137,16 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/merge2": { "node_modules/merge2": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@ -2999,6 +3705,27 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/tailwindcss": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.16.tgz",
"integrity": "sha512-pONL5awpaQX4LN5eiv7moSiSPd/DLDzKVRJz8Q9PgzmAdd1R4307GQS2ZpfiN7ZmekdQrfhZZiSE5jkLR4WNaA==",
"dev": true,
"license": "MIT"
},
"node_modules/tapable": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
"integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/tinyglobby": { "node_modules/tinyglobby": {
"version": "0.2.14", "version": "0.2.14",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",

View File

@ -12,6 +12,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"clsx": "^2.1.1",
"openapi-fetch": "^0.13.5", "openapi-fetch": "^0.13.5",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
@ -19,6 +20,7 @@
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.21.0", "@eslint/js": "^9.21.0",
"@tailwindcss/vite": "^4.1.16",
"@types/react": "^19.0.10", "@types/react": "^19.0.10",
"@types/react-dom": "^19.0.4", "@types/react-dom": "^19.0.4",
"@vitejs/plugin-react-swc": "^3.8.0", "@vitejs/plugin-react-swc": "^3.8.0",
@ -29,6 +31,7 @@
"globals": "^15.15.0", "globals": "^15.15.0",
"openapi-typescript": "^7.6.1", "openapi-typescript": "^7.6.1",
"prettier": "3.5.3", "prettier": "3.5.3",
"tailwindcss": "^4.1.16",
"typescript": "~5.7.2", "typescript": "~5.7.2",
"typescript-eslint": "^8.24.1", "typescript-eslint": "^8.24.1",
"vite": "^6.2.0" "vite": "^6.2.0"

View File

@ -1,5 +1,5 @@
import { BrowserRouter, Route, Routes } from "react-router"; import { BrowserRouter, Route, Routes } from "react-router";
import Home from "./studentportalen/Home.tsx"; import ComponentLibrary from "./studentportalen/ComponentLibrary.tsx";
import Layout from "./studentportalen/Layout.tsx"; import Layout from "./studentportalen/Layout.tsx";
export default function Studentportalen() { export default function Studentportalen() {
@ -8,7 +8,8 @@ export default function Studentportalen() {
<BrowserRouter> <BrowserRouter>
<Routes> <Routes>
<Route element={<Layout />}> <Route element={<Layout />}>
<Route index element={<Home />} /> <Route index element={<ComponentLibrary />} />
<Route path="components" element={<ComponentLibrary />} />
</Route> </Route>
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,79 @@
import type { ButtonHTMLAttributes, ReactNode } from "react";
import clsx from "clsx";
export type ButtonVariant = "primary" | "secondary" | "red" | "green";
export type ButtonSize = "sm" | "md" | "lg";
export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: ButtonVariant;
size?: ButtonSize;
children: ReactNode;
}
const variantClasses: Record<ButtonVariant, string> = {
primary: clsx(
stne3960 marked this conversation as resolved Outdated

This is unwieldy. Any way to break it down or group them somehow? Like the border styles, focus styles, colors, and so on.

Is it necessary to repeat the prefix or can you do something like hover:[a, b, c] instead of hover:a hover:b hover:c?

This is unwieldy. Any way to break it down or group them somehow? Like the border styles, focus styles, colors, and so on. Is it necessary to repeat the prefix or can you do something like `hover:[a, b, c]` instead of `hover:a hover:b hover:c`?
"bg-primary text-base-canvas",
"border border-primary",
"hover:bg-secondary hover:text-base-canvas",
"hover:border hover:border-primary",
"focus-visible:bg-base-canvas focus-visible:text-base-ink-strong",
"focus-visible:border focus-visible:border-primary",
"focus-visible:outline focus-visible:outline-[length:var(--border-width-lg)] focus-visible:outline-sky-100",
),
secondary: clsx(
"bg-base-canvas text-base-ink-strong",
"border-solid [border-width:var(--border-width-sm)] border-base-ink-soft",
"hover:bg-base-canvas hover:text-base-ink-strong",
"hover:border-base-ink-medium",
"focus-visible:bg-base-canvas focus-visible:text-base-ink-strong",
"focus-visible:border-primary",
"focus-visible:outline focus-visible:outline-[length:var(--border-width-lg)] focus-visible:outline-sky-100",
),
red: clsx(
"bg-other-red-100 text-su-white",
"focus-visible:bg-base-canvas focus-visible:text-base-ink-strong",
"focus-visible:border-primary focus-visible:border",
"focus-visible:outline focus-visible:outline-[length:var(--border-width-lg)] focus-visible:outline-sky-100",
),
green: clsx(
"bg-other-green text-su-white",
"focus-visible:bg-base-canvas focus-visible:text-base-ink-strong",
"focus-visible:border-primary focus-visible:border",
"focus-visible:outline focus-visible:outline-[length:var(--border-width-lg)] focus-visible:outline-sky-100",
),
};
const sizeClasses: Record<ButtonSize, string> = {
sm: "h-(--control-height-sm) min-w-(--button-min-width-sm) px-(--button-padding-x-sm) body-bold-md rounded-(--border-radius-sm)",
md: "h-(--control-height-md) min-w-(--button-min-width-md) px-(--button-padding-x-md) body-bold-md rounded-(--border-radius-sm)",
lg: "h-(--control-height-lg) min-w-(--button-min-width-lg) px-(--button-padding-x-lg) body-bold-lg rounded-(--border-radius-md)",
stne3960 marked this conversation as resolved Outdated

What does this do? I assume it does some JavaScript type-coercion of strings/undefined/null to booleans but what about the empty string? Needs a clarification comment.

My initial read through of the code, none of the strings in the list should be null or undefined and joining an empty string shouldn't matter much.

What does this do? I assume it does some JavaScript type-coercion of strings/`undefined`/`null` to booleans but what about the empty string? Needs a clarification comment. My initial read through of the code, none of the strings in the list should be `null` or `undefined` and joining an empty string shouldn't matter much.

You're right that the current implementation passes only non-empty strings, so .filter(Boolean) doesn't change behavior today.

The reason it's useful is as soon as someone adds conditional classes or optional props (e.g. isDisabled && "opacity-50 cursor-not-allowed"), it's easy for the array to end up containing false, undefined, or empty strings. Without filtering, those values can end up in the final className and produce a noisy DOM.

Using .filter(Boolean) keeps the class string clean no matter how the component evolves. I'll add a short comment explaining this so future contributors understand the intent.

You're right that the current implementation passes only non-empty strings, so `.filter(Boolean)` doesn't change behavior today. The reason it's useful is as soon as someone adds conditional classes or optional props (e.g. `isDisabled && "opacity-50 cursor-not-allowed"`), it's easy for the array to end up containing false, undefined, or empty strings. Without filtering, those values can end up in the final className and produce a noisy DOM. Using `.filter(Boolean)` keeps the class string clean no matter how the component evolves. I'll add a short comment explaining this so future contributors understand the intent.
};
const textPaddingClasses: Record<ButtonSize, string> = {
sm: "px-(--button-text-padding-x-sm)",
md: "px-(--button-text-padding-x-md)",
lg: "px-(--button-text-padding-x-lg)",
};
export default function Button({
variant = "primary",
size = "md",
className = "",
children,
...props
}: ButtonProps) {
const baseClasses = "inline-flex items-center justify-center cursor-pointer";
const classes = clsx(
baseClasses,
variantClasses[variant],
sizeClasses[size],
className,
);
return (
<button className={classes} {...props}>
<span className={textPaddingClasses[size]}>{children}</span>
</button>
);
}

View File

@ -1,11 +1,258 @@
@import "tailwindcss";
stne3960 marked this conversation as resolved
Review

Needs to be ran through Prettier.

Needs to be ran through Prettier.
/* TheSans Font Family */
@font-face {
font-family: "TheSansB W2 ExtraLight";
src: url("./assets/TheSansB-W2ExtraLight.woff2") format("woff2");
font-style: normal;
}
@font-face {
font-family: "TheSansB W2 ExtraLight";
src: url("./assets/TheSansB-W2ExtraLightItalic.woff2") format("woff2");
font-style: italic;
}
@font-face {
font-family: "TheSansB W3 Light";
src: url("./assets/TheSansB-W3Light.woff2") format("woff2");
font-style: normal;
}
@font-face {
font-family: "TheSansB W3 Light";
src: url("./assets/TheSansB-W3LightItalic.woff2") format("woff2");
font-style: italic;
}
@font-face {
font-family: "TheSansB W4 SemiLight";
src: url("./assets/TheSansB-W4SemiLight.woff2") format("woff2");
font-style: normal;
}
@font-face {
font-family: "TheSansB W4 SemiLight";
src: url("./assets/TheSansB-W4SemiLightItalic.woff2") format("woff2");
font-style: italic;
}
@font-face {
font-family: "TheSansB W5 Plain";
src: url("./assets/TheSansB-W5Plain.woff2") format("woff2");
font-style: normal;
}
@font-face {
font-family: "TheSansB W5 Plain";
src: url("./assets/TheSansB-W5PlainItalic.woff2") format("woff2");
font-style: italic;
}
@font-face {
font-family: "TheSansB W6 SemiBold";
src: url("./assets/TheSansB-W6SemiBold.woff2") format("woff2");
font-style: normal;
}
@font-face {
font-family: "TheSansB W6 SemiBold";
src: url("./assets/TheSansB-W6SemiBoldItalic.woff2") format("woff2");
font-style: italic;
}
@font-face {
font-family: "TheSansB W7 Bold";
src: url("./assets/TheSansB-W7Bold.woff2") format("woff2");
font-style: normal;
}
@font-face {
font-family: "TheSansB W7 Bold";
src: url("./assets/TheSansB-W7BoldItalic.woff2") format("woff2");
font-style: italic;
}
@font-face {
font-family: "TheSansB W8 ExtraBold";
src: url("./assets/TheSansB-W8ExtraBold.woff2") format("woff2");
font-style: normal;
}
@font-face {
font-family: "TheSansB W8 ExtraBold";
src: url("./assets/TheSansB-W8ExtraBoldItalic.woff2") format("woff2");
font-style: italic;
}
@font-face {
font-family: "TheSansB W9 Black";
src: url("./assets/TheSansB-W9Black.woff2") format("woff2");
font-style: normal;
}
@font-face {
font-family: "TheSansB W9 Black";
src: url("./assets/TheSansB-W9BlackItalic.woff2") format("woff2");
font-style: italic;
}
@theme {
/* Colors */
--color-primary: #05305d;
--color-base-canvas: #ffffff;
--color-secondary: #34587f;
--color-sky-100: #b0dee4;
--color-sky-70: #c7e8ed;
--color-sky-35: #e4f4f7;
--color-sky-20: #eff9fa;
--color-base-ink-max: #000000;
--color-base-ink-strong: #4b4b4b;
--color-base-ink-medium: #bababa;
--color-base-ink-soft: #dadada;
--color-base-ink-placeholder: #757575;
--color-other-red-100: #aa1227;
--color-other-red-10: #f6e6e8;
--color-other-green: #539848;
--color-su-white: #ffffff;
--color-fire-100: #eb7124;
--color-fire-70: #f19b66;
--color-fire-35: #f8cdb4;
--color-fire-20: #fbe2d3;
/* Font sizes */
--font-size-body-md: 16px;
--font-size-body-lg: 18px;
/* Border radius */
--border-radius-sm: 3px;
--border-radius-md: 4px;
--border-radius-lg: 6px;
--border-radius-xl: 8px;
/* Border width */
--border-width-sm: 1px;
--border-width-lg: 3px;
/* Padding */
--padding-md: 12px;
--padding-lg: 24px;
--padding-xl: 48px;
/* Spacing */
--spacing-sm: 8px;
--spacing-md: 12px;
--spacing-lg: 24px;
--spacing-xl: 32px;
/* Control heights */
--control-height-sm: 32px;
--control-height-md: 40px;
--control-height-lg: 48px;
/* Button padding x */
--button-padding-x-sm: 6px;
--button-padding-x-md: 10px;
--button-padding-x-lg: 14px;
/* Button min width */
--button-min-width-sm: 72px;
--button-min-width-md: 72px;
--button-min-width-lg: 84px;
/* Button text padding x */
--button-text-padding-x-sm: 6px;
--button-text-padding-x-md: 6px;
--button-text-padding-x-lg: 6px;
/* Text input default width */
--text-input-default-width-md: 194px;
--text-input-default-width-lg: 218px;
}
.dark {
--color-primary: #ffffff;
--color-base-canvas: #000000;
--color-secondary: #d9d6d6;
--color-sky-100: #403d3d;
--color-sky-70: #2d2b2b;
--color-sky-35: #1f1e1e;
--color-sky-20: #141414;
--color-base-ink-max: #ffffff;
--color-base-ink-strong: #ffffff;
--color-base-ink-medium: #636363;
--color-base-ink-soft: #555555;
--color-base-ink-placeholder: #959595;
--color-other-red-100: #aa1227;
--color-other-red-10: #f6e6e8;
--color-other-green: #539848;
--color-su-white: #ffffff;
--color-fire-100: #eb7124;
--color-fire-70: #f19b66;
--color-fire-35: #f8cdb4;
--color-fire-20: #fbe2d3;
}
:root { :root {
--color-su-primary: #002f5f; --color-su-primary: #002f5f;
--color-su-primary-80: #33587f; --color-su-primary-80: #33587f;
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; --bottom-nav-height: 4.5rem;
font-family: "TheSans", system-ui, Avenir, Helvetica, Arial, sans-serif;
background-color: #ffffff;
color: #000000;
} }
/* Text styles - Body */
.body-light-sm {
font-family: "TheSansB W3 Light", system-ui, sans-serif;
font-size: 14px;
}
.body-normal-md {
font-family: "TheSansB W4 SemiLight", system-ui, sans-serif;
font-size: 16px;
}
.body-normal-lg {
font-family: "TheSansB W4 SemiLight", system-ui, sans-serif;
font-size: 18px;
}
.body-semibold-md {
font-family: "TheSansB W5 Plain", system-ui, sans-serif;
font-size: 16px;
}
.body-semibold-lg {
font-family: "TheSansB W5 Plain", system-ui, sans-serif;
font-size: 18px;
}
.body-bold-md {
font-family: "TheSansB W6 SemiBold", system-ui, sans-serif;
font-size: 16px;
}
.body-bold-lg {
font-family: "TheSansB W6 SemiBold", system-ui, sans-serif;
font-size: 18px;
}
/* Text styles - Heading */
.heading-semibold-lg {
font-family: "TheSansB W6 SemiBold", system-ui, sans-serif;
font-size: 32px;
}
.dark {
background-color: #141414;
color: #ffffff;
}
* { * {
box-sizing: border-box; box-sizing: border-box;
} }
body { body {
margin: 0; margin: 0;
min-height: 100vh;
} }

View File

@ -0,0 +1,48 @@
import { useState, useEffect } from "react";
import Button from "../components/Button/Button";
export default function ComponentLibrary() {
const [darkMode, setDarkMode] = useState(() => {
stne3960 marked this conversation as resolved Outdated

This file needs to be ran through Prettier.

This file needs to be ran through Prettier.
return document.documentElement.classList.contains("dark");
});
useEffect(() => {
if (darkMode) {
document.documentElement.classList.add("dark");
} else {
document.documentElement.classList.remove("dark");
}
}, [darkMode]);
return (
<>
<h1>Component Library</h1>
<section className="mt-lg">
<h2 className="mb-md">Dark Mode</h2>
<Button variant="primary" onClick={() => setDarkMode(!darkMode)}>
{darkMode ? "Light Mode" : "Dark Mode"}
</Button>
</section>
<section className="mt-lg">
<h2 className="mb-md">Button Variants</h2>
<div className="flex flex-wrap gap-md">
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="red">Red</Button>
<Button variant="green">Green</Button>
</div>
</section>
<section className="mt-lg">
<h2 className="mb-md">Button Sizes</h2>
<div className="flex flex-wrap items-center gap-md">
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>
</div>
</section>
</>
);
}

View File

@ -1,7 +1,8 @@
import { defineConfig } from "vite"; import { defineConfig } from "vite";
stne3960 marked this conversation as resolved Outdated

This file needs to be ran through Prettier.

This file needs to be ran through Prettier.
import react from "@vitejs/plugin-react-swc"; import react from "@vitejs/plugin-react-swc";
import tailwindcss from "@tailwindcss/vite";
// https://vite.dev/config/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react(), tailwindcss()],
}); });