diff --git a/astro.config.mjs b/astro.config.mjs index a4159f7..9259b1f 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,12 +1,17 @@ import { defineConfig } from 'astro/config'; import node from '@astrojs/node'; + export default defineConfig({ output: 'server', adapter: node({ mode: 'standalone' }), server: { port: 4321, host: true }, vite: { - optimizeDeps: { exclude: ['better-sqlite3'] }, - ssr: { external: ['better-sqlite3'] } + optimizeDeps: { + exclude: ['better-sqlite3', 'puppeteer'] // ← puppeteer ergänzen + }, + ssr: { + external: ['better-sqlite3', 'puppeteer'] // ← puppeteer ergänzen + } } }); diff --git a/package-lock.json b/package-lock.json index e868d6c..cee4d2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,9 @@ "@astrojs/node": "^8.2.0", "astro": "^4.5.0", "better-sqlite3": "^12.9.0", + "marked": "^18.0.2", "nodemailer": "^6.9.13", + "puppeteer": "^24.42.0", "uuid": "^9.0.1" }, "devDependencies": { @@ -1224,6 +1226,53 @@ "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", "license": "MIT" }, + "node_modules/@puppeteer/browsers": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.0.tgz", + "integrity": "sha512-46BZJYJjc/WwmKjsvDFykHtXrtomsCIrwYQPOP7VfMJoZY2bsDF9oROBABR3paDjDcmkUye1Pb1BqdcdiipaWA==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.3", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.4", + "tar-fs": "^3.1.1", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@puppeteer/browsers/node_modules/tar-fs": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/@puppeteer/browsers/node_modules/tar-stream": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.8.tgz", + "integrity": "sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/@rollup/pluginutils": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", @@ -1646,6 +1695,12 @@ "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", "license": "MIT" }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1784,6 +1839,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -1802,6 +1867,15 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -1901,6 +1975,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/astro": { "version": "4.16.19", "resolved": "https://registry.npmjs.org/astro/-/astro-4.16.19.tgz", @@ -1991,6 +2077,20 @@ "node": ">= 0.4" } }, + "node_modules/b4a": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "license": "Apache-2.0", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -2001,6 +2101,97 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/bare-events": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", + "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", + "license": "Apache-2.0", + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.1.tgz", + "integrity": "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.0.tgz", + "integrity": "sha512-JTjuZyNIDpw+GytMO4a6TK1VXdVKKJr6DRxEHasyuYyShV2deuiHJK/ahGZlebc+SG0/wJCB9XK8gprBGDFi/Q==", + "license": "Apache-2.0", + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.0.tgz", + "integrity": "sha512-3zAJRZMDFGjdn+RVnNpF9kuELw+0Fl3lpndM4NcEOhb9zwtSo/deETfuIwMSE5BXanA0FrN1qVjffGwAg2Y7EA==", + "license": "Apache-2.0", + "dependencies": { + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.2.tgz", + "integrity": "sha512-/9a2j4ac6ckpmAHvod/ob7x439OAHst/drc2Clnq+reRYd/ovddwcF4LfoxHyNk5AuGBnPg+HqFjmE/Zpq6v0A==", + "license": "Apache-2.0", + "dependencies": { + "bare-path": "^3.0.0" + } + }, "node_modules/base-64": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", @@ -2039,6 +2230,15 @@ "node": ">=6.0.0" } }, + "node_modules/basic-ftp": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.0.tgz", + "integrity": "sha512-5K9eNNn7ywHPsYnFwjKgYH8Hf8B5emh7JKcPaVjjrMJFQQwGpwowEnZNEtHs7DfR7hCZsmaK3VA4HUK0YarT+w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/better-sqlite3": { "version": "12.9.0", "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.9.0.tgz", @@ -2164,6 +2364,24 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", @@ -2254,6 +2472,19 @@ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "license": "ISC" }, + "node_modules/chromium-bidi": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz", + "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==", + "license": "Apache-2.0", + "dependencies": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "node_modules/ci-info": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", @@ -2308,6 +2539,93 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -2336,7 +2654,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "optional": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2348,8 +2665,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/color-string": { "version": "1.9.1", @@ -2393,6 +2709,32 @@ "node": ">= 0.6" } }, + "node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -2405,6 +2747,15 @@ "node": ">=4" } }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -2459,6 +2810,20 @@ "node": ">=4.0.0" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2527,6 +2892,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/devtools-protocol": { + "version": "0.0.1595872", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1595872.tgz", + "integrity": "sha512-kRfgp8vWVjBu/fbYCiVFiOqsCk3CrMKEo3WbgGT2NXK2dG7vawWPBljixajVgGK9II8rDO9G0oD0zLt3I1daRg==", + "license": "BSD-3-Clause" + }, "node_modules/diff": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", @@ -2605,6 +2976,30 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-ex/node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, "node_modules/es-module-lexer": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", @@ -2676,6 +3071,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -2689,6 +3105,15 @@ "node": ">=4" } }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, "node_modules/estree-walker": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", @@ -2698,6 +3123,15 @@ "@types/estree": "^1.0.0" } }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -2713,6 +3147,15 @@ "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", "license": "MIT" }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -2740,6 +3183,32 @@ "node": ">=0.10.0" } }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -2765,6 +3234,15 @@ "reusify": "^1.0.4" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -2865,6 +3343,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-east-asian-width": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", @@ -2877,6 +3364,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -3163,6 +3679,32 @@ "url": "https://opencollective.com/express" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -3183,6 +3725,22 @@ ], "license": "BSD-3-Clause" }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/import-meta-resolve": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", @@ -3205,6 +3763,15 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "license": "ISC" }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/is-arrayish": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.4.tgz", @@ -3374,6 +3941,12 @@ "node": ">=6" } }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -3404,6 +3977,12 @@ "node": ">=6" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, "node_modules/load-yaml-file": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/load-yaml-file/-/load-yaml-file-0.2.0.tgz", @@ -3530,6 +4109,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/marked": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.2.tgz", + "integrity": "sha512-NsmlUYBS/Zg57rgDWMYdnre6OTj4e+qq/JS2ot3KrYLSoHLw+sDu0Nm1ZGpRgYAq6c+b1ekaY5NzVchMCQnzcg==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/mdast-util-definitions": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-6.0.0.tgz", @@ -4397,6 +4988,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -4451,6 +5048,15 @@ "node": ">= 10" } }, + "node_modules/netmask": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/nlcst-to-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/nlcst-to-string/-/nlcst-to-string-4.0.0.tgz", @@ -4640,6 +5246,68 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-latin": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz", @@ -4679,6 +5347,12 @@ "node": ">=8" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -4796,6 +5470,15 @@ "node": ">=6" } }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -4828,6 +5511,40 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pump": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", @@ -4838,6 +5555,45 @@ "once": "^1.3.1" } }, + "node_modules/puppeteer": { + "version": "24.42.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.42.0.tgz", + "integrity": "sha512-94MoPfFp2eY3eYIMdINkez4IOP5TMHntlZbVx06fHlQTtiQiYgaY0L2Zzfod8PVUkPqP7m3Qlre2v8YS8cudPA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.13.0", + "chromium-bidi": "14.0.0", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1595872", + "puppeteer-core": "24.42.0", + "typed-query-selector": "^2.12.1" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "24.42.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.42.0.tgz", + "integrity": "sha512-T4zXokk/izH01fYPhyyev1A4piWiOKrYq7CUFpdoYQxmOnXoV6YjUabmfIjCYkNspSoAXIxRid3Tw+Vg0fthYg==", + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.13.0", + "chromium-bidi": "14.0.0", + "debug": "^4.4.3", + "devtools-protocol": "0.0.1595872", + "typed-query-selector": "^2.12.1", + "webdriver-bidi-protocol": "0.4.1", + "ws": "^8.19.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -5063,6 +5819,24 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/restore-cursor": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", @@ -5442,6 +6216,54 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "license": "MIT" }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "license": "MIT", + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5488,6 +6310,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/streamx": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", + "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", + "license": "MIT", + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -5598,6 +6431,24 @@ "node": ">=6" } }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "license": "MIT", + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/tinyexec": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", @@ -5669,8 +6520,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true + "license": "0BSD" }, "node_modules/tunnel-agent": { "version": "0.6.0", @@ -5696,6 +6546,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-query-selector": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz", + "integrity": "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ==", + "license": "MIT" + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -6037,6 +6893,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/webdriver-bidi-protocol": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz", + "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==", + "license": "Apache-2.0" + }, "node_modules/which-pm": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/which-pm/-/which-pm-3.0.1.tgz", @@ -6096,18 +6958,66 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xxhash-wasm": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", "integrity": "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA==", "license": "MIT" }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", @@ -6117,6 +7027,57 @@ "node": ">=12" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yocto-queue": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", diff --git a/package.json b/package.json index 46e803d..864bcc9 100644 --- a/package.json +++ b/package.json @@ -9,10 +9,12 @@ "start": "node dist/server/entry.mjs" }, "dependencies": { - "astro": "^4.5.0", "@astrojs/node": "^8.2.0", + "astro": "^4.5.0", "better-sqlite3": "^12.9.0", + "marked": "^18.0.2", "nodemailer": "^6.9.13", + "puppeteer": "^24.42.0", "uuid": "^9.0.1" }, "devDependencies": { diff --git a/public/scripts/printExport.js b/public/scripts/printExport.js new file mode 100644 index 0000000..04e3dab --- /dev/null +++ b/public/scripts/printExport.js @@ -0,0 +1,121 @@ +// printExport.js +// Einbinden: +// Aufruf: window.printCV(element, cvTitle, cvSettings, template) + +window.printCV = async function (el, cvTitle, cvSettings, template) { + + // ── 1. Lokale CSS-Datei direkt fetchen (kein CORS-Problem) ────── + let globalCss = ''; + try { + globalCss = await fetch('/styles/global.css').then(r => r.text()); + } catch (e) { + console.warn('global.css nicht geladen', e); + } + + // ── 2. Inline + +${el.innerHTML} +`; + + // ── 6. Blob-URL statt document.write ──────────────────────────── + const blob = new Blob([html], { type: 'text/html; charset=utf-8' }); + const blobUrl = URL.createObjectURL(blob); + + const win = window.open(blobUrl, '_blank', 'width=900,height=1200'); + if (!win) { + alert('Popup wurde blockiert. Bitte Popup-Blocker deaktivieren.'); + URL.revokeObjectURL(blobUrl); + return; + } + + win.addEventListener('load', () => { + // Blob-URL freigeben sobald geladen + URL.revokeObjectURL(blobUrl); + + // Fonts + base64-PNGs (Icons) etwas Zeit geben + setTimeout(() => { + win.focus(); + win.print(); + win.addEventListener('afterprint', () => win.close()); + }, 1000); + }); +}; \ No newline at end of file diff --git a/src/components/templates/Template1 copy.astro b/src/components/templates/Template1 copy.astro new file mode 100644 index 0000000..c2c33a7 --- /dev/null +++ b/src/components/templates/Template1 copy.astro @@ -0,0 +1,611 @@ +--- +import type { CVData, CVSettings } from "../../types"; +import { + IcoEmail, + IcoPhone, + IcoCal, + IcoFlag, + IcoHome, + IcoPerson, + IcoEdu, + IcoExp, +} from "../../lib/icons_svg"; + +interface Props { + data: CVData; + settings: CVSettings; +} +const { data: d, settings: s } = Astro.props; +const p = d.personal; +const T = s.language === "en"; + +function date(str: string) { + return str || (T ? "present" : "heute"); +} +function datRange(from: string, to: string, cur: boolean) { + return `${from} – ${cur ? (T ? "present" : "Aktuell") : to}`; +} +--- + +
+
+ + + + +
+
{p.firstName} {p.lastName}
+ {p.jobTitle &&
{p.jobTitle}
} + + { + d.profile && ( +
+
+ 📋 + {T ? "PROFILE" : "PROFIL"} +
+

{d.profile}

+
+ ) + } + + { + d.education.length > 0 && ( +
+
+ 🎓 + {T ? "EDUCATION & QUALIFICATIONS" : "BILDUNG UND QUALIFIKATION"} +
+ {d.education.map((e) => ( +
+
+ {datRange(e.dateFrom, e.dateTo, e.current)} +
+
+
{e.degree}
+ {e.school && ( +
+ {e.school} + {e.location ? `, ${e.location}` : ""} +
+ )} + {e.description &&
{e.description}
} + {e.bullets.filter(Boolean).length > 0 && ( +
    + {e.bullets.filter(Boolean).map((b) => ( +
  • {b}
  • + ))} +
+ )} +
+
+ ))} +
+ ) + } + + { + d.experience.length > 0 && ( +
+
+ 💼 + {T ? "WORK EXPERIENCE" : "ARBEITSERFAHRUNG"} +
+ {d.experience.map((e) => ( +
+
+ {datRange(e.dateFrom, e.dateTo, e.current)} +
+
+
{e.jobTitle}
+ {e.company && ( +
+ {e.company} + {e.location ? `, ${e.location}` : ""} +
+ )} + {e.description &&
{e.description}
} + {e.bullets.filter(Boolean).length > 0 && ( +
    + {e.bullets.filter(Boolean).map((b) => { + const [bold, rest] = b.includes(":") + ? [b.split(":")[0], b.split(":").slice(1).join(":")] + : [null, b]; + return ( +
  • + {bold ? ( + <> + {bold}:{rest} + + ) : ( + rest + )} +
  • + ); + })} +
+ )} +
+
+ ))} +
+ ) + } + + { + d.skills.length > 0 && ( +
+
+ 🔧 + {T ? "COMPETENCIES" : "KOMPETENZEN"} +
+ {Object.entries( + d.skills.reduce((acc: any, sk) => { + const cat = sk.category || (T ? "Other" : "Sonstiges"); + if (!acc[cat]) acc[cat] = []; + acc[cat].push(sk); + return acc; + }, {}), + ).map(([cat, skills]: any) => ( +
+
{cat}
+
+
+ {skills + .map( + (sk: any) => + `${sk.name}: ${["", "Grundkenntnisse", "Gut", "Sehr gut", "Experte", "Meister"][sk.level] || sk.level}`, + ) + .join(" · ")} +
+
+
+ ))} +
+ ) + } + + { + d.certifications.length > 0 && ( +
+
+ 📜 + {T ? "COURSES, TRAINING" : "WEITERBILDUNGEN, KURSE"} +
+ {d.certifications.map((c) => ( +
+
+ {c.dateFrom} + {c.dateTo && c.dateTo !== c.dateFrom ? ` – ${c.dateTo}` : ""} +
+
+
{c.name}
+ {c.issuer && ( +
+ {c.issuer} + {c.location ? `, ${c.location}` : ""} +
+ )} +
+
+ ))} +
+ ) + } + + { + d.achievements.length > 0 && ( +
+
+ 🏆 + {T ? "ACHIEVEMENTS" : "ERFOLGE"} +
+
    + {d.achievements.filter(Boolean).map((a) => ( +
  • {a}
  • + ))} +
+
+ ) + } +
+
+
+ + diff --git a/src/components/templates/Template1.astro b/src/components/templates/Template1.astro index 6a8d4ea..09acdc9 100644 --- a/src/components/templates/Template1.astro +++ b/src/components/templates/Template1.astro @@ -1,5 +1,18 @@ --- -import type { CVData, CVSettings } from '../../types'; +import type { CVData, CVSettings } from "../../types"; +import { + IcoEmail, + IcoPhone, + IcoCal, + IcoFlag, + IcoHome, + IcoPerson, + IcoEdu, + IcoExp, +} from "../../lib/icons_svg"; +// markdown +import { marked } from "marked"; +marked.setOptions({ breaks: true }); interface Props { data: CVData; @@ -7,68 +20,215 @@ interface Props { } const { data: d, settings: s } = Astro.props; const p = d.personal; -const T = s.language === 'en'; +const T = s.language === "en"; -function date(str: string) { return str || (T ? 'present' : 'heute'); } +function date(str: string) { + return str || (T ? "present" : "heute"); +} function datRange(from: string, to: string, cur: boolean) { - return `${from} – ${cur ? (T ? 'present' : 'Aktuell') : to}`; + return `${from} – ${cur ? (T ? "present" : "Aktuell") : to}`; } --- -
+ +
-
diff --git a/src/lib/icons.ts b/src/lib/icons.ts index 89b2838..cf4b90b 100644 --- a/src/lib/icons.ts +++ b/src/lib/icons.ts @@ -1,8 +1,43 @@ -export const IcoEmail = ''; -export const IcoPhone = ''; -export const IcoCal = ''; -export const IcoFlag = ''; -export const IcoHome = ''; -export const IcoPerson = ''; -export const IcoEdu = ''; -export const IcoExp = ''; +/*** + + + + + + + + +***/ + +// Auto-generated PNG icons (pure Node.js, no dependencies) +// All icons: 20×20px transparent PNG, dark (#444) strokes + +export const IcoEmail = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAh0lEQVR4nO3TwQ2AIAwFUFZgBVboAF7Yy9EYTcMBU0pbS+vRJj9RiU/yIyn988nknI9a6xUJALQHjGIjpZSTBfuCJX1XJnDa/kZNC4i/qqEYw9cs2O81lGLc++sDAeUwM0hRCdsCMSph2yBGOcwFjv6kNReozeuPHT56tHhvplqs51eK1nFobtcpL2DD8YzgAAAAAElFTkSuQmCC'; +export const IcoPhone = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAk0lEQVR4nL2U0QnAIAxEXcEVsoID9Cd7dbSO1pKPgyPEDz2pINgWX8+7mNb+GL33y93fmGOMRwYChhk/OAIMdTKMgWZ2y7BKoexj9lAOp4JJUPYQoUjQWSjbYVUbY433ywqr48mlBChuCiuMb+zvNpSft8uJlUFpBi/bwN2HN0u+Vi1NDoqh0pHzyB4eaXGhqiqdD7k1qABJQoCkAAAAAElFTkSuQmCC'; +export const IcoCal = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAd0lEQVR4nGNgoBcQFBS0NzY23k+sOEHg4uLyH4SVlJTqiRHHsBWmkFyM4mpKDcNwNbItIEEQxiaGSxyngcjhAtIAEgMFB3LwYBMnykBY2OIKc7wRRbMwpGmkkIKJDkNiwaiBQ8lAqqVDWP6kFKNkSXISNDKGGQYAXgddF8yb6SQAAAAASUVORK5CYII='; +export const IcoFlag = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAbUlEQVR4nGNgoCUQFBS0d3Fx+W9sbLxfSUmpHoQpMhBkGC4MswBkKVUMxGcJQQORFcE0ETIcFExEGYgOQBpxGYoRHNgMBCkC8fEZBJLDGrbICgh5k6gIIhRGJCcjslxBjIEUJ+hRA0cNHG4GAgCFC737QwHrBwAAAABJRU5ErkJggg=='; +export const IcoHome = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAi0lEQVR4nN3TwQ2AIAwFUFZgBVZgAC/s5WiOpvkHkvqh2ArxIMlPBORRiIbwixZj3HLOxzKslHIi0yhjU6jE8Iyx12gPq82NjjA3asHMqAd7RCWGpJR2CyjX3NC60wzYnExWWUGunCuR73eviUHGtHn1RNoCVIWxZaC1/x3ojQry52PN8EfAbp4wdgHqUfXzO48S3QAAAABJRU5ErkJggg=='; +export const IcoPerson = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAkElEQVR4nGNgGNJAUFDQ3tjYeL+Li8t/GFZSUqon2zBkg5AxyBKKDAO5CoSRXUuSocga0eVABsPkQBYTZSCh8CI5PGlmILZwQg5fog1EDidkTejJiCjDYAA9/aFjoiOEGEOJNgxfYiY5kZNjGF5DYd4D0bCcQQzGGgzIriM1sJEdgl+QSIDVMZQWTRj6B7WBAIJ63VJfa/AIAAAAAElFTkSuQmCC'; +export const IcoEdu = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAmUlEQVR4nO2T0Q2AMAhEWaErdIUO4E/3cjRH02BSQ/Aq15r4JQkfWngnVxT545PIOa+llC2ltLwG1Vp3m1NgbUAg/0yBfKN+JXtOg4bq/XgjHnmPTxus0ozhHnq+nDEcXdwFDH0h/LsBWyBVbUAgKxoCUTM6o4Gt0I5jL83XNZEQaL2L6uCG9Mbs5dMPIAJWKEpqb1WVSQQ7AMPb/9EAxbXuAAAAAElFTkSuQmCC'; +export const IcoExp = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAWklEQVR4nGNgGAXIQFBQ0N7FxeU/MjY2Nt5PtoHohsGwkpJSPUUGglwFMoRoA7F5jVSMEhSUGobhcnSvoWNi5TEMxBU2JMuPGjhq4GAykGpZD5SlqGEgqJABABvuMFINme7XAAAAAElFTkSuQmCC'; +export const IcoRings = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAhklEQVR4nGNgGAWDHwgKCtobGxvvd3Fx+Q/DSkpK9bjECRqGrIEYDLKEKMNAtoMwNlehi2M1FFkBLnEQBlkMkwMZjE0cDHCFC7oXccljhCfNDEQPD3wGIoc7hoHI4YEsiSyOHL7oyQgjUrBFALEYI0KIMRSXOF7DkL0DS2/oYYZNfBRQFwAAfjjIRhgi+hMAAAAASUVORK5CYII='; +export const IcoLink = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAd0lEQVR4nGNgGJZAUFDQ3sXF5T8IGxsb76eaYTCspKRUT7FhIEPIMhCbi0BiyOIgNtEGgsII3XvIYiQZBgPohlBkGC6XUmQYemRQzTCqGUR1wygyEN0w5MggOZuhhxdybiDLpegxicwnK3bRXTO4Ei8MkO09WgEA2VWQrb3SXjUAAAAASUVORK5CYII='; +export const IcoGlobe = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAn0lEQVR4nL2U0Q3AIAhEXcEVXIEB+uNeHa2jtfFDc7GHoKY1ucSIPBHQEP4aMcYjpXTmnG+UiFxlfQrGQAxcDjVhZWPvyOZVQyhz8IhCPdcc6VWAPukor41Gx1JRbay61Jee4gTi7Zp9J3eo74Es6VZR0N6A2H87RWn9SBedQDWY1VeiBoLln5XWbhRqfQ4qbCVSEzaTU9dfyEbfcxboAUk6gd3N0EXVAAAAAElFTkSuQmCC'; + +// ── Helper: PNG-Data-URL als fertiges -Tag ─────────────────────── +export function icoTag(src: string, size = '1em'): string { + return ``; +} + +// ── Fertige -Tags für direkte Verwendung mit set:html ──────────── +export const IcoEmailTag = icoTag(IcoEmail); +export const IcoPhoneTag = icoTag(IcoPhone); +export const IcoCalTag = icoTag(IcoCal); +export const IcoFlagTag = icoTag(IcoFlag); +export const IcoHomeTag = icoTag(IcoHome); +export const IcoPersonTag = icoTag(IcoPerson); +export const IcoEduTag = icoTag(IcoEdu); +export const IcoExpTag = icoTag(IcoExp); +export const IcoRingsTag = icoTag(IcoRings); +export const IcoLinkTag = icoTag(IcoLink); +export const IcoGlobeTag = icoTag(IcoGlobe); diff --git a/src/lib/icons_svg.ts b/src/lib/icons_svg.ts new file mode 100644 index 0000000..783ec3b --- /dev/null +++ b/src/lib/icons_svg.ts @@ -0,0 +1,80 @@ +// Wraps SVG string as base64 img tag → PDF-kompatibel +// Buffer.from() statt btoa() → Node/Astro-SSR-kompatibel +// Farbe ist fest kodiert (kein currentColor) → funktioniert in data:image/svg+xml + +/*** +--- +import { IcoPersonW, IcoEmailW, makeIco } from '../lib/icons'; +--- + + +
+
+ +
+ +
+
+
+ +
+ { + TEMPLATES.map((tpl) => ( +
+
+ + T{tpl.id} + +
+
+ <> + {tpl.name} +
+ + + {tpl.desc} + +
+
+ )) + } +
+
+
+
+ +
+
+ +
+ {t("settings.primaryColor")} +
+
+
+ +
+ {t("settings.accentColor")} +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+ { + cv.public && ( +
+ + +
+ ) + } +
+
+
+
+ + +
+
+ {de ? "Vorschau (A4)" : "Preview (A4)"} +
+ + + +
+
+
+
+
+ {cv.template === 1 && } + {cv.template === 2 && } + {cv.template === 3 && } + {cv.template === 4 && } +
+
+
+
+
+ + - - -
-
- - - {cv.title} -
-
- {de ? '✏️ Daten bearbeiten' : '✏️ Edit Data'} - - -
- - -
-
-
+ + +${el.innerHTML}`; -
- -
-
- -
- -
- -
-
- -
- {TEMPLATES.map(tpl => ( -
-
T{tpl.id}
-
{tpl.name}
{tpl.desc}
-
- ))} -
-
-
-
- -
-
- {t('settings.primaryColor')} -
-
-
- {t('settings.accentColor')} -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
-
- - -
- {cv.public && ( -
- - -
- )} -
-
- -
-
- - -
-
- {de ? 'Vorschau (A4)' : 'Preview (A4)'} -
- - -
-
-
-
-
- {cv.template === 1 && } - {cv.template === 2 && } - {cv.template === 3 && } - {cv.template === 4 && } -
-
-
-
-
- - + // ── HTML Export ─────────────────────────────────────────────── + window.exportHTML = async function () { + document.getElementById("export-menu").classList.add("hidden"); + const el = document.getElementById("cv-preview"); + const globalCss = await fetch("/styles/global.css") + .then((r) => r.text()) + .catch(() => ""); + const inlineStyles = Array.from(document.querySelectorAll("style")) + .map((s) => s.textContent) + .join("\n"); + const fontLinks = Array.from( + document.querySelectorAll('link[rel="stylesheet"]'), + ) + .map((l) => l.outerHTML) + .join("\n"); + const html = ` + + + + ${cvTitle} + ${fontLinks} + + + + ${el.outerHTML} +`; + const a = document.createElement("a"); + a.href = URL.createObjectURL(new Blob([html], { type: "text/html" })); + a.download = (cvTitle || "lebenslauf") + ".html"; + a.click(); + }; + + // ── Mobile toggle ───────────────────────────────────────────── + if (window.innerWidth <= 900) { + document.getElementById("toggle-preview").style.display = "inline-flex"; + } + document + .getElementById("toggle-preview") + ?.addEventListener("click", () => { + document + .getElementById("editor-layout") + .classList.toggle("show-preview"); + }); + + diff --git a/src/styles/global.css b/src/styles/global.css index 8266def..61b0c95 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -1,5 +1,11 @@ /* ── Reset & Base ─────────────────────────────────────────────────── */ -*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} :root { --navy: #1B2A5E; @@ -12,16 +18,40 @@ --danger: #E53E3E; --success: #38A169; --radius: 8px; - --shadow: 0 1px 3px rgba(0,0,0,.1), 0 1px 2px rgba(0,0,0,.06); - --shadow-md: 0 4px 6px -1px rgba(0,0,0,.1), 0 2px 4px -1px rgba(0,0,0,.06); + --shadow: 0 1px 3px rgba(0, 0, 0, .1), 0 1px 2px rgba(0, 0, 0, .06); + --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06); } -html { font-size: 16px; } -body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; background: var(--bg); color: var(--text); line-height: 1.5; } -a { color: var(--accent); text-decoration: none; } -a:hover { text-decoration: underline; } -button { cursor: pointer; font-family: inherit; } -input, textarea, select { font-family: inherit; } +html { + font-size: 16px; +} + +body { + font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; + background: var(--bg); + color: var(--text); + line-height: 1.5; +} + +a { + color: var(--accent); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +button { + cursor: pointer; + font-family: inherit; +} + +input, +textarea, +select { + font-family: inherit; +} /* ── Layout ───────────────────────────────────────────────────────── */ .app-header { @@ -37,13 +67,37 @@ input, textarea, select { font-family: inherit; } z-index: 100; box-shadow: var(--shadow-md); } -.app-header .logo { font-size: 1.1rem; font-weight: 700; color: white; letter-spacing: -0.3px; } -.app-header .logo span { color: var(--accent); } -.app-header nav { display: flex; align-items: center; gap: 16px; } -.app-header nav a { color: rgba(255,255,255,.8); font-size: .875rem; transition: color .2s; } -.app-header nav a:hover { color: white; text-decoration: none; } + +.app-header .logo { + font-size: 1.1rem; + font-weight: 700; + color: white; + letter-spacing: -0.3px; +} + +.app-header .logo span { + color: var(--accent); +} + +.app-header nav { + display: flex; + align-items: center; + gap: 16px; +} + +.app-header nav a { + color: rgba(255, 255, 255, .8); + font-size: .875rem; + transition: color .2s; +} + +.app-header nav a:hover { + color: white; + text-decoration: none; +} + .app-header .btn-logout { - background: rgba(255,255,255,.12); + background: rgba(255, 255, 255, .12); color: white; border: none; padding: 6px 14px; @@ -51,56 +105,182 @@ input, textarea, select { font-family: inherit; } font-size: .875rem; transition: background .2s; } -.app-header .btn-logout:hover { background: rgba(255,255,255,.22); } -.container { max-width: 1200px; margin: 0 auto; padding: 0 24px; } -.page { padding: 32px 24px; max-width: 1200px; margin: 0 auto; } +.app-header .btn-logout:hover { + background: rgba(255, 255, 255, .22); +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 0 24px; +} + +.page { + padding: 32px 24px; + max-width: 1200px; + margin: 0 auto; +} /* ── Buttons ──────────────────────────────────────────────────────── */ .btn { - display: inline-flex; align-items: center; gap: 6px; - padding: 8px 16px; border-radius: var(--radius); - font-size: .875rem; font-weight: 500; - border: none; transition: all .15s; + display: inline-flex; + align-items: center; + gap: 6px; + padding: 8px 16px; + border-radius: var(--radius); + font-size: .875rem; + font-weight: 500; + border: none; + transition: all .15s; text-decoration: none; } -.btn-primary { background: var(--navy); color: white; } -.btn-primary:hover { background: #243572; text-decoration: none; } -.btn-accent { background: var(--accent); color: white; } -.btn-accent:hover { background: #3a6ab5; text-decoration: none; } -.btn-ghost { background: transparent; color: var(--text); border: 1px solid var(--border); } -.btn-ghost:hover { background: var(--bg); text-decoration: none; } -.btn-danger { background: var(--danger); color: white; border: none; } -.btn-danger:hover { background: #c53030; } -.btn-sm { padding: 5px 10px; font-size: .8rem; } -.btn-lg { padding: 12px 24px; font-size: 1rem; } -.btn:disabled { opacity: .5; cursor: not-allowed; } + +.btn-primary { + background: var(--navy); + color: white; +} + +.btn-primary:hover { + background: #243572; + text-decoration: none; +} + +.btn-accent { + background: var(--accent); + color: white; +} + +.btn-accent:hover { + background: #3a6ab5; + text-decoration: none; +} + +.btn-ghost { + background: transparent; + color: var(--text); + border: 1px solid var(--border); +} + +.btn-ghost:hover { + background: var(--bg); + text-decoration: none; +} + +.btn-danger { + background: var(--danger); + color: white; + border: none; +} + +.btn-danger:hover { + background: #c53030; +} + +.btn-sm { + padding: 5px 10px; + font-size: .8rem; +} + +.btn-lg { + padding: 12px 24px; + font-size: 1rem; +} + +.btn:disabled { + opacity: .5; + cursor: not-allowed; +} /* ── Cards ────────────────────────────────────────────────────────── */ .card { - background: var(--surface); border: 1px solid var(--border); - border-radius: var(--radius); box-shadow: var(--shadow); + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + box-shadow: var(--shadow); overflow: hidden; } -.card-body { padding: 24px; } -.card-header { padding: 16px 24px; border-bottom: 1px solid var(--border); background: var(--bg); } -.card-footer { padding: 16px 24px; border-top: 1px solid var(--border); background: var(--bg); } + +.card-body { + padding: 24px; +} + +.card-header { + padding: 16px 24px; + border-bottom: 1px solid var(--border); + background: var(--bg); +} + +.card-footer { + padding: 16px 24px; + border-top: 1px solid var(--border); + background: var(--bg); +} /* ── Forms ────────────────────────────────────────────────────────── */ -.form-group { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; } -.form-label { font-size: .875rem; font-weight: 500; color: var(--text); } +.form-group { + display: flex; + flex-direction: column; + gap: 6px; + margin-bottom: 16px; +} + +.form-label { + font-size: .875rem; + font-weight: 500; + color: var(--text); +} + .form-input { - padding: 8px 12px; border: 1px solid var(--border); border-radius: var(--radius); - font-size: .875rem; background: var(--surface); color: var(--text); + padding: 8px 12px; + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: .875rem; + background: var(--surface); + color: var(--text); transition: border-color .15s, box-shadow .15s; } -.form-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(74,123,197,.15); } -.form-textarea { min-height: 80px; resize: vertical; } -.form-select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748B' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 8px center; padding-right: 32px; } -.form-hint { font-size: .75rem; color: var(--muted); } -.form-error { font-size: .75rem; color: var(--danger); } -.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; } -@media (max-width: 600px) { .form-row { grid-template-columns: 1fr; } } + +.form-input:focus { + outline: none; + border-color: var(--accent); + box-shadow: 0 0 0 3px rgba(74, 123, 197, .15); +} + +.form-textarea { + min-height: 80px; + resize: vertical; +} + +.form-select { + appearance: none; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2364748B' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-position: right 8px center; + padding-right: 32px; +} + +.form-hint { + font-size: .75rem; + color: var(--muted); +} + +.form-error { + font-size: .75rem; + color: var(--danger); +} + +.form-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; +} + +@media (max-width: 600px) { + .form-row { + grid-template-columns: 1fr; + } +} /* ── Auth Page ────────────────────────────────────────────────────── */ .auth-page { @@ -110,24 +290,50 @@ input, textarea, select { font-family: inherit; } background: linear-gradient(135deg, var(--navy) 0%, #2d4a9e 100%); padding: 24px; } + .auth-card { width: 100%; max-width: 420px; background: white; border-radius: 12px; padding: 40px 36px; - box-shadow: 0 20px 60px rgba(0,0,0,.3); + box-shadow: 0 20px 60px rgba(0, 0, 0, .3); } -.auth-logo { font-size: 1.5rem; font-weight: 800; color: var(--navy); margin-bottom: 8px; } -.auth-logo span { color: var(--accent); } -.auth-subtitle { color: var(--muted); font-size: .875rem; margin-bottom: 32px; } + +.auth-logo { + font-size: 1.5rem; + font-weight: 800; + color: var(--navy); + margin-bottom: 8px; +} + +.auth-logo span { + color: var(--accent); +} + +.auth-subtitle { + color: var(--muted); + font-size: .875rem; + margin-bottom: 32px; +} + .otp-input { - width: 100%; text-align: center; font-size: 2rem; font-weight: 700; - letter-spacing: 12px; padding: 16px; border: 2px solid var(--border); - border-radius: var(--radius); font-family: monospace; + width: 100%; + text-align: center; + font-size: 2rem; + font-weight: 700; + letter-spacing: 12px; + padding: 16px; + border: 2px solid var(--border); + border-radius: var(--radius); + font-family: monospace; transition: border-color .15s; } -.otp-input:focus { outline: none; border-color: var(--accent); } + +.otp-input:focus { + outline: none; + border-color: var(--accent); +} /* ── Dashboard ────────────────────────────────────────────────────── */ .cv-grid { @@ -136,13 +342,21 @@ input, textarea, select { font-family: inherit; } gap: 20px; margin-top: 24px; } + .cv-card { - background: var(--surface); border: 1px solid var(--border); - border-radius: var(--radius); overflow: hidden; + background: var(--surface); + border: 1px solid var(--border); + border-radius: var(--radius); + overflow: hidden; transition: box-shadow .2s, transform .2s; cursor: pointer; } -.cv-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); } + +.cv-card:hover { + box-shadow: var(--shadow-md); + transform: translateY(-2px); +} + .cv-card-preview { height: 180px; background: linear-gradient(135deg, var(--navy) 0%, #243572 40%, #3a6ab5 100%); @@ -151,30 +365,50 @@ input, textarea, select { font-family: inherit; } position: relative; overflow: hidden; } + .cv-card-preview .t-badge { position: absolute; top: 10px; right: 10px; - background: rgba(255,255,255,.2); + background: rgba(255, 255, 255, .2); color: white; font-size: .7rem; padding: 2px 8px; border-radius: 20px; } + .cv-card-preview .preview-mini { width: 90px; height: 127px; background: white; border-radius: 3px; - box-shadow: 0 4px 20px rgba(0,0,0,.3); + box-shadow: 0 4px 20px rgba(0, 0, 0, .3); overflow: hidden; display: flex; flex-direction: column; } -.cv-card-body { padding: 16px; } -.cv-card-title { font-weight: 600; font-size: .95rem; margin-bottom: 4px; } -.cv-card-meta { font-size: .75rem; color: var(--muted); } -.cv-card-actions { display: flex; gap: 8px; padding: 12px 16px; border-top: 1px solid var(--border); } + +.cv-card-body { + padding: 16px; +} + +.cv-card-title { + font-weight: 600; + font-size: .95rem; + margin-bottom: 4px; +} + +.cv-card-meta { + font-size: .75rem; + color: var(--muted); +} + +.cv-card-actions { + display: flex; + gap: 8px; + padding: 12px 16px; + border-top: 1px solid var(--border); +} /* ── Editor ───────────────────────────────────────────────────────── */ .editor-layout { @@ -183,6 +417,7 @@ input, textarea, select { font-family: inherit; } height: calc(100vh - 56px); overflow: hidden; } + .editor-sidebar { background: var(--surface); border-right: 1px solid var(--border); @@ -190,6 +425,7 @@ input, textarea, select { font-family: inherit; } flex-direction: column; overflow: hidden; } + .editor-tabs { display: flex; overflow-x: auto; @@ -197,7 +433,11 @@ input, textarea, select { font-family: inherit; } background: var(--bg); scrollbar-width: none; } -.editor-tabs::-webkit-scrollbar { display: none; } + +.editor-tabs::-webkit-scrollbar { + display: none; +} + .editor-tab { padding: 10px 14px; font-size: .8rem; @@ -210,13 +450,22 @@ input, textarea, select { font-family: inherit; } cursor: pointer; transition: all .15s; } -.editor-tab.active { color: var(--navy); border-bottom-color: var(--navy); } -.editor-tab:hover { color: var(--text); } + +.editor-tab.active { + color: var(--navy); + border-bottom-color: var(--navy); +} + +.editor-tab:hover { + color: var(--text); +} + .editor-content { flex: 1; overflow-y: auto; padding: 20px; } + .editor-preview { background: #E8ECF0; display: flex; @@ -224,6 +473,7 @@ input, textarea, select { font-family: inherit; } overflow: hidden; position: relative; } + .editor-preview-toolbar { background: var(--surface); border-bottom: 1px solid var(--border); @@ -234,6 +484,7 @@ input, textarea, select { font-family: inherit; } gap: 8px; flex-shrink: 0; } + .preview-wrap { flex: 1; overflow: auto; @@ -242,11 +493,13 @@ input, textarea, select { font-family: inherit; } justify-content: center; padding: 24px; } + .preview-scale-wrap { transform-origin: top center; width: 794px; flex-shrink: 0; } + .save-status { font-size: .75rem; color: var(--success); @@ -254,7 +507,10 @@ input, textarea, select { font-family: inherit; } align-items: center; gap: 4px; } -.save-status.saving { color: var(--muted); } + +.save-status.saving { + color: var(--muted); +} /* ── Section Items ────────────────────────────────────────────────── */ .item-card { @@ -263,6 +519,7 @@ input, textarea, select { font-family: inherit; } margin-bottom: 12px; overflow: hidden; } + .item-card-header { padding: 10px 14px; background: var(--bg); @@ -272,29 +529,79 @@ input, textarea, select { font-family: inherit; } cursor: pointer; user-select: none; } -.item-card-title { font-size: .875rem; font-weight: 500; } -.item-card-body { padding: 14px; display: none; } -.item-card.open .item-card-body { display: block; } -.item-card-actions { display: flex; gap: 6px; } + +.item-card-title { + font-size: .875rem; + font-weight: 500; +} + +.item-card-body { + padding: 14px; + display: none; +} + +.item-card.open .item-card-body { + display: block; +} + +.item-card-actions { + display: flex; + gap: 6px; +} /* ── Skill level ──────────────────────────────────────────────────── */ -.skill-dots { display: flex; gap: 4px; align-items: center; } +.skill-dots { + display: flex; + gap: 4px; + align-items: center; +} + .skill-dot { - width: 14px; height: 14px; border-radius: 50%; + width: 14px; + height: 14px; + border-radius: 50%; border: 2px solid var(--accent); background: transparent; cursor: pointer; transition: background .15s; } -.skill-dot.filled { background: var(--accent); } + +.skill-dot.filled { + background: var(--accent); +} /* ── Color picker ─────────────────────────────────────────────────── */ -.color-row { display: flex; align-items: center; gap: 10px; } -.color-swatch { width: 36px; height: 36px; border-radius: 6px; border: 2px solid var(--border); cursor: pointer; overflow: hidden; padding: 0; } -.color-swatch input[type=color] { width: 200%; height: 200%; margin: -50%; border: none; cursor: pointer; } +.color-row { + display: flex; + align-items: center; + gap: 10px; +} + +.color-swatch { + width: 36px; + height: 36px; + border-radius: 6px; + border: 2px solid var(--border); + cursor: pointer; + overflow: hidden; + padding: 0; +} + +.color-swatch input[type=color] { + width: 200%; + height: 200%; + margin: -50%; + border: none; + cursor: pointer; +} /* ── Template selector ────────────────────────────────────────────── */ -.template-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; } +.template-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; +} + .template-option { border: 2px solid var(--border); border-radius: var(--radius); @@ -302,15 +609,28 @@ input, textarea, select { font-family: inherit; } cursor: pointer; transition: border-color .15s; } -.template-option.selected { border-color: var(--accent); } -.template-option:hover { border-color: var(--accent); } + +.template-option.selected { + border-color: var(--accent); +} + +.template-option:hover { + border-color: var(--accent); +} + .template-thumb { height: 100px; background: linear-gradient(135deg, #1B2A5E, #4A7BC5); display: grid; place-items: center; } -.template-label { padding: 8px; font-size: .75rem; font-weight: 500; text-align: center; } + +.template-label { + padding: 8px; + font-size: .75rem; + font-weight: 500; + text-align: center; +} /* ── CV Templates (A4) ────────────────────────────────────────────── */ .cv-a4 { @@ -320,7 +640,7 @@ input, textarea, select { font-family: inherit; } position: relative; font-size: 13px; line-height: 1.4; - box-shadow: 0 8px 32px rgba(0,0,0,.15); + box-shadow: 0 8px 32px rgba(0, 0, 0, .15); } /* ── Public CV Page ───────────────────────────────────────────────── */ @@ -333,6 +653,7 @@ input, textarea, select { font-family: inherit; } align-items: center; gap: 20px; } + .cv-public-actions { display: flex; gap: 10px; @@ -341,45 +662,183 @@ input, textarea, select { font-family: inherit; } } /* ── Alerts ───────────────────────────────────────────────────────── */ -.alert { padding: 12px 16px; border-radius: var(--radius); font-size: .875rem; margin-bottom: 16px; } -.alert-success { background: #f0fff4; border: 1px solid #9ae6b4; color: #276749; } -.alert-error { background: #fff5f5; border: 1px solid #fed7d7; color: #9b2c2c; } -.alert-info { background: #ebf8ff; border: 1px solid #bee3f8; color: #2a4a6b; } +.alert { + padding: 12px 16px; + border-radius: var(--radius); + font-size: .875rem; + margin-bottom: 16px; +} + +.alert-success { + background: #f0fff4; + border: 1px solid #9ae6b4; + color: #276749; +} + +.alert-error { + background: #fff5f5; + border: 1px solid #fed7d7; + color: #9b2c2c; +} + +.alert-info { + background: #ebf8ff; + border: 1px solid #bee3f8; + color: #2a4a6b; +} /* ── Utils ────────────────────────────────────────────────────────── */ -.flex { display: flex; } -.items-center { align-items: center; } -.justify-between { justify-content: space-between; } -.gap-2 { gap: 8px; } -.gap-3 { gap: 12px; } -.mt-1 { margin-top: 4px; } -.mt-2 { margin-top: 8px; } -.mt-4 { margin-top: 16px; } -.mt-6 { margin-top: 24px; } -.mb-2 { margin-bottom: 8px; } -.mb-4 { margin-bottom: 16px; } -.text-sm { font-size: .875rem; } -.text-xs { font-size: .75rem; } -.text-muted { color: var(--muted); } -.font-bold { font-weight: 700; } -.font-semibold { font-weight: 600; } -.w-full { width: 100%; } -.hidden { display: none !important; } -.divider { border: none; border-top: 1px solid var(--border); margin: 20px 0; } +.flex { + display: flex; +} + +.items-center { + align-items: center; +} + +.justify-between { + justify-content: space-between; +} + +.gap-2 { + gap: 8px; +} + +.gap-3 { + gap: 12px; +} + +.mt-1 { + margin-top: 4px; +} + +.mt-2 { + margin-top: 8px; +} + +.mt-4 { + margin-top: 16px; +} + +.mt-6 { + margin-top: 24px; +} + +.mb-2 { + margin-bottom: 8px; +} + +.mb-4 { + margin-bottom: 16px; +} + +.text-sm { + font-size: .875rem; +} + +.text-xs { + font-size: .75rem; +} + +.text-muted { + color: var(--muted); +} + +.font-bold { + font-weight: 700; +} + +.font-semibold { + font-weight: 600; +} + +.w-full { + width: 100%; +} + +.hidden { + display: none !important; +} + +.divider { + border: none; + border-top: 1px solid var(--border); + margin: 20px 0; +} + +/* ── Responsive ───────────────────────────────────────────────────── */ +@media (max-width: 900px) { + .editor-layout { + grid-template-columns: 1fr; + } + + .editor-preview { + display: none; + } + + .editor-layout.show-preview .editor-sidebar { + display: none; + } + + .editor-layout.show-preview .editor-preview { + display: flex; + } + + .preview-scale-wrap { + width: 100%; + transform: none !important; + } + + .cv-a4 { + width: 100% !important; + } +} /* ── Print ────────────────────────────────────────────────────────── */ @media print { - body { background: white !important; } - .cv-public-actions, .app-header { display: none !important; } - .cv-public-wrap { padding: 0 !important; background: white !important; } - .cv-a4 { box-shadow: none !important; } -} + @page { + size: A4 portrait; + margin: 10mm 0 0 0; + } -@media (max-width: 900px) { - .editor-layout { grid-template-columns: 1fr; } - .editor-preview { display: none; } - .editor-layout.show-preview .editor-sidebar { display: none; } - .editor-layout.show-preview .editor-preview { display: flex; } - .preview-scale-wrap { width: 100%; transform: none !important; } - .cv-a4 { width: 100% !important; } -} + @page :first { + margin: 0 0 0 0; + } + + body, + .cv-public-wrap, + .editor-preview { + background: white !important; + padding: 0 !important; + } + + .app-header, + .cv-public-bar, + .cv-public-actions, + .editor-sidebar, + .editor-preview-toolbar { + display: none !important; + } + + .cv-a4 { + width: 210mm !important; + box-shadow: none !important; + } + + * { + -webkit-print-color-adjust: exact !important; + print-color-adjust: exact !important; + } + + .t1-entry, + .t1-sec, + .t2-tl-item, + .t2-sec, + .t3-entry, + .t3-sec, + .t4-entry, + .t4-sec { + break-inside: avoid; + page-break-inside: avoid; + } +} \ No newline at end of file