mirror of
https://github.com/duhanbalci/dreport.git
synced 2026-07-01 18:39:16 +00:00
fixes
This commit is contained in:
@@ -5,6 +5,14 @@
|
||||
"": {
|
||||
"name": "frontend",
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.20.1",
|
||||
"@codemirror/language": "^6.12.3",
|
||||
"@codemirror/state": "^6.6.0",
|
||||
"@codemirror/view": "^6.41.0",
|
||||
"@lezer/highlight": "^1.2.3",
|
||||
"@lezer/lr": "^1.4.8",
|
||||
"codemirror": "^6.0.2",
|
||||
"codemirror-lang-dexpr": "file:../../rust-expr/editor",
|
||||
"pinia": "^3.0.4",
|
||||
"vue": "^3.5.31",
|
||||
},
|
||||
@@ -31,16 +39,98 @@
|
||||
|
||||
"@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
|
||||
|
||||
"@codemirror/autocomplete": ["@codemirror/autocomplete@6.20.1", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A=="],
|
||||
|
||||
"@codemirror/commands": ["@codemirror/commands@6.10.3", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.6.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q=="],
|
||||
|
||||
"@codemirror/language": ["@codemirror/language@6.12.3", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", "@lezer/common": "^1.5.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "style-mod": "^4.0.0" } }, "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA=="],
|
||||
|
||||
"@codemirror/lint": ["@codemirror/lint@6.9.5", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.35.0", "crelt": "^1.0.5" } }, "sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA=="],
|
||||
|
||||
"@codemirror/search": ["@codemirror/search@6.6.0", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.37.0", "crelt": "^1.0.5" } }, "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw=="],
|
||||
|
||||
"@codemirror/state": ["@codemirror/state@6.6.0", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ=="],
|
||||
|
||||
"@codemirror/view": ["@codemirror/view@6.41.0", "", { "dependencies": { "@codemirror/state": "^6.6.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-6H/qadXsVuDY219Yljhohglve8xf4B8xJkVOEWfA5uiYKiTFppjqsvsfR5iPA0RbvRBoOyTZpbLIxe9+0UR8xA=="],
|
||||
|
||||
"@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" } }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="],
|
||||
|
||||
"@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="],
|
||||
|
||||
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.7", "", { "os": "aix", "cpu": "ppc64" }, "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.7", "", { "os": "android", "cpu": "arm" }, "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.7", "", { "os": "android", "cpu": "arm64" }, "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.27.7", "", { "os": "android", "cpu": "x64" }, "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.7", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.7", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.7", "", { "os": "linux", "cpu": "arm" }, "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.7", "", { "os": "linux", "cpu": "ia32" }, "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.7", "", { "os": "linux", "cpu": "ppc64" }, "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.7", "", { "os": "linux", "cpu": "none" }, "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.7", "", { "os": "linux", "cpu": "s390x" }, "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.7", "", { "os": "linux", "cpu": "x64" }, "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA=="],
|
||||
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.7", "", { "os": "none", "cpu": "x64" }, "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw=="],
|
||||
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.7", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.7", "", { "os": "openbsd", "cpu": "x64" }, "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg=="],
|
||||
|
||||
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.7", "", { "os": "none", "cpu": "arm64" }, "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.7", "", { "os": "sunos", "cpu": "x64" }, "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.7", "", { "os": "win32", "cpu": "ia32" }, "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.7", "", { "os": "win32", "cpu": "x64" }, "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg=="],
|
||||
|
||||
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
|
||||
|
||||
"@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="],
|
||||
|
||||
"@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="],
|
||||
|
||||
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
||||
|
||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="],
|
||||
|
||||
"@lezer/common": ["@lezer/common@1.5.1", "", {}, "sha512-6YRVG9vBkaY7p1IVxL4s44n5nUnaNnGM2/AckNgYOnxTG2kWh1vR8BMxPseWPjRNpb5VtXnMpeYAEAADoRV1Iw=="],
|
||||
|
||||
"@lezer/generator": ["@lezer/generator@1.8.0", "", { "dependencies": { "@lezer/common": "^1.1.0", "@lezer/lr": "^1.3.0" }, "bin": { "lezer-generator": "src/lezer-generator.cjs" } }, "sha512-/SF4EDWowPqV1jOgoGSGTIFsE7Ezdr7ZYxyihl5eMKVO5tlnpIhFcDavgm1hHY5GEonoOAEnJ0CU0x+tvuAuUg=="],
|
||||
|
||||
"@lezer/highlight": ["@lezer/highlight@1.2.3", "", { "dependencies": { "@lezer/common": "^1.3.0" } }, "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g=="],
|
||||
|
||||
"@lezer/lr": ["@lezer/lr@1.4.8", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA=="],
|
||||
|
||||
"@marijn/find-cluster-break": ["@marijn/find-cluster-break@1.0.2", "", {}, "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g=="],
|
||||
|
||||
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.2", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-sNXv5oLJ7ob93xkZ1XnxisYhGYXfaG9f65/ZgYuAu3qt7b3NadcOEhLvx28hv31PgX8SZJRYrAIPQilQmFpLVw=="],
|
||||
|
||||
"@one-ini/wasm": ["@one-ini/wasm@0.1.1", "", {}, "sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw=="],
|
||||
@@ -83,6 +173,56 @@
|
||||
|
||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.2", "", {}, "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw=="],
|
||||
|
||||
"@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.60.1", "", { "os": "android", "cpu": "arm" }, "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA=="],
|
||||
|
||||
"@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.60.1", "", { "os": "android", "cpu": "arm64" }, "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA=="],
|
||||
|
||||
"@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.60.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw=="],
|
||||
|
||||
"@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.60.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew=="],
|
||||
|
||||
"@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.60.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w=="],
|
||||
|
||||
"@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.60.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.60.1", "", { "os": "linux", "cpu": "arm" }, "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g=="],
|
||||
|
||||
"@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.60.1", "", { "os": "linux", "cpu": "arm" }, "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.60.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ=="],
|
||||
|
||||
"@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.60.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA=="],
|
||||
|
||||
"@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ=="],
|
||||
|
||||
"@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw=="],
|
||||
|
||||
"@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.60.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw=="],
|
||||
|
||||
"@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.60.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg=="],
|
||||
|
||||
"@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.60.1", "", { "os": "linux", "cpu": "none" }, "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg=="],
|
||||
|
||||
"@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.60.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.60.1", "", { "os": "linux", "cpu": "x64" }, "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg=="],
|
||||
|
||||
"@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.60.1", "", { "os": "linux", "cpu": "x64" }, "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w=="],
|
||||
|
||||
"@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.60.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw=="],
|
||||
|
||||
"@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.60.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA=="],
|
||||
|
||||
"@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.60.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g=="],
|
||||
|
||||
"@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.60.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.60.1", "", { "os": "win32", "cpu": "x64" }, "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg=="],
|
||||
|
||||
"@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.60.1", "", { "os": "win32", "cpu": "x64" }, "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ=="],
|
||||
|
||||
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||
|
||||
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
||||
@@ -153,12 +293,16 @@
|
||||
|
||||
"abbrev": ["abbrev@2.0.0", "", {}, "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ=="],
|
||||
|
||||
"acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
|
||||
|
||||
"alien-signals": ["alien-signals@3.1.2", "", {}, "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="],
|
||||
|
||||
"any-promise": ["any-promise@1.3.0", "", {}, "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="],
|
||||
|
||||
"assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
@@ -167,24 +311,42 @@
|
||||
|
||||
"brace-expansion": ["brace-expansion@2.0.3", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA=="],
|
||||
|
||||
"bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="],
|
||||
|
||||
"cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="],
|
||||
|
||||
"chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="],
|
||||
|
||||
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||
|
||||
"codemirror": ["codemirror@6.0.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/lint": "^6.0.0", "@codemirror/search": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0" } }, "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw=="],
|
||||
|
||||
"codemirror-lang-dexpr": ["codemirror-lang-dexpr@file:../../rust-expr/editor", { "devDependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/generator": "^1.8.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.4.8", "codemirror": "^6.0.2", "tsup": "^8.0.0", "typescript": "^5.0.0" }, "peerDependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0" } }],
|
||||
|
||||
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
|
||||
|
||||
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
||||
|
||||
"commander": ["commander@10.0.1", "", {}, "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="],
|
||||
|
||||
"confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
|
||||
|
||||
"config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="],
|
||||
|
||||
"consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="],
|
||||
|
||||
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
||||
|
||||
"copy-anything": ["copy-anything@4.0.5", "", { "dependencies": { "is-what": "^5.2.0" } }, "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA=="],
|
||||
|
||||
"crelt": ["crelt@1.0.6", "", {}, "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="],
|
||||
|
||||
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
||||
|
||||
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
|
||||
|
||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
||||
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||
|
||||
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
||||
@@ -197,12 +359,16 @@
|
||||
|
||||
"es-module-lexer": ["es-module-lexer@2.0.0", "", {}, "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw=="],
|
||||
|
||||
"esbuild": ["esbuild@0.27.7", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.7", "@esbuild/android-arm": "0.27.7", "@esbuild/android-arm64": "0.27.7", "@esbuild/android-x64": "0.27.7", "@esbuild/darwin-arm64": "0.27.7", "@esbuild/darwin-x64": "0.27.7", "@esbuild/freebsd-arm64": "0.27.7", "@esbuild/freebsd-x64": "0.27.7", "@esbuild/linux-arm": "0.27.7", "@esbuild/linux-arm64": "0.27.7", "@esbuild/linux-ia32": "0.27.7", "@esbuild/linux-loong64": "0.27.7", "@esbuild/linux-mips64el": "0.27.7", "@esbuild/linux-ppc64": "0.27.7", "@esbuild/linux-riscv64": "0.27.7", "@esbuild/linux-s390x": "0.27.7", "@esbuild/linux-x64": "0.27.7", "@esbuild/netbsd-arm64": "0.27.7", "@esbuild/netbsd-x64": "0.27.7", "@esbuild/openbsd-arm64": "0.27.7", "@esbuild/openbsd-x64": "0.27.7", "@esbuild/openharmony-arm64": "0.27.7", "@esbuild/sunos-x64": "0.27.7", "@esbuild/win32-arm64": "0.27.7", "@esbuild/win32-ia32": "0.27.7", "@esbuild/win32-x64": "0.27.7" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w=="],
|
||||
|
||||
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
|
||||
|
||||
"expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],
|
||||
|
||||
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
||||
|
||||
"fix-dts-default-cjs-exports": ["fix-dts-default-cjs-exports@1.0.1", "", { "dependencies": { "magic-string": "^0.30.17", "mlly": "^1.7.4", "rollup": "^4.34.8" } }, "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg=="],
|
||||
|
||||
"foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
@@ -223,6 +389,8 @@
|
||||
|
||||
"jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="],
|
||||
|
||||
"joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="],
|
||||
|
||||
"js-beautify": ["js-beautify@1.15.4", "", { "dependencies": { "config-chain": "^1.1.13", "editorconfig": "^1.0.4", "glob": "^10.4.2", "js-cookie": "^3.0.5", "nopt": "^7.2.1" }, "bin": { "css-beautify": "js/bin/css-beautify.js", "html-beautify": "js/bin/html-beautify.js", "js-beautify": "js/bin/js-beautify.js" } }, "sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA=="],
|
||||
|
||||
"js-cookie": ["js-cookie@3.0.5", "", {}, "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="],
|
||||
@@ -251,6 +419,12 @@
|
||||
|
||||
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
|
||||
|
||||
"lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="],
|
||||
|
||||
"lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="],
|
||||
|
||||
"load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="],
|
||||
|
||||
"lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
|
||||
|
||||
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
||||
@@ -261,12 +435,20 @@
|
||||
|
||||
"mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="],
|
||||
|
||||
"mlly": ["mlly@1.8.2", "", { "dependencies": { "acorn": "^8.16.0", "pathe": "^2.0.3", "pkg-types": "^1.3.1", "ufo": "^1.6.3" } }, "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
|
||||
|
||||
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
|
||||
|
||||
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"nopt": ["nopt@7.2.1", "", { "dependencies": { "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w=="],
|
||||
|
||||
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
||||
|
||||
"obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="],
|
||||
|
||||
"package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="],
|
||||
@@ -287,18 +469,30 @@
|
||||
|
||||
"pinia": ["pinia@3.0.4", "", { "dependencies": { "@vue/devtools-api": "^7.7.7" }, "peerDependencies": { "typescript": ">=4.5.0", "vue": "^3.5.11" }, "optionalPeers": ["typescript"] }, "sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw=="],
|
||||
|
||||
"pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="],
|
||||
|
||||
"pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="],
|
||||
|
||||
"playwright": ["playwright@1.58.2", "", { "dependencies": { "playwright-core": "1.58.2" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A=="],
|
||||
|
||||
"playwright-core": ["playwright-core@1.58.2", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg=="],
|
||||
|
||||
"postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="],
|
||||
|
||||
"postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="],
|
||||
|
||||
"proto-list": ["proto-list@1.2.4", "", {}, "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA=="],
|
||||
|
||||
"readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
|
||||
|
||||
"resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="],
|
||||
|
||||
"rfdc": ["rfdc@1.4.1", "", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
|
||||
|
||||
"rolldown": ["rolldown@1.0.0-rc.12", "", { "dependencies": { "@oxc-project/types": "=0.122.0", "@rolldown/pluginutils": "1.0.0-rc.12" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.12", "@rolldown/binding-darwin-arm64": "1.0.0-rc.12", "@rolldown/binding-darwin-x64": "1.0.0-rc.12", "@rolldown/binding-freebsd-x64": "1.0.0-rc.12", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.12", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.12", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.12", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.12", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.12", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.12", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.12", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.12" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-yP4USLIMYrwpPHEFB5JGH1uxhcslv6/hL0OyvTuY+3qlOSJvZ7ntYnoWpehBxufkgN0cvXxppuTu5hHa/zPh+A=="],
|
||||
|
||||
"rollup": ["rollup@4.60.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.60.1", "@rollup/rollup-android-arm64": "4.60.1", "@rollup/rollup-darwin-arm64": "4.60.1", "@rollup/rollup-darwin-x64": "4.60.1", "@rollup/rollup-freebsd-arm64": "4.60.1", "@rollup/rollup-freebsd-x64": "4.60.1", "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", "@rollup/rollup-linux-arm-musleabihf": "4.60.1", "@rollup/rollup-linux-arm64-gnu": "4.60.1", "@rollup/rollup-linux-arm64-musl": "4.60.1", "@rollup/rollup-linux-loong64-gnu": "4.60.1", "@rollup/rollup-linux-loong64-musl": "4.60.1", "@rollup/rollup-linux-ppc64-gnu": "4.60.1", "@rollup/rollup-linux-ppc64-musl": "4.60.1", "@rollup/rollup-linux-riscv64-gnu": "4.60.1", "@rollup/rollup-linux-riscv64-musl": "4.60.1", "@rollup/rollup-linux-s390x-gnu": "4.60.1", "@rollup/rollup-linux-x64-gnu": "4.60.1", "@rollup/rollup-linux-x64-musl": "4.60.1", "@rollup/rollup-openbsd-x64": "4.60.1", "@rollup/rollup-openharmony-arm64": "4.60.1", "@rollup/rollup-win32-arm64-msvc": "4.60.1", "@rollup/rollup-win32-ia32-msvc": "4.60.1", "@rollup/rollup-win32-x64-gnu": "4.60.1", "@rollup/rollup-win32-x64-msvc": "4.60.1", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w=="],
|
||||
|
||||
"semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
||||
|
||||
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
||||
@@ -309,6 +503,8 @@
|
||||
|
||||
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||
|
||||
"source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="],
|
||||
|
||||
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
||||
|
||||
"speakingurl": ["speakingurl@14.0.1", "", {}, "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ=="],
|
||||
@@ -325,8 +521,16 @@
|
||||
|
||||
"strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||
|
||||
"style-mod": ["style-mod@4.1.3", "", {}, "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="],
|
||||
|
||||
"sucrase": ["sucrase@3.35.1", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", "lines-and-columns": "^1.1.6", "mz": "^2.7.0", "pirates": "^4.0.1", "tinyglobby": "^0.2.11", "ts-interface-checker": "^0.1.9" }, "bin": { "sucrase": "bin/sucrase", "sucrase-node": "bin/sucrase-node" } }, "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw=="],
|
||||
|
||||
"superjson": ["superjson@2.2.6", "", { "dependencies": { "copy-anything": "^4" } }, "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA=="],
|
||||
|
||||
"thenify": ["thenify@3.3.1", "", { "dependencies": { "any-promise": "^1.0.0" } }, "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw=="],
|
||||
|
||||
"thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="],
|
||||
|
||||
"tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
|
||||
|
||||
"tinyexec": ["tinyexec@1.0.4", "", {}, "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw=="],
|
||||
@@ -335,10 +539,18 @@
|
||||
|
||||
"tinyrainbow": ["tinyrainbow@3.1.0", "", {}, "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw=="],
|
||||
|
||||
"tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="],
|
||||
|
||||
"ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"tsup": ["tsup@8.5.1", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.27.0", "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "^0.7.6", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing=="],
|
||||
|
||||
"typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="],
|
||||
|
||||
"ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="],
|
||||
|
||||
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
|
||||
|
||||
"vite": ["vite@8.0.3", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.12", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-B9ifbFudT1TFhfltfaIPgjo9Z3mDynBTJSUYxTjOQruf/zHH+ezCQKcoqO+h7a9Pw9Nm/OtlXAiGT1axBgwqrQ=="],
|
||||
@@ -353,6 +565,8 @@
|
||||
|
||||
"vue-tsc": ["vue-tsc@3.2.6", "", { "dependencies": { "@volar/typescript": "2.4.28", "@vue/language-core": "3.2.6" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "bin/vue-tsc.js" } }, "sha512-gYW/kWI0XrwGzd0PKc7tVB/qpdeAkIZLNZb10/InizkQjHjnT8weZ/vBarZoj4kHKbUTZT/bAVgoOr8x4NsQ/Q=="],
|
||||
|
||||
"w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="],
|
||||
|
||||
"whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
|
||||
|
||||
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
||||
@@ -371,6 +585,8 @@
|
||||
|
||||
"@vue/compiler-sfc/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||
|
||||
"codemirror-lang-dexpr/typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"happy-dom/@types/node": ["@types/node@24.12.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ=="],
|
||||
|
||||
"playwright/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="],
|
||||
@@ -383,6 +599,10 @@
|
||||
|
||||
"strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="],
|
||||
|
||||
"tsup/tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="],
|
||||
|
||||
"wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
"test:visual": "playwright test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/autocomplete": "^6.20.1",
|
||||
"@codemirror/language": "^6.12.3",
|
||||
"@codemirror/state": "^6.6.0",
|
||||
"@codemirror/view": "^6.41.0",
|
||||
"@lezer/highlight": "^1.2.3",
|
||||
"@lezer/lr": "^1.4.8",
|
||||
"codemirror": "^6.0.2",
|
||||
"codemirror-lang-dexpr": "file:../../rust-expr/editor",
|
||||
"pinia": "^3.0.4",
|
||||
"vue": "^3.5.31"
|
||||
},
|
||||
|
||||
237
frontend/src/components/common/DexprEditor.vue
Normal file
237
frontend/src/components/common/DexprEditor.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount, watch, computed } from 'vue'
|
||||
import { EditorView, lineNumbers } from '@codemirror/view'
|
||||
import { EditorState } from '@codemirror/state'
|
||||
import { dexpr } from 'codemirror-lang-dexpr'
|
||||
import type { DexprLanguageInfo } from 'codemirror-lang-dexpr'
|
||||
import { useSchemaStore } from '../../stores/schema'
|
||||
import type { SchemaNode } from '../../core/schema-parser'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: string
|
||||
placeholder?: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
}>()
|
||||
|
||||
const editorEl = ref<HTMLDivElement>()
|
||||
let view: EditorView | null = null
|
||||
let debounceTimer: ReturnType<typeof setTimeout> | null = null
|
||||
|
||||
function emitDebounced(val: string) {
|
||||
if (debounceTimer) clearTimeout(debounceTimer)
|
||||
debounceTimer = setTimeout(() => {
|
||||
emit('update:modelValue', val)
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const schemaStore = useSchemaStore()
|
||||
|
||||
/** Schema tree'den dexpr LanguageInfo formatina donustur */
|
||||
function schemaToLanguageInfo(): DexprLanguageInfo {
|
||||
const info: DexprLanguageInfo = {
|
||||
functions: [
|
||||
{ name: 'log', signature: '(...args) -> Null', doc: 'Deger yazdir' },
|
||||
{ name: 'rand', signature: '(min: Number, max: Number) -> Number', doc: 'Rastgele sayi' },
|
||||
],
|
||||
methods: {
|
||||
String: [
|
||||
{ name: 'upper', signature: '() -> String' },
|
||||
{ name: 'lower', signature: '() -> String' },
|
||||
{ name: 'trim', signature: '() -> String' },
|
||||
{ name: 'length', signature: '() -> Number' },
|
||||
{ name: 'contains', signature: '(substr: String) -> Boolean' },
|
||||
{ name: 'replace', signature: '(old: String, new: String) -> String' },
|
||||
{ name: 'split', signature: '(delim: String) -> StringList' },
|
||||
{ name: 'substring', signature: '(start: Number, end?: Number) -> String' },
|
||||
{ name: 'startsWith', signature: '(prefix: String) -> Boolean' },
|
||||
{ name: 'endsWith', signature: '(suffix: String) -> Boolean' },
|
||||
{ name: 'charAt', signature: '(index: Number) -> String' },
|
||||
{ name: 'trimStart', signature: '() -> String' },
|
||||
{ name: 'trimEnd', signature: '() -> String' },
|
||||
],
|
||||
Number: [],
|
||||
Boolean: [],
|
||||
NumberList: [
|
||||
{ name: 'length', signature: '() -> Number' },
|
||||
{ name: 'sum', signature: '() -> Number' },
|
||||
{ name: 'avg', signature: '() -> Number' },
|
||||
{ name: 'min', signature: '() -> Number' },
|
||||
{ name: 'max', signature: '() -> Number' },
|
||||
{ name: 'first', signature: '() -> Number' },
|
||||
{ name: 'last', signature: '() -> Number' },
|
||||
{ name: 'sort', signature: '() -> NumberList' },
|
||||
{ name: 'reverse', signature: '() -> NumberList' },
|
||||
{ name: 'contains', signature: '(value: Number) -> Boolean' },
|
||||
],
|
||||
StringList: [
|
||||
{ name: 'length', signature: '() -> Number' },
|
||||
{ name: 'join', signature: '(delim?: String) -> String' },
|
||||
{ name: 'first', signature: '() -> String' },
|
||||
{ name: 'last', signature: '() -> String' },
|
||||
{ name: 'sort', signature: '() -> StringList' },
|
||||
{ name: 'reverse', signature: '() -> StringList' },
|
||||
{ name: 'contains', signature: '(value: String) -> Boolean' },
|
||||
],
|
||||
Object: [
|
||||
{ name: 'keys', signature: '() -> StringList' },
|
||||
{ name: 'values', signature: '() -> StringList | NumberList' },
|
||||
{ name: 'length', signature: '() -> Number' },
|
||||
{ name: 'contains', signature: '(key: String) -> Boolean' },
|
||||
{ name: 'get', signature: '(key: String) -> any' },
|
||||
],
|
||||
},
|
||||
variables: [],
|
||||
}
|
||||
|
||||
// Schema tree'deki top-level object property'lerinden dexpr degiskenleri olustur
|
||||
const tree = schemaStore.schemaTree
|
||||
for (const child of tree.children) {
|
||||
if (child.type === 'object') {
|
||||
const fields = child.children.map(f => ({
|
||||
name: f.key,
|
||||
type: schemaToDexprType(f),
|
||||
}))
|
||||
info.variables!.push({
|
||||
name: child.key,
|
||||
type: 'Object',
|
||||
doc: child.title,
|
||||
fields,
|
||||
})
|
||||
} else {
|
||||
info.variables!.push({
|
||||
name: child.key,
|
||||
type: schemaToDexprType(child),
|
||||
doc: child.title,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
function schemaToDexprType(node: SchemaNode): 'String' | 'Number' | 'Boolean' | 'Object' | 'NumberList' | 'StringList' {
|
||||
switch (node.type) {
|
||||
case 'number':
|
||||
case 'integer':
|
||||
return 'Number'
|
||||
case 'boolean':
|
||||
return 'Boolean'
|
||||
case 'object':
|
||||
return 'Object'
|
||||
case 'array':
|
||||
return 'StringList'
|
||||
default:
|
||||
return 'String'
|
||||
}
|
||||
}
|
||||
|
||||
const langInfo = computed(() => schemaToLanguageInfo())
|
||||
|
||||
function createState(doc: string): EditorState {
|
||||
return EditorState.create({
|
||||
doc,
|
||||
extensions: [
|
||||
EditorView.updateListener.of(update => {
|
||||
if (update.docChanged) {
|
||||
const val = update.state.doc.toString()
|
||||
if (val !== props.modelValue) {
|
||||
emitDebounced(val)
|
||||
}
|
||||
}
|
||||
}),
|
||||
lineNumbers(),
|
||||
dexpr(langInfo.value),
|
||||
EditorView.lineWrapping,
|
||||
EditorView.theme({
|
||||
'&': {
|
||||
fontSize: '11px',
|
||||
border: '1px solid #e2e8f0',
|
||||
borderRadius: '4px',
|
||||
backgroundColor: '#fff',
|
||||
maxHeight: '120px',
|
||||
},
|
||||
'&.cm-focused': {
|
||||
outline: '2px solid #93c5fd',
|
||||
outlineOffset: '-1px',
|
||||
},
|
||||
'.cm-scroller': {
|
||||
overflow: 'auto',
|
||||
},
|
||||
'.cm-content': {
|
||||
padding: '4px 6px',
|
||||
fontFamily: '"JetBrains Mono", "Fira Code", "Cascadia Code", monospace',
|
||||
minHeight: '20px',
|
||||
},
|
||||
'.cm-line': {
|
||||
padding: '0',
|
||||
},
|
||||
'.cm-gutters': {
|
||||
backgroundColor: '#f8fafc',
|
||||
borderRight: '1px solid #e2e8f0',
|
||||
color: '#94a3b8',
|
||||
fontSize: '10px',
|
||||
minWidth: '20px',
|
||||
paddingLeft: '2px',
|
||||
paddingRight: '4px',
|
||||
},
|
||||
'.cm-activeLine': {
|
||||
backgroundColor: 'transparent',
|
||||
},
|
||||
'.cm-tooltip.cm-tooltip-autocomplete': {
|
||||
fontSize: '11px',
|
||||
zIndex: '9999',
|
||||
},
|
||||
}),
|
||||
EditorState.tabSize.of(2),
|
||||
EditorView.contentAttributes.of({
|
||||
'aria-label': 'dexpr expression editor',
|
||||
}),
|
||||
],
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!editorEl.value) return
|
||||
view = new EditorView({
|
||||
state: createState(props.modelValue ?? ''),
|
||||
parent: editorEl.value,
|
||||
})
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
view?.destroy()
|
||||
view = null
|
||||
})
|
||||
|
||||
// Disaridan gelen deger degisikligi (undo/redo vs.)
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
if (!view) return
|
||||
const current = view.state.doc.toString()
|
||||
if (current !== newVal) {
|
||||
view.dispatch({
|
||||
changes: { from: 0, to: current.length, insert: newVal ?? '' },
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Schema degisince editor'u yeniden olustur (autocomplete guncellenmeli)
|
||||
watch(langInfo, () => {
|
||||
if (!view) return
|
||||
const doc = view.state.doc.toString()
|
||||
view.setState(createState(doc))
|
||||
}, { deep: true })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="editorEl" class="dexpr-editor" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.dexpr-editor {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -168,7 +168,7 @@ function applyZoom(delta: number, clientX: number, clientY: number) {
|
||||
}
|
||||
|
||||
function onKeyDown(e: KeyboardEvent) {
|
||||
if (e.code === 'Space' && !e.repeat && !(e.target instanceof HTMLInputElement || e.target instanceof HTMLSelectElement || e.target instanceof HTMLTextAreaElement)) {
|
||||
if (e.code === 'Space' && !e.repeat && !(e.target instanceof HTMLInputElement || e.target instanceof HTMLSelectElement || e.target instanceof HTMLTextAreaElement || (e.target as HTMLElement)?.isContentEditable)) {
|
||||
e.preventDefault()
|
||||
spaceHeld.value = true
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { computed } from 'vue'
|
||||
import { useTemplateStore } from '../../stores/template'
|
||||
import { useEditorStore } from '../../stores/editor'
|
||||
import { isContainer } from '../../core/types'
|
||||
import type { ContainerElement, TextStyle } from '../../core/types'
|
||||
import type { ContainerElement, TextStyle, RepeatingTableElement, TableStyle } from '../../core/types'
|
||||
import type { ElementLayout } from '../../core/layout-types'
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -32,6 +32,10 @@ const isText = computed(() => {
|
||||
|
||||
const isLine = computed(() => selected.value?.type === 'line')
|
||||
|
||||
const isTable = computed(() => selected.value?.type === 'repeating_table')
|
||||
const tableEl = computed(() => isTable.value ? selected.value as RepeatingTableElement : null)
|
||||
const tableStyle = computed(() => tableEl.value?.style as TableStyle | undefined)
|
||||
|
||||
const toolbarStyle = computed(() => {
|
||||
const el = selected.value
|
||||
if (!el) return { display: 'none' }
|
||||
@@ -66,6 +70,12 @@ function setGap(e: Event) { update({ gap: parseFloat((e.target as HTMLInputEleme
|
||||
// Text
|
||||
function setFontWeight(w: string) { updateStyle('fontWeight', w) }
|
||||
function setTextAlign(a: string) { updateStyle('align', a) }
|
||||
|
||||
// Table
|
||||
function updateTableStyle(key: string, value: unknown) {
|
||||
if (!selected.value) return
|
||||
update({ style: { ...selected.value.style, [key]: value } })
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -230,6 +240,66 @@ function setTextAlign(a: string) { updateStyle('align', a) }
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ===== Repeating Table ===== -->
|
||||
<template v-if="isTable && tableStyle">
|
||||
<!-- Font size -->
|
||||
<div class="et__group et__group--gap" data-tip="Yazi Boyutu">
|
||||
<svg class="et__gap-icon" width="12" height="12" viewBox="0 0 12 12" fill="none">
|
||||
<path d="M2 10L6 2l4 8" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" fill="none"/>
|
||||
<line x1="3.5" y1="7" x2="8.5" y2="7" stroke="currentColor" stroke-width="1" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<input type="number" class="et__num" step="1" min="6" :value="tableStyle.fontSize ?? 10" @input="(e) => updateTableStyle('fontSize', parseFloat((e.target as HTMLInputElement).value) || 10)" />
|
||||
</div>
|
||||
|
||||
<div class="et__sep" />
|
||||
|
||||
<!-- Header bg color -->
|
||||
<div class="et__group">
|
||||
<label class="et__color-wrap" data-tip="Header Rengi">
|
||||
<input type="color" class="et__color" :value="tableStyle.headerBg ?? '#f0f0f0'" @input="(e) => updateTableStyle('headerBg', (e.target as HTMLInputElement).value)" />
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
|
||||
<rect x="2" y="2" width="10" height="4" rx="1" :fill="tableStyle.headerBg ?? '#f0f0f0'" stroke="#94a3b8" stroke-width="0.5"/>
|
||||
<rect x="2" y="7" width="10" height="2" rx="0.5" fill="none" stroke="#94a3b8" stroke-width="0.5"/>
|
||||
<rect x="2" y="10" width="10" height="2" rx="0.5" fill="none" stroke="#94a3b8" stroke-width="0.5"/>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Zebra color -->
|
||||
<div class="et__group">
|
||||
<label class="et__color-wrap" data-tip="Zebra Rengi">
|
||||
<input type="color" class="et__color" :value="tableStyle.zebraOdd ?? '#fafafa'" @input="(e) => updateTableStyle('zebraOdd', (e.target as HTMLInputElement).value)" />
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
|
||||
<rect x="2" y="2" width="10" height="2.5" rx="0.5" fill="none" stroke="#94a3b8" stroke-width="0.5"/>
|
||||
<rect x="2" y="5.5" width="10" height="2.5" rx="0.5" :fill="tableStyle.zebraOdd ?? '#fafafa'" stroke="#94a3b8" stroke-width="0.5"/>
|
||||
<rect x="2" y="9" width="10" height="2.5" rx="0.5" fill="none" stroke="#94a3b8" stroke-width="0.5"/>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="et__sep" />
|
||||
|
||||
<!-- Border color -->
|
||||
<div class="et__group">
|
||||
<label class="et__color-wrap" data-tip="Kenarlik Rengi">
|
||||
<input type="color" class="et__color" :value="tableStyle.borderColor ?? '#cccccc'" @input="(e) => updateTableStyle('borderColor', (e.target as HTMLInputElement).value)" />
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none">
|
||||
<rect x="2" y="2" width="10" height="10" rx="1" fill="none" :stroke="tableStyle.borderColor ?? '#cccccc'" stroke-width="1.5"/>
|
||||
<line x1="2" y1="6" x2="12" y2="6" :stroke="tableStyle.borderColor ?? '#cccccc'" stroke-width="0.8"/>
|
||||
<line x1="7" y1="2" x2="7" y2="12" :stroke="tableStyle.borderColor ?? '#cccccc'" stroke-width="0.8"/>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- Border width -->
|
||||
<div class="et__group et__group--gap" data-tip="Kenarlik (mm)">
|
||||
<svg class="et__gap-icon" width="12" height="12" viewBox="0 0 12 12" fill="none">
|
||||
<rect x="1" y="1" width="10" height="10" rx="1" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
||||
</svg>
|
||||
<input type="number" class="et__num" step="0.1" min="0" :value="tableStyle.borderWidth ?? 0.5" @input="(e) => updateTableStyle('borderWidth', parseFloat((e.target as HTMLInputElement).value) || 0)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- ===== Line ===== -->
|
||||
<template v-if="isLine">
|
||||
<!-- Stroke width -->
|
||||
@@ -282,34 +352,6 @@ function setTextAlign(a: string) { updateStyle('align', a) }
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Tooltip */
|
||||
[data-tip] {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
[data-tip]::after {
|
||||
content: attr(data-tip);
|
||||
position: absolute;
|
||||
bottom: calc(100% + 6px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: #0f172a;
|
||||
color: #e2e8f0;
|
||||
font-size: 10px;
|
||||
padding: 3px 6px;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
[data-tip]:hover::after,
|
||||
[data-tip]:focus-within::after {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Button */
|
||||
.et__btn {
|
||||
display: flex;
|
||||
|
||||
@@ -124,7 +124,7 @@ function findDeepestContainer(mouseX: number, mouseY: number, excludeId?: string
|
||||
if (!l) continue
|
||||
|
||||
const cx = l.x_mm * s
|
||||
const cy = l.y_mm * s
|
||||
const cy = l.y_mm * s + pageYOffset(l.pageIndex)
|
||||
const cw = l.width_mm * s
|
||||
const ch = l.height_mm * s
|
||||
|
||||
@@ -154,7 +154,7 @@ function computeDropIndex(container: ContainerElement, mouseX: number, mouseY: n
|
||||
const centerX = l.x_mm * s + (l.width_mm * s) / 2
|
||||
if (mouseX < centerX) { visualIdx = i; break }
|
||||
} else {
|
||||
const centerY = l.y_mm * s + (l.height_mm * s) / 2
|
||||
const centerY = l.y_mm * s + pageYOffset(l.pageIndex) + (l.height_mm * s) / 2
|
||||
if (mouseY < centerY) { visualIdx = i; break }
|
||||
}
|
||||
}
|
||||
@@ -246,7 +246,8 @@ const dropIndicatorStyle = computed(() => {
|
||||
}
|
||||
}
|
||||
|
||||
const top = cl.y_mm * s
|
||||
const clPageOff = pageYOffset(cl.pageIndex)
|
||||
const top = cl.y_mm * s + clPageOff
|
||||
const height = cl.height_mm * s
|
||||
|
||||
return {
|
||||
@@ -263,30 +264,31 @@ const dropIndicatorStyle = computed(() => {
|
||||
}
|
||||
|
||||
// Column container: yatay gösterge çizgisi
|
||||
const colPageOff = pageYOffset(cl.pageIndex)
|
||||
let y = 0
|
||||
if (idx === 0 && flowChildren.length > 0) {
|
||||
const l = props.layoutMap[flowChildren[0].id]
|
||||
if (l) {
|
||||
y = (cl.y_mm * s + l.y_mm * s) / 2
|
||||
y = (cl.y_mm * s + colPageOff + l.y_mm * s + pageYOffset(l.pageIndex)) / 2
|
||||
} else {
|
||||
y = cl.y_mm * s - 4
|
||||
y = cl.y_mm * s + colPageOff - 4
|
||||
}
|
||||
} else if (idx < flowChildren.length && idx > 0) {
|
||||
const above = props.layoutMap[flowChildren[idx - 1].id]
|
||||
const below = props.layoutMap[flowChildren[idx].id]
|
||||
if (above && below) {
|
||||
const aboveBottom = (above.y_mm + above.height_mm) * s
|
||||
const belowTop = below.y_mm * s
|
||||
const aboveBottom = (above.y_mm + above.height_mm) * s + pageYOffset(above.pageIndex)
|
||||
const belowTop = below.y_mm * s + pageYOffset(below.pageIndex)
|
||||
y = (aboveBottom + belowTop) / 2
|
||||
}
|
||||
} else if (idx === 0 && flowChildren.length === 0) {
|
||||
y = cl.y_mm * s + 8
|
||||
y = cl.y_mm * s + colPageOff + 8
|
||||
} else if (flowChildren.length > 0) {
|
||||
const last = flowChildren[flowChildren.length - 1]
|
||||
const l = props.layoutMap[last.id]
|
||||
if (l) {
|
||||
const gapPx = container.gap * props.scale
|
||||
y = (l.y_mm + l.height_mm) * s + gapPx / 2
|
||||
y = (l.y_mm + l.height_mm) * s + pageYOffset(l.pageIndex) + gapPx / 2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -205,6 +205,9 @@ const tools: ToolItem[] = [
|
||||
create: (): PageBreakElement => ({
|
||||
id: nextId('pb'),
|
||||
type: 'page_break',
|
||||
position: { type: 'flow' },
|
||||
size: { width: sz.fr(1), height: sz.auto() },
|
||||
style: {},
|
||||
}),
|
||||
},
|
||||
]
|
||||
|
||||
@@ -94,7 +94,7 @@ function onBarcodeFormatChange(newFormat: BarcodeFormat) {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Barkod Ayarlari</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Barkod formati">
|
||||
<label class="prop-label">Format</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.format"
|
||||
@@ -106,14 +106,14 @@ function onBarcodeFormatChange(newFormat: BarcodeFormat) {
|
||||
<option value="code39">Code 39</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Barkod icerigi — formata uygun olmali">
|
||||
<label class="prop-label">Deger</label>
|
||||
<input class="prop-input" type="text"
|
||||
:class="{ 'prop-input--invalid': barcodeInputInvalid }"
|
||||
:value="barcodeInputValue"
|
||||
@input="onBarcodeValueInput" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Barkod cizgi/modül rengi">
|
||||
<label class="prop-label">Renk</label>
|
||||
<div class="prop-row-inline">
|
||||
<input class="prop-input prop-color" type="color"
|
||||
@@ -122,13 +122,13 @@ function onBarcodeFormatChange(newFormat: BarcodeFormat) {
|
||||
<button v-if="element.style.color" class="prop-clear" @click="updateStyle('color', undefined)">x</button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="element.format !== 'qr'" class="prop-row">
|
||||
<div v-if="element.format !== 'qr'" class="prop-row" data-tip="Barkod altinda degeri metin olarak goster">
|
||||
<label class="prop-label">Metin Goster</label>
|
||||
<input type="checkbox"
|
||||
:checked="element.style.includeText ?? (element.format === 'ean13' || element.format === 'ean8')"
|
||||
@change="(e) => updateStyle('includeText', (e.target as HTMLInputElement).checked)" />
|
||||
</div>
|
||||
<div v-if="schemaStore.scalarFields.length > 0" class="prop-row">
|
||||
<div v-if="schemaStore.scalarFields.length > 0" class="prop-row" data-tip="Schema'dan dinamik veri baglama">
|
||||
<label class="prop-label">Veri Baglama</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.binding?.path ?? ''"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { useTemplateStore } from '../../stores/template'
|
||||
import { useEditorStore } from '../../stores/editor'
|
||||
import type { CalculatedTextElement, TextStyle, TemplateElement } from '../../core/types'
|
||||
import DexprEditor from '../common/DexprEditor.vue'
|
||||
import '../../styles/properties.css'
|
||||
|
||||
const props = defineProps<{ element: CalculatedTextElement }>()
|
||||
@@ -17,19 +18,23 @@ function update(updates: Partial<TemplateElement>) {
|
||||
function updateStyle(key: string, value: unknown) {
|
||||
update({ style: { ...props.element.style, [key]: value } } as Partial<TemplateElement>)
|
||||
}
|
||||
|
||||
function onExpressionChange(value: string) {
|
||||
update({ expression: value } as any)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Hesaplanan Metin</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row-stack" data-tip="Hesaplama ifadesi (orn: toplamlar.kdv + toplamlar.araToplam)">
|
||||
<label class="prop-label">Ifade</label>
|
||||
<input class="prop-input" type="text"
|
||||
:value="element.expression"
|
||||
@change="(e) => update({ expression: (e.target as HTMLInputElement).value } as any)"
|
||||
<DexprEditor
|
||||
:model-value="element.expression"
|
||||
@update:model-value="onExpressionChange"
|
||||
placeholder="toplamlar.kdv + toplamlar.araToplam" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Sonucun gosterim formati">
|
||||
<label class="prop-label">Format</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.format ?? ''"
|
||||
@@ -40,19 +45,19 @@ function updateStyle(key: string, value: unknown) {
|
||||
<option value="percentage">Yuzde</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Yazi tipi boyutu (point)">
|
||||
<label class="prop-label">Boyut (pt)</label>
|
||||
<input class="prop-input" type="number" step="1" min="1"
|
||||
:value="(element.style as TextStyle).fontSize ?? 11"
|
||||
@input="(e) => updateStyle('fontSize', parseFloat((e.target as HTMLInputElement).value) || 11)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Metin rengi">
|
||||
<label class="prop-label">Renk</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="(element.style as TextStyle).color ?? '#000000'"
|
||||
@input="(e) => updateStyle('color', (e.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Yazi tipi kalinligi">
|
||||
<label class="prop-label">Kalinlik</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="(element.style as TextStyle).fontWeight ?? 'normal'"
|
||||
@@ -61,7 +66,7 @@ function updateStyle(key: string, value: unknown) {
|
||||
<option value="bold">Kalin</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Metnin yatay hizalamasi">
|
||||
<label class="prop-label">Hizalama</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="(element.style as TextStyle).align ?? 'left'"
|
||||
|
||||
@@ -22,25 +22,25 @@ function updateStyle(key: string, value: unknown) {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Onay Kutusu</div>
|
||||
<div v-if="!element.binding" class="prop-row">
|
||||
<div v-if="!element.binding" class="prop-row" data-tip="Onay kutusunun varsayilan durumu">
|
||||
<label class="prop-label">Isaretli</label>
|
||||
<input type="checkbox"
|
||||
:checked="element.checked ?? false"
|
||||
@change="(e) => update({ checked: (e.target as HTMLInputElement).checked } as any)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Onay kutusu boyutu (mm)">
|
||||
<label class="prop-label">Boyut (mm)</label>
|
||||
<input class="prop-input" type="number" step="0.5" min="1"
|
||||
:value="element.style.size ?? 4"
|
||||
@input="(e) => updateStyle('size', parseFloat((e.target as HTMLInputElement).value) || 4)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Isaret (tik) rengi">
|
||||
<label class="prop-label">Isaret Rengi</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="element.style.checkColor ?? '#000000'"
|
||||
@input="(e) => updateStyle('checkColor', (e.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Kutu kenarlik rengi">
|
||||
<label class="prop-label">Kenar Rengi</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="element.style.borderColor ?? '#333333'"
|
||||
|
||||
@@ -23,7 +23,7 @@ function updateStyle(key: string, value: unknown) {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Container Ayarlari</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Cocuk elemanlarin dizilim yonu">
|
||||
<label class="prop-label">Yon</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.direction"
|
||||
@@ -32,13 +32,13 @@ function updateStyle(key: string, value: unknown) {
|
||||
<option value="row">Yatay</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Cocuk elemanlar arasi bosluk (mm)">
|
||||
<label class="prop-label">Bosluk (mm)</label>
|
||||
<input class="prop-input" type="number" step="1" min="0"
|
||||
:value="element.gap"
|
||||
@input="(e) => update({ gap: parseFloat((e.target as HTMLInputElement).value) || 0 } as any)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Cocuklarin cross-axis hizalamasi">
|
||||
<label class="prop-label">{{ element.direction === 'column' ? 'Yatay Hizalama' : 'Dikey Hizalama' }}</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.align"
|
||||
@@ -49,7 +49,7 @@ function updateStyle(key: string, value: unknown) {
|
||||
<option value="stretch">Esnet</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Cocuklarin main-axis dagilimi">
|
||||
<label class="prop-label">{{ element.direction === 'column' ? 'Dikey Dagilim' : 'Yatay Dagilim' }}</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.justify"
|
||||
@@ -70,7 +70,7 @@ function updateStyle(key: string, value: unknown) {
|
||||
@update="(side, value) => update({ padding: { ...element.padding, [side]: value } } as any)"
|
||||
/>
|
||||
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Sayfa sonunda bolunmeyi kontrol eder">
|
||||
<label class="prop-label">Sayfa Bolme</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.breakInside ?? 'auto'"
|
||||
@@ -81,7 +81,7 @@ function updateStyle(key: string, value: unknown) {
|
||||
</div>
|
||||
|
||||
<div class="prop-section__subtitle">Stil</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Container arka plan rengi">
|
||||
<label class="prop-label">Arka plan</label>
|
||||
<div class="prop-row-inline">
|
||||
<input class="prop-input prop-color" type="color"
|
||||
@@ -90,13 +90,13 @@ function updateStyle(key: string, value: unknown) {
|
||||
<button v-if="element.style.backgroundColor" class="prop-clear" @click="updateStyle('backgroundColor', undefined)">x</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Kenarlik kalinligi (mm)">
|
||||
<label class="prop-label">Kenarlik (mm)</label>
|
||||
<input class="prop-input" type="number" step="0.1" min="0"
|
||||
:value="element.style.borderWidth ?? 0"
|
||||
@input="(e) => updateStyle('borderWidth', parseFloat((e.target as HTMLInputElement).value) || 0)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Kenarlik cizgisi rengi">
|
||||
<label class="prop-label">Kenarlik rengi</label>
|
||||
<div class="prop-row-inline">
|
||||
<input class="prop-input prop-color" type="color"
|
||||
@@ -105,7 +105,7 @@ function updateStyle(key: string, value: unknown) {
|
||||
<button v-if="element.style.borderColor" class="prop-clear" @click="updateStyle('borderColor', undefined)">x</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Kenarlik cizgi stili">
|
||||
<label class="prop-label">Kenarlik stili</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.style.borderStyle ?? 'solid'"
|
||||
@@ -115,7 +115,7 @@ function updateStyle(key: string, value: unknown) {
|
||||
<option value="dotted">Noktali</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Kose yuvarlakligi (mm)">
|
||||
<label class="prop-label">Radius (mm)</label>
|
||||
<input class="prop-input" type="number" step="0.5" min="0"
|
||||
:value="element.style.borderRadius ?? 0"
|
||||
|
||||
@@ -22,7 +22,7 @@ function updateStyle(key: string, value: unknown) {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Tarih</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Tarih gosterim formati">
|
||||
<label class="prop-label">Format</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.format ?? 'DD.MM.YYYY'"
|
||||
@@ -33,19 +33,19 @@ function updateStyle(key: string, value: unknown) {
|
||||
<option value="DD.MM.YYYY HH:mm">30.03.2026 14:30</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Yazi tipi boyutu (point)">
|
||||
<label class="prop-label">Boyut (pt)</label>
|
||||
<input class="prop-input" type="number" step="1" min="1"
|
||||
:value="(element.style as TextStyle).fontSize ?? 10"
|
||||
@input="(e) => updateStyle('fontSize', parseFloat((e.target as HTMLInputElement).value) || 10)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Metin rengi">
|
||||
<label class="prop-label">Renk</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="(element.style as TextStyle).color ?? '#666666'"
|
||||
@input="(e) => updateStyle('color', (e.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Metnin yatay hizalamasi">
|
||||
<label class="prop-label">Hizalama</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="(element.style as TextStyle).align ?? 'left'"
|
||||
|
||||
@@ -33,22 +33,22 @@ function onImageFileSelect(e: Event) {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Gorsel</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Gorsel dosyasi secin (PNG, JPG, SVG)">
|
||||
<label class="prop-label">Kaynak</label>
|
||||
<label class="prop-file-btn">
|
||||
Dosya Sec
|
||||
<input type="file" accept="image/*" style="display: none" @change="onImageFileSelect" />
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="element.src" class="prop-row">
|
||||
<div v-if="element.src" class="prop-row" data-tip="Yuklenen gorsel onizlemesi">
|
||||
<label class="prop-label">Onizleme</label>
|
||||
<img :src="element.src" class="prop-image-preview" />
|
||||
</div>
|
||||
<div v-if="element.src" class="prop-row">
|
||||
<div v-if="element.src" class="prop-row" data-tip="Gorseli kaldirmak icin tiklayin">
|
||||
<label class="prop-label"></label>
|
||||
<button class="prop-clear" @click="update({ src: undefined } as any)">Gorseli kaldir</button>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Gorselin alana sigdirma modu">
|
||||
<label class="prop-label">Sigdirma</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.style.objectFit ?? 'contain'"
|
||||
|
||||
@@ -18,13 +18,13 @@ function updateStyle(key: string, value: unknown) {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Cizgi Stili</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Cizgi kalinligi (mm)">
|
||||
<label class="prop-label">Kalinlik (mm)</label>
|
||||
<input class="prop-input" type="number" step="0.1" min="0.1"
|
||||
:value="element.style.strokeWidth ?? 0.5"
|
||||
@input="(e) => updateStyle('strokeWidth', parseFloat((e.target as HTMLInputElement).value) || 0.5)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Cizgi rengi">
|
||||
<label class="prop-label">Renk</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="element.style.strokeColor ?? '#000000'"
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import '../../styles/properties.css'
|
||||
|
||||
const props = defineProps<{
|
||||
top: number
|
||||
right: number
|
||||
@@ -20,10 +22,10 @@ function onInput(side: 'top' | 'right' | 'bottom' | 'left', e: Event) {
|
||||
<div class="pb">
|
||||
<span class="pb__label">Padding</span>
|
||||
<div class="pb__box">
|
||||
<input class="pb__in pb__in--t" type="number" step="1" min="0" :value="props.top" @input="(e) => onInput('top', e)" />
|
||||
<input class="pb__in pb__in--r" type="number" step="1" min="0" :value="props.right" @input="(e) => onInput('right', e)" />
|
||||
<input class="pb__in pb__in--b" type="number" step="1" min="0" :value="props.bottom" @input="(e) => onInput('bottom', e)" />
|
||||
<input class="pb__in pb__in--l" type="number" step="1" min="0" :value="props.left" @input="(e) => onInput('left', e)" />
|
||||
<input class="pb__in pb__in--t" type="number" step="1" min="0" :value="props.top" @input="(e) => onInput('top', e)" data-tip="Ust bosluk (mm)" />
|
||||
<input class="pb__in pb__in--r" type="number" step="1" min="0" :value="props.right" @input="(e) => onInput('right', e)" data-tip="Sag bosluk (mm)" />
|
||||
<input class="pb__in pb__in--b" type="number" step="1" min="0" :value="props.bottom" @input="(e) => onInput('bottom', e)" data-tip="Alt bosluk (mm)" />
|
||||
<input class="pb__in pb__in--l" type="number" step="1" min="0" :value="props.left" @input="(e) => onInput('left', e)" data-tip="Sol bosluk (mm)" />
|
||||
<div class="pb__center" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,7 +22,7 @@ function updateStyle(key: string, value: unknown) {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Sayfa Numarasi</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Sayfa numarasi gosterim formati">
|
||||
<label class="prop-label">Format</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.format ?? '{current} / {total}'"
|
||||
@@ -33,19 +33,19 @@ function updateStyle(key: string, value: unknown) {
|
||||
<option value="Sayfa {current} / {total}">Sayfa 1 / 5</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Yazi tipi boyutu (point)">
|
||||
<label class="prop-label">Boyut (pt)</label>
|
||||
<input class="prop-input" type="number" step="1" min="1"
|
||||
:value="(element.style as TextStyle).fontSize ?? 10"
|
||||
@input="(e) => updateStyle('fontSize', parseFloat((e.target as HTMLInputElement).value) || 10)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Metin rengi">
|
||||
<label class="prop-label">Renk</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="(element.style as TextStyle).color ?? '#666666'"
|
||||
@input="(e) => updateStyle('color', (e.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Metnin yatay hizalamasi">
|
||||
<label class="prop-label">Hizalama</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="(element.style as TextStyle).align ?? 'center'"
|
||||
|
||||
@@ -18,7 +18,7 @@ function togglePositioning() {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Pozisyon</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Flow: otomatik dizilim, Absolute: sabit konum">
|
||||
<label class="prop-label">Mod</label>
|
||||
<select class="prop-input prop-select" :value="element.position.type" @change="togglePositioning">
|
||||
<option value="flow">Flow</option>
|
||||
@@ -26,13 +26,13 @@ function togglePositioning() {
|
||||
</select>
|
||||
</div>
|
||||
<template v-if="element.position.type === 'absolute'">
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Yatay pozisyon — parent sol kenardan uzaklik (mm)">
|
||||
<label class="prop-label">X (mm)</label>
|
||||
<input class="prop-input" type="number" step="0.5"
|
||||
:value="element.position.x"
|
||||
@input="(e) => templateStore.updateElementPosition(element.id, { type: 'absolute', x: parseFloat((e.target as HTMLInputElement).value) || 0, y: (element.position as any).y ?? 0 })" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Dikey pozisyon — parent ust kenardan uzaklik (mm)">
|
||||
<label class="prop-label">Y (mm)</label>
|
||||
<input class="prop-input" type="number" step="0.5"
|
||||
:value="element.position.y"
|
||||
|
||||
@@ -88,7 +88,7 @@ const tableItemFields = computed(() => {
|
||||
<!-- Data source -->
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Veri Kaynagi</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Tablonun baglanacagi array veri kaynagi">
|
||||
<label class="prop-label">Kaynak</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.dataSource.path"
|
||||
@@ -112,24 +112,31 @@ const tableItemFields = computed(() => {
|
||||
<div
|
||||
v-for="col in element.columns"
|
||||
:key="col.id"
|
||||
class="prop-column-card"
|
||||
class="tbl-col"
|
||||
>
|
||||
<div class="prop-column-header">
|
||||
<span class="prop-column-title">{{ col.title || col.field }}</span>
|
||||
<div class="prop-column-actions">
|
||||
<button class="prop-icon-btn" @click="moveColumn(col.id, -1)" title="Yukari">↑</button>
|
||||
<button class="prop-icon-btn" @click="moveColumn(col.id, 1)" title="Asagi">↓</button>
|
||||
<button class="prop-icon-btn prop-icon-btn--danger" @click="removeColumn(col.id)" title="Sil">x</button>
|
||||
<!-- Row 1: title + actions -->
|
||||
<div class="tbl-col__head">
|
||||
<input class="tbl-col__title" type="text" :value="col.title"
|
||||
@change="(e) => updateColumn(col.id, { title: (e.target as HTMLInputElement).value })"
|
||||
:placeholder="col.field"
|
||||
data-tip="Sutun basligi" />
|
||||
<div class="tbl-col__actions">
|
||||
<button class="tbl-col__act" @click="moveColumn(col.id, -1)" data-tip="Yukari tasi">
|
||||
<svg width="10" height="10" viewBox="0 0 10 10"><path d="M5 2L2 6h6L5 2z" fill="currentColor"/></svg>
|
||||
</button>
|
||||
<button class="tbl-col__act" @click="moveColumn(col.id, 1)" data-tip="Asagi tasi">
|
||||
<svg width="10" height="10" viewBox="0 0 10 10"><path d="M5 8L2 4h6L5 8z" fill="currentColor"/></svg>
|
||||
</button>
|
||||
<button class="tbl-col__act tbl-col__act--del" @click="removeColumn(col.id)" data-tip="Sutunu sil">
|
||||
<svg width="10" height="10" viewBox="0 0 10 10"><path d="M2 2l6 6M8 2l-6 6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Baslik</label>
|
||||
<input class="prop-input" type="text" :value="col.title"
|
||||
@change="(e) => updateColumn(col.id, { title: (e.target as HTMLInputElement).value })" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Alan</label>
|
||||
<select v-if="tableItemFields.length > 0" class="prop-input prop-select" :value="col.field"
|
||||
|
||||
<!-- Row 2: field + align + format + width compact -->
|
||||
<div class="tbl-col__controls">
|
||||
<!-- Field -->
|
||||
<select v-if="tableItemFields.length > 0" class="tbl-col__field" :value="col.field" data-tip="Veri alani"
|
||||
@change="(e) => {
|
||||
const field = (e.target as HTMLSelectElement).value
|
||||
const node = tableItemFields.find(f => f.key === field)
|
||||
@@ -144,23 +151,30 @@ const tableItemFields = computed(() => {
|
||||
updateColumn(col.id, { field })
|
||||
}
|
||||
}">
|
||||
<option v-for="f in tableItemFields" :key="f.key" :value="f.key">{{ f.title }} ({{ f.key }})</option>
|
||||
<option v-for="f in tableItemFields" :key="f.key" :value="f.key">{{ f.key }}</option>
|
||||
</select>
|
||||
<input v-else class="prop-input" type="text" :value="col.field"
|
||||
@change="(e) => updateColumn(col.id, { field: (e.target as HTMLInputElement).value })" />
|
||||
<input v-else class="tbl-col__field" type="text" :value="col.field"
|
||||
@change="(e) => updateColumn(col.id, { field: (e.target as HTMLInputElement).value })"
|
||||
data-tip="Veri alani" />
|
||||
|
||||
<!-- Alignment icons -->
|
||||
<div class="tbl-col__align">
|
||||
<button class="tbl-col__align-btn" :class="{ 'tbl-col__align-btn--on': col.align === 'left' }" @click="updateColumn(col.id, { align: 'left' })" data-tip="Sola hizala">
|
||||
<svg width="12" height="12" viewBox="0 0 12 12"><line x1="1" y1="3" x2="11" y2="3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><line x1="1" y1="6" x2="8" y2="6" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><line x1="1" y1="9" x2="10" y2="9" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
|
||||
</button>
|
||||
<button class="tbl-col__align-btn" :class="{ 'tbl-col__align-btn--on': col.align === 'center' }" @click="updateColumn(col.id, { align: 'center' })" data-tip="Ortala">
|
||||
<svg width="12" height="12" viewBox="0 0 12 12"><line x1="1" y1="3" x2="11" y2="3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><line x1="2.5" y1="6" x2="9.5" y2="6" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><line x1="1.5" y1="9" x2="10.5" y2="9" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
|
||||
</button>
|
||||
<button class="tbl-col__align-btn" :class="{ 'tbl-col__align-btn--on': col.align === 'right' }" @click="updateColumn(col.id, { align: 'right' })" data-tip="Saga hizala">
|
||||
<svg width="12" height="12" viewBox="0 0 12 12"><line x1="1" y1="3" x2="11" y2="3" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><line x1="4" y1="6" x2="11" y2="6" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/><line x1="2" y1="9" x2="11" y2="9" stroke="currentColor" stroke-width="1.3" stroke-linecap="round"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Hizalama</label>
|
||||
<select class="prop-input prop-select" :value="col.align"
|
||||
@change="(e) => updateColumn(col.id, { align: (e.target as HTMLSelectElement).value as 'left'|'center'|'right' })">
|
||||
<option value="left">Sol</option>
|
||||
<option value="center">Orta</option>
|
||||
<option value="right">Sag</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Format</label>
|
||||
<select class="prop-input prop-select" :value="col.format ?? ''"
|
||||
|
||||
<!-- Row 3: format + width -->
|
||||
<div class="tbl-col__extra" data-tip="Veri gosterim formati">
|
||||
<label class="tbl-col__elabel">Format</label>
|
||||
<select class="tbl-col__fmt" :value="col.format ?? ''"
|
||||
@change="(e) => updateColumn(col.id, { format: ((e.target as HTMLSelectElement).value || undefined) as FormatType | undefined })">
|
||||
<option value="">Yok</option>
|
||||
<option value="currency">Para birimi</option>
|
||||
@@ -169,10 +183,9 @@ const tableItemFields = computed(() => {
|
||||
<option value="percentage">Yuzde</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Genislik</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="col.width.type"
|
||||
<div class="tbl-col__extra" data-tip="Sutun genislik modu">
|
||||
<label class="tbl-col__elabel">Genislik</label>
|
||||
<select class="tbl-col__wtype" :value="col.width.type"
|
||||
@change="(e) => {
|
||||
const t = (e.target as HTMLSelectElement).value
|
||||
if (t === 'auto') updateColumn(col.id, { width: { type: 'auto' } })
|
||||
@@ -183,71 +196,484 @@ const tableItemFields = computed(() => {
|
||||
<option value="fixed">Sabit (mm)</option>
|
||||
<option value="fr">Oran (fr)</option>
|
||||
</select>
|
||||
<span v-if="col.width.type === 'fixed' || col.width.type === 'fr'" class="ts-tip-wrap" :data-tip="col.width.type === 'fixed' ? 'Sabit genislik (mm)' : 'Oran degeri (fr)'">
|
||||
<input class="tbl-col__wval" type="number" step="1"
|
||||
:min="col.width.type === 'fixed' ? 5 : 1"
|
||||
:value="(col.width as any).value"
|
||||
@change="(e) => updateColumn(col.id, { width: { type: col.width.type, value: parseFloat((e.target as HTMLInputElement).value) || (col.width.type === 'fixed' ? 30 : 1) } as any })" />
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="col.width.type === 'fixed'" class="prop-row">
|
||||
<label class="prop-label">mm</label>
|
||||
<input class="prop-input" type="number" step="1" min="5"
|
||||
:value="(col.width as any).value"
|
||||
@change="(e) => updateColumn(col.id, { width: { type: 'fixed', value: parseFloat((e.target as HTMLInputElement).value) || 30 } })" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sayfa bölme ayarları -->
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Sayfa Bolme</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Header tekrarla</label>
|
||||
<input type="checkbox"
|
||||
:checked="element.repeatHeader !== false"
|
||||
@change="(e) => update({ repeatHeader: (e.target as HTMLInputElement).checked } as any)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Table style -->
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Tablo Stili</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Yazi boyutu</label>
|
||||
<input class="prop-input" type="number" step="1" min="6"
|
||||
:value="element.style.fontSize ?? 10"
|
||||
@input="(e) => updateTableStyle('fontSize', parseFloat((e.target as HTMLInputElement).value) || 10)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Header bg</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="element.style.headerBg ?? '#f0f0f0'"
|
||||
@input="(e) => updateTableStyle('headerBg', (e.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Header renk</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="element.style.headerColor ?? '#000000'"
|
||||
@input="(e) => updateTableStyle('headerColor', (e.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Zebra tek</label>
|
||||
<div class="prop-row-inline">
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="element.style.zebraOdd ?? '#fafafa'"
|
||||
@input="(e) => updateTableStyle('zebraOdd', (e.target as HTMLInputElement).value)" />
|
||||
<button v-if="element.style.zebraOdd" class="prop-clear" @click="updateTableStyle('zebraOdd', undefined)">x</button>
|
||||
|
||||
<div class="ts-form">
|
||||
<!-- Font sizes -->
|
||||
<label class="ts-lbl" data-tip="Icerik ve header yazi boyutu (pt)">Yazi boyutu</label>
|
||||
<div class="ts-val ts-val--pair">
|
||||
<span class="ts-sep">Icerik</span>
|
||||
<span class="ts-tip-wrap" data-tip="Icerik yazi boyutu (pt)">
|
||||
<input class="ts-num" type="number" step="1" min="6" max="99"
|
||||
:value="element.style.fontSize ?? 10"
|
||||
@input="(e) => updateTableStyle('fontSize', parseFloat((e.target as HTMLInputElement).value) || 10)" />
|
||||
</span>
|
||||
<span class="ts-sep">Header</span>
|
||||
<span class="ts-tip-wrap" data-tip="Header yazi boyutu (pt)">
|
||||
<input class="ts-num" type="number" step="1" min="6" max="99"
|
||||
:value="element.style.headerFontSize ?? element.style.fontSize ?? 10"
|
||||
@input="(e) => updateTableStyle('headerFontSize', parseFloat((e.target as HTMLInputElement).value) || 10)" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Kenarlik rengi</label>
|
||||
<div class="prop-row-inline">
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="element.style.borderColor ?? '#cccccc'"
|
||||
@input="(e) => updateTableStyle('borderColor', (e.target as HTMLInputElement).value)" />
|
||||
<button v-if="element.style.borderColor" class="prop-clear" @click="updateTableStyle('borderColor', undefined)">x</button>
|
||||
|
||||
<!-- Colors -->
|
||||
<label class="ts-lbl" data-tip="Header, metin ve zebra satirlari renkleri">Renkler</label>
|
||||
<div class="ts-val ts-val--colors">
|
||||
<div class="ts-color-item" data-tip="Header arkaplan rengi">
|
||||
<input class="ts-swatch" type="color"
|
||||
:value="element.style.headerBg ?? '#f0f0f0'"
|
||||
@input="(e) => updateTableStyle('headerBg', (e.target as HTMLInputElement).value)" />
|
||||
<span class="ts-clbl">Arkaplan</span>
|
||||
</div>
|
||||
<div class="ts-color-item" data-tip="Header metin rengi">
|
||||
<input class="ts-swatch" type="color"
|
||||
:value="element.style.headerColor ?? '#000000'"
|
||||
@input="(e) => updateTableStyle('headerColor', (e.target as HTMLInputElement).value)" />
|
||||
<span class="ts-clbl">Metin</span>
|
||||
</div>
|
||||
<div class="ts-color-item" data-tip="Zebra satir rengi — tek satirlar">
|
||||
<div class="ts-swatch-wrap">
|
||||
<input class="ts-swatch" type="color"
|
||||
:value="element.style.zebraOdd ?? '#fafafa'"
|
||||
@input="(e) => updateTableStyle('zebraOdd', (e.target as HTMLInputElement).value)" />
|
||||
<button v-if="element.style.zebraOdd" class="ts-swatch-clr" @click="updateTableStyle('zebraOdd', undefined)">×</button>
|
||||
</div>
|
||||
<span class="ts-clbl">Zebra</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Border -->
|
||||
<label class="ts-lbl" data-tip="Tablo kenarlik rengi ve kalinligi">Kenarlik</label>
|
||||
<div class="ts-val ts-val--pair">
|
||||
<div class="ts-swatch-wrap" data-tip="Kenarlik rengi">
|
||||
<input class="ts-swatch" type="color"
|
||||
:value="element.style.borderColor ?? '#cccccc'"
|
||||
@input="(e) => updateTableStyle('borderColor', (e.target as HTMLInputElement).value)" />
|
||||
<button v-if="element.style.borderColor" class="ts-swatch-clr" @click="updateTableStyle('borderColor', undefined)">×</button>
|
||||
</div>
|
||||
<span class="ts-tip-wrap" data-tip="Kenarlik kalinligi (mm)">
|
||||
<input class="ts-num" type="number" step="0.1" min="0" max="99"
|
||||
:value="element.style.borderWidth ?? 0.5"
|
||||
@input="(e) => updateTableStyle('borderWidth', parseFloat((e.target as HTMLInputElement).value) || 0)" />
|
||||
</span>
|
||||
<span class="ts-unit">mm</span>
|
||||
</div>
|
||||
|
||||
<!-- Cell padding -->
|
||||
<label class="ts-lbl" data-tip="Hucre ic bosluklari — yatay ve dikey (mm)">Ic bosluk</label>
|
||||
<div class="ts-val ts-val--pair">
|
||||
<span class="ts-pad-icon" data-tip="Yatay bosluk (mm)">↔</span>
|
||||
<span class="ts-tip-wrap" data-tip="Yatay ic bosluk (mm)">
|
||||
<input class="ts-num" type="number" step="0.5" min="0" max="99"
|
||||
:value="element.style.cellPaddingH ?? 2"
|
||||
@input="(e) => updateTableStyle('cellPaddingH', parseFloat((e.target as HTMLInputElement).value) || 0)" />
|
||||
</span>
|
||||
<span class="ts-pad-icon" data-tip="Dikey bosluk (mm)">↕</span>
|
||||
<span class="ts-tip-wrap" data-tip="Dikey ic bosluk (mm)">
|
||||
<input class="ts-num" type="number" step="0.5" min="0" max="99"
|
||||
:value="element.style.cellPaddingV ?? 1"
|
||||
@input="(e) => updateTableStyle('cellPaddingV', parseFloat((e.target as HTMLInputElement).value) || 0)" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Header padding -->
|
||||
<label class="ts-lbl" data-tip="Header hucre bosluklari — yatay ve dikey (mm)">Header bosluk</label>
|
||||
<div class="ts-val ts-val--pair">
|
||||
<span class="ts-pad-icon" data-tip="Yatay bosluk (mm)">↔</span>
|
||||
<span class="ts-tip-wrap" data-tip="Header yatay bosluk (mm)">
|
||||
<input class="ts-num" type="number" step="0.5" min="0" max="99"
|
||||
:value="element.style.headerPaddingH ?? element.style.cellPaddingH ?? 2"
|
||||
@input="(e) => updateTableStyle('headerPaddingH', parseFloat((e.target as HTMLInputElement).value) || 0)" />
|
||||
</span>
|
||||
<span class="ts-pad-icon" data-tip="Dikey bosluk (mm)">↕</span>
|
||||
<span class="ts-tip-wrap" data-tip="Header dikey bosluk (mm)">
|
||||
<input class="ts-num" type="number" step="0.5" min="0" max="99"
|
||||
:value="element.style.headerPaddingV ?? element.style.cellPaddingV ?? 1"
|
||||
@input="(e) => updateTableStyle('headerPaddingV', parseFloat((e.target as HTMLInputElement).value) || 0)" />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Repeat header -->
|
||||
<label class="ts-lbl" data-tip="Cok sayfali tablolarda header'i her sayfada tekrarla">Header tekrarla</label>
|
||||
<div class="ts-val">
|
||||
<label class="ts-toggle">
|
||||
<input type="checkbox"
|
||||
:checked="element.repeatHeader !== false"
|
||||
@change="(e) => update({ repeatHeader: (e.target as HTMLInputElement).checked } as any)" />
|
||||
<span class="ts-toggle__track"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<label class="prop-label">Kenarlik (mm)</label>
|
||||
<input class="prop-input" type="number" step="0.1" min="0"
|
||||
:value="element.style.borderWidth ?? 0.5"
|
||||
@input="(e) => updateTableStyle('borderWidth', parseFloat((e.target as HTMLInputElement).value) || 0)" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Column card - compact */
|
||||
.tbl-col {
|
||||
background: #f8fafc;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 5px;
|
||||
padding: 5px 6px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.tbl-col__head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.tbl-col__title {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: #334155;
|
||||
padding: 1px 0;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.tbl-col__title:focus {
|
||||
border-bottom: 1px solid #93c5fd;
|
||||
}
|
||||
|
||||
.tbl-col__actions {
|
||||
display: flex;
|
||||
gap: 1px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tbl-col__act {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
background: transparent;
|
||||
color: #94a3b8;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tbl-col__act:hover {
|
||||
background: #e2e8f0;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.tbl-col__act--del:hover {
|
||||
background: #fef2f2;
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.tbl-col__controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.tbl-col__field {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
background: white;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.tbl-col__field:focus {
|
||||
outline: none;
|
||||
border-color: #93c5fd;
|
||||
}
|
||||
|
||||
.tbl-col__align {
|
||||
display: flex;
|
||||
gap: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tbl-col__align-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 1px solid #e2e8f0;
|
||||
background: white;
|
||||
color: #94a3b8;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tbl-col__align-btn:first-child {
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
|
||||
.tbl-col__align-btn:last-child {
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
|
||||
.tbl-col__align-btn:not(:first-child) {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.tbl-col__align-btn--on {
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
|
||||
.tbl-col__extra {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.tbl-col__elabel {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tbl-col__fmt {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
background: white;
|
||||
color: #334155;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tbl-col__wtype {
|
||||
width: 80px;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
background: white;
|
||||
color: #334155;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tbl-col__wval {
|
||||
width: 36px;
|
||||
padding: 2px 3px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
background: white;
|
||||
color: #334155;
|
||||
text-align: center;
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
.tbl-col__wval::-webkit-inner-spin-button,
|
||||
.tbl-col__wval::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.tbl-col__wval:focus {
|
||||
outline: none;
|
||||
border-color: #93c5fd;
|
||||
}
|
||||
|
||||
/* Table style — aligned 2-column form */
|
||||
.ts-form {
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
gap: 5px 8px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ts-lbl {
|
||||
font-size: 11px;
|
||||
color: #64748b;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ts-val {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.ts-val--pair {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.ts-val--colors {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.ts-sep {
|
||||
font-size: 10px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.ts-num {
|
||||
width: 32px;
|
||||
padding: 2px 3px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
background: white;
|
||||
color: #334155;
|
||||
text-align: center;
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
.ts-num::-webkit-inner-spin-button,
|
||||
.ts-num::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.ts-num:focus {
|
||||
outline: none;
|
||||
border-color: #93c5fd;
|
||||
}
|
||||
|
||||
.ts-unit {
|
||||
font-size: 10px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
/* Color swatches */
|
||||
.ts-color-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.ts-clbl {
|
||||
font-size: 9px;
|
||||
color: #94a3b8;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ts-swatch {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.ts-swatch-wrap {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.ts-swatch-clr {
|
||||
position: absolute;
|
||||
top: -4px;
|
||||
right: -4px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
background: #f1f5f9;
|
||||
border: 1px solid #e2e8f0;
|
||||
font-size: 9px;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
color: #94a3b8;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ts-swatch-clr:hover {
|
||||
background: #fef2f2;
|
||||
color: #dc2626;
|
||||
border-color: #fecaca;
|
||||
}
|
||||
|
||||
.ts-pad-icon {
|
||||
font-size: 11px;
|
||||
color: #94a3b8;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.ts-tip-wrap {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
/* Toggle switch */
|
||||
.ts-toggle {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.ts-toggle input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.ts-toggle__track {
|
||||
display: block;
|
||||
width: 28px;
|
||||
height: 16px;
|
||||
background: #e2e8f0;
|
||||
border-radius: 8px;
|
||||
transition: background 0.15s;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ts-toggle__track::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
transition: transform 0.15s;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.ts-toggle input:checked + .ts-toggle__track {
|
||||
background: #3b82f6;
|
||||
}
|
||||
|
||||
.ts-toggle input:checked + .ts-toggle__track::after {
|
||||
transform: translateX(12px);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -44,19 +44,19 @@ function removeSpan(index: number) {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Varsayilan Stil</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Varsayilan yazi tipi boyutu (point)">
|
||||
<label class="prop-label">Boyut (pt)</label>
|
||||
<input class="prop-input" type="number" step="1" min="1"
|
||||
:value="element.style.fontSize ?? 11"
|
||||
@input="(e) => updateStyle('fontSize', parseFloat((e.target as HTMLInputElement).value) || 11)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Varsayilan metin rengi">
|
||||
<label class="prop-label">Renk</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="element.style.color ?? '#000000'"
|
||||
@input="(e) => updateStyle('color', (e.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Metnin yatay hizalamasi">
|
||||
<label class="prop-label">Hizalama</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.style.align ?? 'left'"
|
||||
@@ -85,13 +85,13 @@ function removeSpan(index: number) {
|
||||
>×</button>
|
||||
</div>
|
||||
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Span metin icerigi">
|
||||
<label class="prop-label">Metin</label>
|
||||
<input class="prop-input" type="text"
|
||||
:value="span.text ?? ''"
|
||||
@input="(e) => updateSpan(idx, { text: (e.target as HTMLInputElement).value })" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Span yazi boyutu — bos birakilirsa varsayilan kullanilir">
|
||||
<label class="prop-label">Boyut</label>
|
||||
<input class="prop-input" type="number" step="1" min="1"
|
||||
:value="(span.style as TextStyle).fontSize ?? ''"
|
||||
@@ -101,7 +101,7 @@ function removeSpan(index: number) {
|
||||
updateSpanStyle(idx, 'fontSize', v ? parseFloat(v) : undefined)
|
||||
}" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Span yazi kalinligi">
|
||||
<label class="prop-label">Kalinlik</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="(span.style as TextStyle).fontWeight ?? ''"
|
||||
@@ -114,7 +114,7 @@ function removeSpan(index: number) {
|
||||
<option value="bold">Kalin</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Span metin rengi">
|
||||
<label class="prop-label">Renk</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="(span.style as TextStyle).color ?? element.style.color ?? '#000000'"
|
||||
|
||||
@@ -22,7 +22,7 @@ function updateStyle(key: string, value: unknown) {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Sekil</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Sekil tipi">
|
||||
<label class="prop-label">Tip</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.shapeType"
|
||||
@@ -32,25 +32,25 @@ function updateStyle(key: string, value: unknown) {
|
||||
<option value="ellipse">Elips</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Sekil arka plan rengi">
|
||||
<label class="prop-label">Arka Plan</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="element.style.backgroundColor ?? '#f0f0f0'"
|
||||
@input="(e) => updateStyle('backgroundColor', (e.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Kenarlik cizgisi rengi">
|
||||
<label class="prop-label">Kenar Rengi</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="element.style.borderColor ?? '#333333'"
|
||||
@input="(e) => updateStyle('borderColor', (e.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Kenarlik cizgi kalinligi (mm)">
|
||||
<label class="prop-label">Kenar Kalinligi</label>
|
||||
<input class="prop-input" type="number" step="0.25" min="0"
|
||||
:value="element.style.borderWidth ?? 0.5"
|
||||
@input="(e) => updateStyle('borderWidth', parseFloat((e.target as HTMLInputElement).value) || 0)" />
|
||||
</div>
|
||||
<div v-if="element.shapeType === 'rounded_rectangle'" class="prop-row">
|
||||
<div v-if="element.shapeType === 'rounded_rectangle'" class="prop-row" data-tip="Kose yuvarlakligi (mm)">
|
||||
<label class="prop-label">Kose Yuvarlakligi</label>
|
||||
<input class="prop-input" type="number" step="0.5" min="0"
|
||||
:value="element.style.borderRadius ?? 2"
|
||||
|
||||
@@ -14,7 +14,7 @@ function updateSize(axis: 'width' | 'height', sv: SizeValue) {
|
||||
<template>
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Boyut</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Genislik boyutlandirma modu">
|
||||
<label class="prop-label">Genislik</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.size.width.type"
|
||||
@@ -29,20 +29,20 @@ function updateSize(axis: 'width' | 'height', sv: SizeValue) {
|
||||
<option value="fr">Oran (fr)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-if="element.size.width.type === 'fixed'" class="prop-row">
|
||||
<div v-if="element.size.width.type === 'fixed'" class="prop-row" data-tip="Sabit genislik degeri (mm)">
|
||||
<label class="prop-label">mm</label>
|
||||
<input class="prop-input" type="number" step="1" min="1"
|
||||
:value="(element.size.width as any).value"
|
||||
@input="(e) => updateSize('width', { type: 'fixed', value: parseFloat((e.target as HTMLInputElement).value) || 10 })" />
|
||||
</div>
|
||||
<div v-if="element.size.width.type === 'fr'" class="prop-row">
|
||||
<div v-if="element.size.width.type === 'fr'" class="prop-row" data-tip="Kalan alani oransal doldurma degeri">
|
||||
<label class="prop-label">fr</label>
|
||||
<input class="prop-input" type="number" step="1" min="1"
|
||||
:value="(element.size.width as any).value"
|
||||
@input="(e) => updateSize('width', { type: 'fr', value: parseFloat((e.target as HTMLInputElement).value) || 1 })" />
|
||||
</div>
|
||||
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Yukseklik boyutlandirma modu">
|
||||
<label class="prop-label">Yukseklik</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="element.size.height.type"
|
||||
@@ -57,7 +57,7 @@ function updateSize(axis: 'width' | 'height', sv: SizeValue) {
|
||||
<option value="fr">Oran (fr)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-if="element.size.height.type === 'fixed'" class="prop-row">
|
||||
<div v-if="element.size.height.type === 'fixed'" class="prop-row" data-tip="Sabit yukseklik degeri (mm)">
|
||||
<label class="prop-label">mm</label>
|
||||
<input class="prop-input" type="number" step="1" min="1"
|
||||
:value="(element.size.height as any).value"
|
||||
|
||||
@@ -23,20 +23,20 @@ function updateStyle(key: string, value: unknown) {
|
||||
<div class="prop-section">
|
||||
<div class="prop-section__title">Metin Stili</div>
|
||||
|
||||
<div v-if="element.type === 'static_text'" class="prop-row">
|
||||
<div v-if="element.type === 'static_text'" class="prop-row" data-tip="Sabit metin icerigi">
|
||||
<label class="prop-label">Metin</label>
|
||||
<input class="prop-input" type="text"
|
||||
:value="(element as StaticTextElement).content"
|
||||
@input="(e) => update({ content: (e.target as HTMLInputElement).value } as any)" />
|
||||
</div>
|
||||
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Yazi tipi boyutu (point)">
|
||||
<label class="prop-label">Boyut (pt)</label>
|
||||
<input class="prop-input" type="number" step="1" min="1"
|
||||
:value="(element.style as TextStyle).fontSize ?? 11"
|
||||
@input="(e) => updateStyle('fontSize', parseFloat((e.target as HTMLInputElement).value) || 11)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Yazi tipi kalinligi">
|
||||
<label class="prop-label">Kalinlik</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="(element.style as TextStyle).fontWeight ?? 'normal'"
|
||||
@@ -45,13 +45,13 @@ function updateStyle(key: string, value: unknown) {
|
||||
<option value="bold">Kalin</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Metin rengi">
|
||||
<label class="prop-label">Renk</label>
|
||||
<input class="prop-input prop-color" type="color"
|
||||
:value="(element.style as TextStyle).color ?? '#000000'"
|
||||
@input="(e) => updateStyle('color', (e.target as HTMLInputElement).value)" />
|
||||
</div>
|
||||
<div class="prop-row">
|
||||
<div class="prop-row" data-tip="Metnin yatay hizalamasi">
|
||||
<label class="prop-label">Hizalama</label>
|
||||
<select class="prop-input prop-select"
|
||||
:value="(element.style as TextStyle).align ?? 'left'"
|
||||
|
||||
@@ -101,6 +101,10 @@ export interface TableStyle {
|
||||
borderWidth?: number // pt
|
||||
fontSize?: number // pt
|
||||
headerFontSize?: number // pt
|
||||
cellPaddingH?: number // mm — hücre yatay iç boşluk (sol+sağ). Default: 2
|
||||
cellPaddingV?: number // mm — hücre dikey iç boşluk (üst+alt). Default: 1
|
||||
headerPaddingH?: number // mm — header yatay iç boşluk. Default: cellPaddingH
|
||||
headerPaddingV?: number // mm — header dikey iç boşluk. Default: cellPaddingV
|
||||
}
|
||||
|
||||
// --- Barcode ---
|
||||
@@ -208,9 +212,9 @@ export interface RichTextElement extends BaseElement {
|
||||
style: TextStyle // varsayılan stil
|
||||
}
|
||||
|
||||
export interface PageBreakElement {
|
||||
export interface PageBreakElement extends BaseElement {
|
||||
type: 'page_break'
|
||||
id: string
|
||||
style: Record<string, never>
|
||||
}
|
||||
|
||||
export interface ContainerElement extends BaseElement {
|
||||
|
||||
80
frontend/src/directives/tip.ts
Normal file
80
frontend/src/directives/tip.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
let tooltipEl: HTMLDivElement | null = null
|
||||
let currentTarget: HTMLElement | null = null
|
||||
|
||||
function getTooltip(): HTMLDivElement {
|
||||
if (!tooltipEl) {
|
||||
tooltipEl = document.createElement('div')
|
||||
tooltipEl.className = 'prop-tooltip'
|
||||
document.body.appendChild(tooltipEl)
|
||||
}
|
||||
return tooltipEl
|
||||
}
|
||||
|
||||
function show(el: HTMLElement) {
|
||||
const text = el.getAttribute('data-tip')
|
||||
if (!text) return
|
||||
|
||||
currentTarget = el
|
||||
const tip = getTooltip()
|
||||
tip.textContent = text
|
||||
|
||||
// Position before showing so we can measure
|
||||
tip.style.top = '0px'
|
||||
tip.style.left = '0px'
|
||||
tip.classList.add('prop-tooltip--visible')
|
||||
|
||||
const rect = el.getBoundingClientRect()
|
||||
const tipRect = tip.getBoundingClientRect()
|
||||
|
||||
let top = rect.top - tipRect.height - 6
|
||||
let left = rect.left + rect.width / 2 - tipRect.width / 2
|
||||
|
||||
// Clamp to viewport
|
||||
if (top < 4) top = rect.bottom + 6
|
||||
if (left < 4) left = 4
|
||||
if (left + tipRect.width > window.innerWidth - 4) {
|
||||
left = window.innerWidth - tipRect.width - 4
|
||||
}
|
||||
|
||||
tip.style.top = `${top}px`
|
||||
tip.style.left = `${left}px`
|
||||
}
|
||||
|
||||
function hide() {
|
||||
currentTarget = null
|
||||
if (tooltipEl) {
|
||||
tooltipEl.classList.remove('prop-tooltip--visible')
|
||||
}
|
||||
}
|
||||
|
||||
function closest(el: EventTarget | null): HTMLElement | null {
|
||||
if (!(el instanceof HTMLElement)) return null
|
||||
return el.closest('[data-tip]')
|
||||
}
|
||||
|
||||
let installed = false
|
||||
|
||||
/** Call once to enable data-tip tooltips globally via event delegation. */
|
||||
export function setupTooltips() {
|
||||
if (installed) return
|
||||
installed = true
|
||||
document.addEventListener('pointerenter', (e) => {
|
||||
const target = closest(e.target)
|
||||
if (target) show(target)
|
||||
}, true)
|
||||
|
||||
document.addEventListener('pointerleave', (e) => {
|
||||
const target = closest(e.target)
|
||||
if (target && target === currentTarget) hide()
|
||||
}, true)
|
||||
|
||||
document.addEventListener('focusin', (e) => {
|
||||
const target = closest(e.target)
|
||||
if (target) show(target)
|
||||
}, true)
|
||||
|
||||
document.addEventListener('focusout', (e) => {
|
||||
const target = closest(e.target)
|
||||
if (target && target === currentTarget) hide()
|
||||
}, true)
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import { useEditorStore } from '../stores/editor'
|
||||
import EditorCanvas from '../components/editor/EditorCanvas.vue'
|
||||
import ToolboxPanel from '../components/panels/ToolboxPanel.vue'
|
||||
import SchemaTreePanel from '../components/panels/SchemaTreePanel.vue'
|
||||
import { setupTooltips } from '../directives/tip'
|
||||
import PropertiesPanel from '../components/panels/PropertiesPanel.vue'
|
||||
|
||||
export interface DreportEditorConfig {
|
||||
@@ -46,6 +47,7 @@ onMounted(() => {
|
||||
templateStore.template = JSON.parse(JSON.stringify(props.modelValue))
|
||||
nextTick(() => { syncing = false })
|
||||
templateStore.setOverrideData(props.data ?? null)
|
||||
setupTooltips()
|
||||
})
|
||||
|
||||
watch(() => props.schema, (val) => {
|
||||
@@ -81,8 +83,9 @@ function onCompileError(error: string | null) {
|
||||
// --- Keyboard shortcuts ---
|
||||
|
||||
function onKeyDown(e: KeyboardEvent) {
|
||||
const tag = (e.target as HTMLElement)?.tagName
|
||||
const isInput = tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT'
|
||||
const target = e.target as HTMLElement
|
||||
const tag = target?.tagName
|
||||
const isInput = tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || target?.isContentEditable
|
||||
|
||||
// Delete / Backspace
|
||||
if ((e.key === 'Delete' || e.key === 'Backspace') && editorStore.selectedElementId) {
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import App from './App.vue'
|
||||
import { setupTooltips } from './directives/tip'
|
||||
import './styles/editor.css'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(createPinia())
|
||||
app.mount('#app')
|
||||
|
||||
setupTooltips()
|
||||
|
||||
@@ -46,6 +46,13 @@
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.prop-row-stack {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.prop-label {
|
||||
font-size: 12px;
|
||||
color: #475569;
|
||||
@@ -205,3 +212,22 @@
|
||||
color: #dc2626;
|
||||
border-color: #fecaca;
|
||||
}
|
||||
|
||||
/* Tooltip — global portal element */
|
||||
.prop-tooltip {
|
||||
position: fixed;
|
||||
background: #0f172a;
|
||||
color: #e2e8f0;
|
||||
font-size: 10px;
|
||||
padding: 3px 6px;
|
||||
border-radius: 4px;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.prop-tooltip--visible {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 22 KiB |
@@ -3,6 +3,17 @@ import vue from '@vitejs/plugin-vue'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
dedupe: [
|
||||
'@codemirror/state',
|
||||
'@codemirror/view',
|
||||
'@codemirror/language',
|
||||
'@codemirror/autocomplete',
|
||||
'@lezer/common',
|
||||
'@lezer/lr',
|
||||
'@lezer/highlight',
|
||||
],
|
||||
},
|
||||
worker: {
|
||||
format: 'es',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user