mirror of
https://github.com/hpware/news-analyze.git
synced 2025-06-23 07:41:02 +08:00
Compare commits
8 Commits
9accdb28c1
...
d7dfb2fb1d
Author | SHA1 | Date | |
---|---|---|---|
d7dfb2fb1d | |||
a998a99901 | |||
5b5475f74c | |||
a09416db53 | |||
eb6c131163 | |||
eaa925e5dd | |||
7057f8293d | |||
a4ccad0989 |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
@ -8,3 +8,6 @@ sentry*
|
||||
package.json
|
||||
node_modules
|
||||
/public/docs
|
||||
Dockerfile
|
||||
docker-compose.yml
|
||||
nginx.conf
|
@ -1,6 +1,7 @@
|
||||
# 新聞解析 / News Analyze
|
||||
|
||||

|
||||
   
|
||||
|
||||
|
||||
App Design: [PDF Document](/design.pdf)
|
||||
|
||||
@ -95,4 +96,4 @@ https://news.yuanhau.com/api/home/lt?query=domestic
|
||||
|
||||
https://news.yuanhau.com/api/news/get/lt/${article url hash}
|
||||
|
||||
or you can self host the API on your own server with a basic docker compose command.
|
||||
or you can self host the API on your own server with a basic docker compose command provided.
|
||||
|
110
bun.lock
110
bun.lock
@ -175,55 +175,55 @@
|
||||
|
||||
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.0.2", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA=="],
|
||||
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="],
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.5", "", { "os": "android", "cpu": "arm" }, "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA=="],
|
||||
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.4", "", { "os": "android", "cpu": "arm64" }, "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A=="],
|
||||
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.5", "", { "os": "android", "cpu": "arm64" }, "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg=="],
|
||||
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.4", "", { "os": "android", "cpu": "x64" }, "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ=="],
|
||||
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.5", "", { "os": "android", "cpu": "x64" }, "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw=="],
|
||||
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g=="],
|
||||
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ=="],
|
||||
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A=="],
|
||||
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ=="],
|
||||
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ=="],
|
||||
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.5", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw=="],
|
||||
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ=="],
|
||||
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.5", "", { "os": "freebsd", "cpu": "x64" }, "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw=="],
|
||||
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.4", "", { "os": "linux", "cpu": "arm" }, "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ=="],
|
||||
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.5", "", { "os": "linux", "cpu": "arm" }, "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw=="],
|
||||
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ=="],
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ=="],
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.5", "", { "os": "linux", "cpu": "ia32" }, "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA=="],
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg=="],
|
||||
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg=="],
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag=="],
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.5", "", { "os": "linux", "cpu": "ppc64" }, "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA=="],
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.5", "", { "os": "linux", "cpu": "none" }, "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g=="],
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.5", "", { "os": "linux", "cpu": "s390x" }, "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ=="],
|
||||
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA=="],
|
||||
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.5", "", { "os": "linux", "cpu": "x64" }, "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw=="],
|
||||
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.4", "", { "os": "none", "cpu": "arm64" }, "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ=="],
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.5", "", { "os": "none", "cpu": "arm64" }, "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.4", "", { "os": "none", "cpu": "x64" }, "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw=="],
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.5", "", { "os": "none", "cpu": "x64" }, "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ=="],
|
||||
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A=="],
|
||||
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.5", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw=="],
|
||||
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw=="],
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.5", "", { "os": "openbsd", "cpu": "x64" }, "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q=="],
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.5", "", { "os": "sunos", "cpu": "x64" }, "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ=="],
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.5", "", { "os": "win32", "cpu": "arm64" }, "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="],
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="],
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.5", "", { "os": "win32", "cpu": "x64" }, "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g=="],
|
||||
|
||||
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.7.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw=="],
|
||||
|
||||
@ -1225,7 +1225,7 @@
|
||||
|
||||
"effect": ["effect@3.14.21", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-TKR7zfWcuZgEdWd+oIGA8LdREj/c+1Q0wz4pWqQtYT7VHnkW/QQEYCXgrDI5dT6lJgRTgyQAC1bAnpAf6MdjIA=="],
|
||||
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.157", "", {}, "sha512-/0ybgsQd1muo8QlnuTpKwtl0oX5YMlUGbm8xyqgDU00motRkKFFbUJySAQBWcY79rVqNLWIWa87BGVGClwAB2w=="],
|
||||
"electron-to-chromium": ["electron-to-chromium@1.5.158", "", {}, "sha512-9vcp2xHhkvraY6AHw2WMi+GDSLPX42qe2xjYaVoZqFRJiOcilVQFq9mZmpuHEQpzlgGDelKlV7ZiGcmMsc8WxQ=="],
|
||||
|
||||
"emoji-datasource": ["emoji-datasource@15.0.1", "", {}, "sha512-aF5Q6LCKXzJzpG4K0ETiItuzz0xLYxNexR9qWw45/shuuEDWZkOIbeGHA23uopOSYA/LmeZIXIFsySCx+YKg2g=="],
|
||||
|
||||
@ -1263,7 +1263,7 @@
|
||||
|
||||
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
|
||||
|
||||
"esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="],
|
||||
"esbuild": ["esbuild@0.25.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.5", "@esbuild/android-arm": "0.25.5", "@esbuild/android-arm64": "0.25.5", "@esbuild/android-x64": "0.25.5", "@esbuild/darwin-arm64": "0.25.5", "@esbuild/darwin-x64": "0.25.5", "@esbuild/freebsd-arm64": "0.25.5", "@esbuild/freebsd-x64": "0.25.5", "@esbuild/linux-arm": "0.25.5", "@esbuild/linux-arm64": "0.25.5", "@esbuild/linux-ia32": "0.25.5", "@esbuild/linux-loong64": "0.25.5", "@esbuild/linux-mips64el": "0.25.5", "@esbuild/linux-ppc64": "0.25.5", "@esbuild/linux-riscv64": "0.25.5", "@esbuild/linux-s390x": "0.25.5", "@esbuild/linux-x64": "0.25.5", "@esbuild/netbsd-arm64": "0.25.5", "@esbuild/netbsd-x64": "0.25.5", "@esbuild/openbsd-arm64": "0.25.5", "@esbuild/openbsd-x64": "0.25.5", "@esbuild/sunos-x64": "0.25.5", "@esbuild/win32-arm64": "0.25.5", "@esbuild/win32-ia32": "0.25.5", "@esbuild/win32-x64": "0.25.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ=="],
|
||||
|
||||
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
|
||||
|
||||
@ -1299,7 +1299,7 @@
|
||||
|
||||
"events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="],
|
||||
|
||||
"execa": ["execa@9.5.3", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.3", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.0", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.0.0" } }, "sha512-QFNnTvU3UjgWFy8Ef9iDHvIdcgZ344ebkwYx4/KLbR+CKQA4xBaHzv+iRpp86QfMHP8faFQLh8iOc57215y4Rg=="],
|
||||
"execa": ["execa@9.6.0", "", { "dependencies": { "@sindresorhus/merge-streams": "^4.0.0", "cross-spawn": "^7.0.6", "figures": "^6.1.0", "get-stream": "^9.0.0", "human-signals": "^8.0.1", "is-plain-obj": "^4.1.0", "is-stream": "^4.0.1", "npm-run-path": "^6.0.0", "pretty-ms": "^9.2.0", "signal-exit": "^4.1.0", "strip-final-newline": "^4.0.0", "yoctocolors": "^2.1.1" } }, "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw=="],
|
||||
|
||||
"expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="],
|
||||
|
||||
@ -2545,7 +2545,7 @@
|
||||
|
||||
"zip-stream": ["zip-stream@6.0.1", "", { "dependencies": { "archiver-utils": "^5.0.0", "compress-commons": "^6.0.2", "readable-stream": "^4.0.0" } }, "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA=="],
|
||||
|
||||
"zod": ["zod@3.25.28", "", {}, "sha512-/nt/67WYKnr5by3YS7LroZJbtcCBurDKKPBPWWzaxvVCGuG/NOsiKkrjoOhI8mJ+SQUXEbUzeB3S+6XDUEEj7Q=="],
|
||||
"zod": ["zod@3.25.30", "", {}, "sha512-VolhdEtu6TJr/fzGuHA/SZ5ixvXqA6ADOG9VRcQ3rdOKmF5hkmcJbyaQjUH5BgmpA9gej++zYRX7zjSmdReIwA=="],
|
||||
|
||||
"zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="],
|
||||
|
||||
@ -2599,6 +2599,8 @@
|
||||
|
||||
"@netlify/dev-utils/find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild": ["esbuild@0.25.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.4", "@esbuild/android-arm": "0.25.4", "@esbuild/android-arm64": "0.25.4", "@esbuild/android-x64": "0.25.4", "@esbuild/darwin-arm64": "0.25.4", "@esbuild/darwin-x64": "0.25.4", "@esbuild/freebsd-arm64": "0.25.4", "@esbuild/freebsd-x64": "0.25.4", "@esbuild/linux-arm": "0.25.4", "@esbuild/linux-arm64": "0.25.4", "@esbuild/linux-ia32": "0.25.4", "@esbuild/linux-loong64": "0.25.4", "@esbuild/linux-mips64el": "0.25.4", "@esbuild/linux-ppc64": "0.25.4", "@esbuild/linux-riscv64": "0.25.4", "@esbuild/linux-s390x": "0.25.4", "@esbuild/linux-x64": "0.25.4", "@esbuild/netbsd-arm64": "0.25.4", "@esbuild/netbsd-x64": "0.25.4", "@esbuild/openbsd-arm64": "0.25.4", "@esbuild/openbsd-x64": "0.25.4", "@esbuild/sunos-x64": "0.25.4", "@esbuild/win32-arm64": "0.25.4", "@esbuild/win32-ia32": "0.25.4", "@esbuild/win32-x64": "0.25.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/execa": ["execa@8.0.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^8.0.1", "human-signals": "^5.0.0", "is-stream": "^3.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^5.1.0", "onetime": "^6.0.0", "signal-exit": "^4.1.0", "strip-final-newline": "^3.0.0" } }, "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/find-up": ["find-up@7.0.0", "", { "dependencies": { "locate-path": "^7.2.0", "path-exists": "^5.0.0", "unicorn-magic": "^0.1.0" } }, "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g=="],
|
||||
@ -2939,6 +2941,56 @@
|
||||
|
||||
"@netlify/dev-utils/find-up/unicorn-magic": ["unicorn-magic@0.1.0", "", {}, "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.25.4", "", { "os": "android", "cpu": "arm" }, "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.4", "", { "os": "android", "cpu": "arm64" }, "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.25.4", "", { "os": "android", "cpu": "x64" }, "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.4", "", { "os": "linux", "cpu": "arm" }, "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.4", "", { "os": "linux", "cpu": "none" }, "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.4", "", { "os": "linux", "cpu": "x64" }, "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.4", "", { "os": "none", "cpu": "arm64" }, "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.4", "", { "os": "none", "cpu": "x64" }, "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.4", "", { "os": "win32", "cpu": "x64" }, "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/execa/get-stream": ["get-stream@8.0.1", "", {}, "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA=="],
|
||||
|
||||
"@netlify/zip-it-and-ship-it/execa/human-signals": ["human-signals@5.0.0", "", {}, "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ=="],
|
||||
|
@ -70,12 +70,35 @@ watch(
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
const findRel = (title: string) => {
|
||||
return tf(title);
|
||||
}
|
||||
|
||||
const tf = (text: string) => {
|
||||
const words = text.toLowerCase().split('');
|
||||
// const words = text.toLowerCase().match(/[\u4e00-\u9fff]|[a-zA-Z0-9]+/g) || [];
|
||||
|
||||
const freqMap = new Map();
|
||||
|
||||
for (const word of words) {
|
||||
if (word.trim()) {
|
||||
freqMap.set(word, (freqMap.get(word) || 0) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
const tfVector = <any>{};
|
||||
for (const [term, count] of freqMap) {
|
||||
tfVector[term] = count / words.length;
|
||||
}
|
||||
|
||||
return tfVector;
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="justify-center align-center text-center">
|
||||
<!--Tabs-->
|
||||
<div
|
||||
class="sticky inset-x-0 top-0 bg-gray-300/90 backdrop-blur-xl border shadow-lg rounded-xl p-1 m-1 mt-0 justify-center align-center text-center z-[50] overflow-x-auto scrollbar-hide min-w-min whitespace-nowrap px-2"
|
||||
class="sticky inset-x-0 top-0 bg-gray-300/90 backdrop-blur-xl border shadow-lg rounded-xl p-1 m-1 mt-0 justify-center align-center text-center z-[50] overflow-x-auto scrollbar-xl min-w-min whitespace-nowrap px-2"
|
||||
>
|
||||
<div class="gap-2 flex flex-row justify-center align-center text-center">
|
||||
<button
|
||||
@ -88,6 +111,14 @@ watch(
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<Transition
|
||||
enter-active-class="animate__animated animate__fadeIn"
|
||||
leave-active-class="animate__animated animate__fadeOut"
|
||||
>
|
||||
<div v-if="switchTabs" class="absolute inset-x-0 top-12 p-2 m-12 z-[50]">
|
||||
Loading...
|
||||
</div>
|
||||
</Transition>
|
||||
<Transition
|
||||
enter-active-class="animate__animated animate__fadeIn"
|
||||
leave-active-class="animate__animated animate__fadeOut"
|
||||
@ -119,10 +150,16 @@ watch(
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
<p :class="getCheckResult(item.title) ? 'hidden' : ''">
|
||||
<div>
|
||||
<h3 class="text-lg">類似文章</h3>
|
||||
<div>{{ findRel(item.title) }}</div>
|
||||
<!--<div v-for="item in findRel(item.title)">
|
||||
{{ item }}
|
||||
</div>-->
|
||||
</div>
|
||||
<!--<p :class="getCheckResult(item.title) ? 'hidden' : ''">
|
||||
{{ item.shortDescription }}
|
||||
</p>
|
||||
<!--ADD 類似 NEWS ARTICLES.-->
|
||||
</p>-->
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -9,6 +9,7 @@ const activateAiSummary = ref(false);
|
||||
const isGenerating = ref(false);
|
||||
const summaryText = ref("");
|
||||
const { locale } = useI18n();
|
||||
const likeart = ref([]);
|
||||
const aiSummary = async () => {
|
||||
activateAiSummary.value = true;
|
||||
isGenerating.value = true;
|
||||
@ -57,6 +58,15 @@ const aiSummary = async () => {
|
||||
</button>
|
||||
<div v-else>{{ summaryText }}</div>
|
||||
</div>
|
||||
<div class="flex flex-col bg-gray-500">
|
||||
<div class="flex flex-row" v-for="item in likeart">
|
||||
<img /><!--Image-->
|
||||
<div class="flex flex-col">
|
||||
<h2>title</h2>
|
||||
<span>description</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -2,9 +2,15 @@
|
||||
// Great, there are now no errors ig
|
||||
const emit = defineEmits(["windowopener", "error", "loadValue"]);
|
||||
import sha512 from "crypto-js/sha512";
|
||||
import Input from "~/components/ui/input/Input.vue";
|
||||
const userAccount = ref("");
|
||||
const userPassword = ref("");
|
||||
const error = ref(false);
|
||||
const errormsg = ref("");
|
||||
const success = ref(false);
|
||||
const submitUserPassword = async () => {
|
||||
error.value = false;
|
||||
errormsg.value = "";
|
||||
// Encrypt password during transit
|
||||
const password = sha512(userPassword.value).toString();
|
||||
|
||||
@ -21,46 +27,53 @@ const submitUserPassword = async () => {
|
||||
});
|
||||
const res = await sendData.json();
|
||||
|
||||
if (res.status === "ok") {
|
||||
// Store the token in local storage
|
||||
if (!res.error) {
|
||||
error.value = false;
|
||||
localStorage.setItem("token", res.token);
|
||||
// Redirect to the home page
|
||||
window.location.href = "/";
|
||||
success.value = true;
|
||||
console.log(res);
|
||||
userAccount.value = "";
|
||||
} else {
|
||||
alert("Login failed");
|
||||
error.value = true;
|
||||
errormsg.value = res.error;
|
||||
}
|
||||
// Clear the input fields
|
||||
userAccount.value = "";
|
||||
userPassword.value = "";
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex flex-col items-center justify-center h-full">
|
||||
<div class="">
|
||||
<form
|
||||
class="flex flex-col items-center justify-center h-full"
|
||||
@submit.prevent="submitUserPassword"
|
||||
v-if="!success"
|
||||
>
|
||||
<div class="text-xl mb-4 text-bold">Login / Register</div>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
class="mb-2 p-2 border rounded"
|
||||
v-model="userAccount"
|
||||
/>
|
||||
<input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
class="p-2 border rounded mb-2"
|
||||
v-model="userPassword"
|
||||
/>
|
||||
<span class="text-2xl text-bold mb-0">Login / Register</span>
|
||||
<span class="mb-4 text-sm mt-0"
|
||||
>We will create a account for you if you don't have one.</span
|
||||
>
|
||||
<div class="">
|
||||
<Input
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
class="mb-2 p-2 border rounded"
|
||||
v-model="userAccount"
|
||||
required
|
||||
/>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
class="p-2 border rounded mb-2"
|
||||
v-model="userPassword"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<span v-if="error" class="text-red-600 text-xs m-2"
|
||||
>Error: {{ errormsg }}</span
|
||||
>
|
||||
<button class="bg-black text-white p-2 rounded transition duration-200">
|
||||
Log In
|
||||
</button>
|
||||
</form>
|
||||
<div v-else></div>
|
||||
<div v-else>Hi! ${user}</div>
|
||||
</div>
|
||||
</template>
|
@ -47,7 +47,7 @@
|
||||
"interface": "Use a desktop like interface, the one that you already got used to.",
|
||||
"documentation": "We provide a documentation for you to learn how to use the app.",
|
||||
"opensource": "This platform is open source! minus the database part, but I'm going to try!",
|
||||
"apis": "We develop apis that does not exist before, like the line today one, but it just needs some revese engineering to find the apis behind it."
|
||||
"apis": "We use api's that are made via reverse engineering."
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -73,5 +73,16 @@
|
||||
"terminal": "Terminal",
|
||||
"aboutNewsOrg": "About this news organization",
|
||||
"newsview": "News View"
|
||||
},
|
||||
"tools": {
|
||||
"title": "Tools",
|
||||
"name": {
|
||||
"checkweirdkeywords": "Check Sensivite Keywords",
|
||||
"noadlinetoday": "LINE Today but no ads"
|
||||
},
|
||||
"content": {
|
||||
"checkweirdkeywords": "This tool check if the news title has weird 18+ content.",
|
||||
"noadlinetoday": "Provides free, no ads Line today."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,5 +73,16 @@
|
||||
"terminal": "終端機",
|
||||
"aboutNewsOrg": "關於這個新聞來源",
|
||||
"newsview": "新聞"
|
||||
},
|
||||
"tools":{
|
||||
"title": "工具",
|
||||
"name": {
|
||||
"checkweirdkeywords": "檢查偏色情標體",
|
||||
"noadlinetoday": "無廣告新聞"
|
||||
},
|
||||
"content": {
|
||||
"checkweirdkeywords": "這個工具檢查新聞記者是不是使用偏色情的標體 (台灣的很愛用)",
|
||||
"noadlinetoday": "提供無廣告的LINE Today 新聞"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,211 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
// No layout
|
||||
|
||||
// interfaces
|
||||
interface currentNavBarInterface {
|
||||
name: string;
|
||||
icon: string;
|
||||
action: any;
|
||||
flash: boolean;
|
||||
windowAssociated: string;
|
||||
}
|
||||
|
||||
// Import plugins
|
||||
import { gsap } from "gsap";
|
||||
import { TextPlugin } from "gsap/TextPlugin";
|
||||
import { createApp } from "vue";
|
||||
gsap.registerPlugin(TextPlugin);
|
||||
|
||||
// Import Windows
|
||||
import SignIn from "~/components/app/windows/login.vue";
|
||||
|
||||
// Import Shadcn/UI components
|
||||
import AlertComponent from "~/components/ui/alert/Alert.vue";
|
||||
import ButtonComponent from "~/components/ui/button/Button.vue";
|
||||
import DialogComponent from "~/components/ui/dialog/Dialog.vue";
|
||||
import ProgressComponent from "~/components/ui/progress/Progress.vue";
|
||||
import HoverCardComponent from "~/components/ui/hover-card/HoverCard.vue";
|
||||
|
||||
// Icons
|
||||
import {
|
||||
ComputerDesktopIcon,
|
||||
UserIcon,
|
||||
LanguageIcon,
|
||||
ChevronRightIcon,
|
||||
} from "@heroicons/vue/24/outline";
|
||||
|
||||
// i18n
|
||||
const { t, locale, locales } = useI18n();
|
||||
const switchLocalePath = useSwitchLocalePath();
|
||||
const localePath = useLocalePath();
|
||||
|
||||
// Router
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
// values
|
||||
const popMessage = ref(null);
|
||||
const menuOpen = ref(false);
|
||||
const langMenuOpen = ref(false);
|
||||
const lang = ref(locale.value);
|
||||
const alertOpen = ref(false);
|
||||
const currentNavBar = ref<currentNavBarInterface[]>([]);
|
||||
|
||||
// Date
|
||||
const currentDate = ref(
|
||||
new Date().toLocaleDateString("zh-TW", {
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
}),
|
||||
);
|
||||
onMounted(() => {
|
||||
setInterval(() => {
|
||||
currentDate.value = new Date().toLocaleDateString("zh-TW", {
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
// functions
|
||||
const openWindow = (windowName?: string) => {
|
||||
if (windowName === "leave") {
|
||||
router.push(localePath("/home"));
|
||||
}
|
||||
console.log(windowName);
|
||||
menuOpen.value = false;
|
||||
};
|
||||
|
||||
const unMinWindow = (windowName?: string) => {
|
||||
console.log(windowName);
|
||||
};
|
||||
|
||||
// menus
|
||||
const menuItems = [
|
||||
{ name: "Hot News", windowName: "hotnews" },
|
||||
{ name: "News", windowName: "news" },
|
||||
{ name: "Sources", windowName: "sources" },
|
||||
{ name: "About This Website", windowName: "about" },
|
||||
{ name: "Settings", windowName: "settings" },
|
||||
{ name: "Leave", windowName: "leave" },
|
||||
];
|
||||
const toggleMenu = () => {
|
||||
menuOpen.value = !menuOpen.value;
|
||||
};
|
||||
// Lang Menu
|
||||
const toggleLangMenu = () => {
|
||||
langMenuOpen.value = !langMenuOpen.value;
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="absolute inset-x-0 flex flex-row px-2 py-1 bg-[#7D7C7C]/70 text-white justify-between align-center text-center z-50"
|
||||
>
|
||||
<!--Menu container-->
|
||||
<div class="flex flex-row g-2 text-gray-400 text-white z-9999">
|
||||
<button
|
||||
@click="toggleMenu"
|
||||
class="w-8 h-8 text-white hover:text-blue-500 transition-all duration-100 flex flex-row"
|
||||
>
|
||||
<ComputerDesktopIcon />
|
||||
</button>
|
||||
<span class="ml-1 mr-2 text-[20px]">|</span>
|
||||
<!--navbar icons for min and max application window-->
|
||||
<button
|
||||
class="flex flex-row items-center gap-x-2 text-gray-400 hover:text-gray-600 transition-all duration-100"
|
||||
></button>
|
||||
<div
|
||||
v-for="item in currentNavBar"
|
||||
:key="item.name"
|
||||
class="flex flex-row items-center gap-x-2 hover:bg-gray-100 transition-all duration-100 px-4 py-2 cursor-pointer"
|
||||
>
|
||||
<button
|
||||
@click="unMinWindow(item.windowAssociated)"
|
||||
class="flex flex-row items-center gap-x-2 text-gray-400 hover:text-gray-600 transition-all duration-100"
|
||||
>
|
||||
<span>{{ item.name }}</span>
|
||||
<span
|
||||
v-if="item.flash"
|
||||
class="animate-ping absolute inline-flex h-3 w-3 rounded-full bg-red-400 opacity-75"
|
||||
></span>
|
||||
<span v-if="item.icon" :class="item.icon"> </span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center align-middle justify-center text-white">
|
||||
{{ currentDate }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full h-[2.5em]"></div>
|
||||
<!--Menu-->
|
||||
<Transition
|
||||
enter-active-class="animate__animated animate__fadeInDown animate_fast03"
|
||||
leave-active-class="animate__animated animate__fadeOutUp animate_fast03"
|
||||
>
|
||||
<div
|
||||
class="m-2 p-2 bg-gray-800 shadow-lg w-fit rounded-[10px] v-9998"
|
||||
v-if="menuOpen"
|
||||
>
|
||||
<div v-for="item in menuItems" :key="item.name" class="">
|
||||
<button
|
||||
@click="openWindow(item.windowName)"
|
||||
class="flex flex-row items-center gap-x-2 text-gray-400 hover:text-gray-600 transition-all duration-100"
|
||||
>
|
||||
<span>{{ item.name }}</span>
|
||||
<ChevronRightIcon class="w-4 h-4 justify-center align-center" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
<!--Main desktop contents-->
|
||||
<div
|
||||
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-x-0 inset-y-0 z-[-1]"
|
||||
id="desktop"
|
||||
></div>
|
||||
<slot />
|
||||
<!--Footer-->
|
||||
<div
|
||||
class="absolute w-[calc(100% - 5px)] inset-x-0 bottom-0 mx-[1.5px] p-3 justify-between align-center flex flex-row"
|
||||
>
|
||||
<div class="">
|
||||
<!--Lang-->
|
||||
<span>Lang: </span>
|
||||
<span class="text-lg">{{ t("localeflag") }}</span
|
||||
>
|
||||
<button
|
||||
class="w-4 h-4 hover:text-blue-200 transition-all duration-100"
|
||||
@click="toggleLangMenu"
|
||||
>
|
||||
<LanguageIcon />
|
||||
</button>
|
||||
</div>
|
||||
<div class="gap-2 flex flex-row">
|
||||
<!--版權資訊-->
|
||||
<span class="text-sm">1.0.0</span>
|
||||
<span class="text-sm">|</span>
|
||||
<span class="text-sm">MIT License</span>
|
||||
<span class="text-sm">|</span>
|
||||
<span class="text-sm">{{ new Date().getFullYear() }} © yh</span>
|
||||
</div>
|
||||
<div class="">
|
||||
<button
|
||||
@click="openWindow('login')"
|
||||
class="w-8 h-8 text-gray-400 flex flex-row"
|
||||
>
|
||||
<UserIcon
|
||||
class="w-8 h-8 text-gray-400 hover:text-blue-500 transition-all duration-100"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
23
nginx.conf
23
nginx.conf
@ -1,14 +1,27 @@
|
||||
# Run :%s/news.yuanhau.com/your.domain.here/ in vim to replace news.yuanhau.com to your domain.
|
||||
# Caddy is currently not supported.
|
||||
# Before getting the SSL cert for your website comment the the few with the lines of #commentbeforessl
|
||||
#
|
||||
#
|
||||
#
|
||||
# If you want to change the log dir use :%s/news_analyze/{your-file-here}
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
server {
|
||||
listen 80;
|
||||
listen 443 ssl;
|
||||
ssl_certificate /etc/letsencrypt/live/news.yuanhau.com/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/news.yuanhau.com/privkey.pem;
|
||||
listen 443 ssl; #commentbeforessl
|
||||
ssl_certificate /etc/letsencrypt/live/news.yuanhau.com/fullchain.pem; #commentbeforessl
|
||||
ssl_certificate_key /etc/letsencrypt/live/news.yuanhau.com/privkey.pem; #commentbeforessl
|
||||
server_name news.yuanhau.com;
|
||||
access_log /var/log/nginx/news_analyze.access.log;
|
||||
error_log /var/log/nginx/news_analyze.error.log;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:36694;
|
||||
proxy_pass http://127.0.0.1:36694; # Traefik port.
|
||||
proxy_set_header X-real-IP $remote_addr;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
|
||||
@ -21,4 +34,4 @@ server {
|
||||
proxy_buffering off;
|
||||
proxy_cache off;
|
||||
}
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@ import { TextPlugin } from "gsap/TextPlugin";
|
||||
gsap.registerPlugin(TextPlugin);
|
||||
|
||||
// Import Windows
|
||||
import LoginWindow from "~/components/app/windows/login.vue";
|
||||
import UserWindow from "~/components/app/windows/user.vue";
|
||||
import HotNewsWindow from "~/components/app/windows/hotnews.vue";
|
||||
import SourcesWindow from "~/components/app/windows/sources.vue";
|
||||
import AboutWindow from "~/components/app/windows/about.vue";
|
||||
@ -92,7 +92,7 @@ const menuItems = [
|
||||
{ name: t("app.about"), windowName: "about" },
|
||||
{ name: t("app.terminal"), windowName: "tty" },
|
||||
{ name: t("app.settings"), windowName: "settings" },
|
||||
{ name: t("app.login"), windowName: "login" },
|
||||
{ name: t("app.login"), windowName: "user" },
|
||||
{ name: t("app.leave"), windowName: "leave" },
|
||||
];
|
||||
|
||||
@ -106,10 +106,10 @@ const associAppWindow = [
|
||||
height: "500px",
|
||||
},
|
||||
{
|
||||
name: "login",
|
||||
name: "user",
|
||||
id: "2",
|
||||
title: t("app.login"),
|
||||
component: LoginWindow,
|
||||
component: UserWindow,
|
||||
},
|
||||
{
|
||||
name: "sources",
|
||||
@ -340,6 +340,7 @@ const toggleMinWindow = (windowUUId: string) => {
|
||||
useSeoMeta({
|
||||
title: "Desktop",
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
useSeoMeta({
|
||||
title: titleAppName.value + " - Desktop",
|
||||
@ -396,9 +397,9 @@ const openArticles = async (slug: string) => {
|
||||
};
|
||||
|
||||
const getStaticArticleId = () => {
|
||||
storeStaticArticleId.value += 1
|
||||
return storeStaticArticleId.value
|
||||
}
|
||||
storeStaticArticleId.value += 1;
|
||||
return storeStaticArticleId.value;
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div v-if="changeLangAnimation">
|
||||
|
@ -1,428 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
// Make the Desktop funner // TODO
|
||||
// No layout
|
||||
definePageMeta({
|
||||
layout: false,
|
||||
});
|
||||
|
||||
// interfaces
|
||||
interface currentNavBarInterface {
|
||||
name: string;
|
||||
icon: string;
|
||||
action: any;
|
||||
flash: boolean;
|
||||
windowAssociated: string;
|
||||
minimized: boolean;
|
||||
}
|
||||
|
||||
interface associAppWindowInterface {
|
||||
name: string;
|
||||
id: string;
|
||||
absoluteId: string;
|
||||
title: string;
|
||||
component: any;
|
||||
width: string;
|
||||
height: string;
|
||||
black: boolean;
|
||||
}
|
||||
|
||||
// Import plugins
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { gsap } from "gsap";
|
||||
import { TextPlugin } from "gsap/TextPlugin";
|
||||
gsap.registerPlugin(TextPlugin);
|
||||
|
||||
// Import Windows
|
||||
import LoginWindow from "~/components/app/windows/login.vue";
|
||||
import HotNewsWindow from "~/components/app/windows/hotnews.vue";
|
||||
import SourcesWindow from "~/components/app/windows/sources.vue";
|
||||
import AboutWindow from "~/components/app/windows/about.vue";
|
||||
import ChatbotWindow from "~/components/app/windows/chatbot.vue";
|
||||
import AboutNewsOrgWindow from "~/components/app/windows/aboutNewsOrg.vue";
|
||||
import TTYWindow from "~/components/app/windows/tty.vue";
|
||||
import FavStaredWindow from "~/components/app/windows/fav.vue";
|
||||
import Error404Window from "~/components/app/windows/error404.vue";
|
||||
import NewsViewWindow from "~/components/app/windows/newsView.vue";
|
||||
|
||||
// Import Icons
|
||||
import {
|
||||
ComputerDesktopIcon,
|
||||
UserIcon,
|
||||
LanguageIcon,
|
||||
ChevronRightIcon,
|
||||
} from "@heroicons/vue/24/outline";
|
||||
|
||||
// i18n
|
||||
const { t, locale, locales } = useI18n();
|
||||
const switchLocalePath = useSwitchLocalePath();
|
||||
const localePath = useLocalePath();
|
||||
|
||||
// Router
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
// values
|
||||
const popMessage = ref(null);
|
||||
const menuOpen = ref(false);
|
||||
const langMenuOpen = ref(false);
|
||||
const lang = ref(locale.value);
|
||||
const alertOpen = ref(false);
|
||||
const currentNavBar = ref<currentNavBarInterface[]>([]);
|
||||
const bootingAnimation = ref(true);
|
||||
const activeWindows = ref<associAppWindowInterface[]>([]);
|
||||
const openApp = ref();
|
||||
const openAppId = ref();
|
||||
const openAppNameQuery = ref();
|
||||
const currentOpenAppId = ref(0);
|
||||
const progress = ref(0);
|
||||
const titleAppName = ref("Desktop");
|
||||
const openingAppViaAnApp = ref(false);
|
||||
const passedValues = ref();
|
||||
const globalWindowVal = ref(new Map());
|
||||
const changeLangAnimation = ref(false);
|
||||
|
||||
// Key Data
|
||||
const menuItems = [
|
||||
{ name: t("app.hotnews"), windowName: "hotnews" },
|
||||
{ name: t("app.news"), windowName: "news" },
|
||||
{ name: t("app.sources"), windowName: "sources" },
|
||||
{ name: t("app.starred"), windowName: "starred" },
|
||||
{ name: t("app.chatbot"), windowName: "chatbot" },
|
||||
{ name: t("app.about"), windowName: "about" },
|
||||
{ name: t("app.terminal"), windowName: "tty" },
|
||||
{ name: t("app.settings"), windowName: "settings" },
|
||||
{ name: t("app.login"), windowName: "login" },
|
||||
{ name: t("app.leave"), windowName: "leave" },
|
||||
];
|
||||
|
||||
const associAppWindow = [
|
||||
{
|
||||
name: "hotnews",
|
||||
id: "1",
|
||||
title: t("app.hotnews"),
|
||||
component: HotNewsWindow,
|
||||
width: "700px",
|
||||
height: "500px",
|
||||
},
|
||||
{
|
||||
name: "login",
|
||||
id: "2",
|
||||
title: t("app.login"),
|
||||
component: LoginWindow,
|
||||
},
|
||||
{
|
||||
name: "sources",
|
||||
id: "3",
|
||||
title: t("app.sources"),
|
||||
component: SourcesWindow,
|
||||
width: "700px",
|
||||
height: "500px",
|
||||
},
|
||||
{
|
||||
name: "about",
|
||||
id: "4",
|
||||
title: t("app.about"),
|
||||
component: AboutWindow,
|
||||
},
|
||||
{
|
||||
name: "settings",
|
||||
id: "5",
|
||||
title: t("app.settings"),
|
||||
component: Error404Window,
|
||||
},
|
||||
{
|
||||
name: "news",
|
||||
id: "6",
|
||||
title: t("app.news"),
|
||||
component: Error404Window,
|
||||
},
|
||||
{
|
||||
name: "starred",
|
||||
id: "7",
|
||||
title: t("app.starred"),
|
||||
component: FavStaredWindow,
|
||||
},
|
||||
{
|
||||
name: "chatbot",
|
||||
id: "8",
|
||||
title: t("app.chatbot"),
|
||||
component: ChatbotWindow,
|
||||
width: "400px",
|
||||
height: "600px",
|
||||
},
|
||||
{
|
||||
name: "error404",
|
||||
id: "9",
|
||||
title: t("app.error404"),
|
||||
component: Error404Window,
|
||||
},
|
||||
{
|
||||
name: "aboutNewsOrg",
|
||||
id: "10",
|
||||
title: t("app.aboutNewsOrg"),
|
||||
component: AboutNewsOrgWindow,
|
||||
},
|
||||
{
|
||||
name: "tty",
|
||||
id: "11",
|
||||
title: t("app.terminal"),
|
||||
component: TTYWindow,
|
||||
black: true,
|
||||
},
|
||||
{
|
||||
name: "newsView",
|
||||
id: "12",
|
||||
title: t("app.newsview"),
|
||||
component: NewsViewWindow,
|
||||
},
|
||||
];
|
||||
|
||||
// Date
|
||||
const currentDate = ref(
|
||||
new Date().toLocaleDateString("zh-TW", {
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
}),
|
||||
);
|
||||
onMounted(() => {
|
||||
setInterval(() => {
|
||||
currentDate.value = new Date().toLocaleDateString("zh-TW", {
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
// functions
|
||||
onMounted(() => {
|
||||
associAppWindow.forEach((window) => {
|
||||
globalWindowVal.value.set(window.name, {
|
||||
id: window.id,
|
||||
title: window.title,
|
||||
windowCount: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const openWindow = (windowName?: string) => {
|
||||
if (windowName === "leave") {
|
||||
if (confirm("Are you sure?")) {
|
||||
router.push(localePath("/home"));
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (windowName) findAndOpenWindow(windowName);
|
||||
}
|
||||
menuOpen.value = false;
|
||||
};
|
||||
|
||||
const unMinWindow = (windowName?: string) => {
|
||||
console.log(windowName);
|
||||
};
|
||||
|
||||
// menus
|
||||
const toggleMenu = () => {
|
||||
menuOpen.value = !menuOpen.value;
|
||||
};
|
||||
// Lang Menu
|
||||
const toggleLangMenu = () => {
|
||||
langMenuOpen.value = !langMenuOpen.value;
|
||||
};
|
||||
|
||||
// ?openapp= component
|
||||
onMounted(async () => {
|
||||
openApp.value = route.query.openapp;
|
||||
openAppId.value = route.query.id;
|
||||
if (openApp.value) {
|
||||
// DO NOT REMOVE THIS FUNCTION!! IT WILL ABSOLUTELY 100% FAIL!
|
||||
if (openApp.value === "newsView") {
|
||||
return;
|
||||
}
|
||||
openWindow(openApp.value);
|
||||
}
|
||||
});
|
||||
|
||||
const findAndOpenWindow = (windowName: string) => {
|
||||
const app = associAppWindow.find((app) => app.name === windowName);
|
||||
|
||||
// Prevent dual logins
|
||||
if (
|
||||
windowName === "login" &&
|
||||
activeWindows.value.some((window) => window.name === "login")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent dual about
|
||||
if (
|
||||
windowName === "about" &&
|
||||
activeWindows.value.some((window) => window.name === "about")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (app) {
|
||||
// Use shallowRef for better performance with components
|
||||
const windowComponent = shallowRef(app.component);
|
||||
titleAppName.value = app.title;
|
||||
const abosluteId = uuidv4();
|
||||
activeWindows.value.push({
|
||||
id: currentOpenAppId.value,
|
||||
absoluteId: abosluteId,
|
||||
component: windowComponent,
|
||||
name: windowName,
|
||||
title: app.title,
|
||||
width: app.width || "600px",
|
||||
height: app.height || "400px",
|
||||
black: app.black || false,
|
||||
});
|
||||
currentOpenAppId.value++;
|
||||
// Add to navbar
|
||||
const windowNameVal2 =
|
||||
globalWindowVal.value.get(windowName).windowCount === 1
|
||||
? windowName
|
||||
: windowName +
|
||||
"(" +
|
||||
globalWindowVal.value.get(windowName).windowCount +
|
||||
")";
|
||||
currentNavBar.value.push({
|
||||
name: windowNameVal2,
|
||||
icon: "anything",
|
||||
action: "idk",
|
||||
flash: true,
|
||||
windowAssociated: abosluteId,
|
||||
minimized: false,
|
||||
});
|
||||
globalWindowVal.value.get(windowName).windowCount++;
|
||||
}
|
||||
};
|
||||
|
||||
const obtainTopWindowPosition = (windowId: string) => {
|
||||
if (!openingAppViaAnApp.value) {
|
||||
const windowIndex = activeWindows.value.findIndex(
|
||||
(window) => window.id === windowId,
|
||||
);
|
||||
if (windowIndex !== -1) {
|
||||
const [window] = activeWindows.value.splice(windowIndex, 1);
|
||||
titleAppName.value = window.title;
|
||||
activeWindows.value.push(window);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const closeWindow = (windowId: string, windowAID: string) => {
|
||||
activeWindows.value = activeWindows.value.filter(
|
||||
(window) => window.id !== windowId,
|
||||
);
|
||||
currentNavBar.value = currentNavBar.value.filter(
|
||||
(window) => window.windowAssociated !== windowAID,
|
||||
);
|
||||
console.log("activeWindows.value", activeWindows.value);
|
||||
};
|
||||
|
||||
const openNewWindowViaApp = (windowId: string) => {
|
||||
openingAppViaAnApp.value = true;
|
||||
findAndOpenWindow(windowId);
|
||||
setTimeout(() => {
|
||||
openingAppViaAnApp.value = false;
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const maxWindow = (windowUUId: string) => {
|
||||
const windowIndex = activeWindows.value.findIndex(
|
||||
(window) => window.absoluteId === windowUUId,
|
||||
);
|
||||
console.log(windowIndex);
|
||||
};
|
||||
|
||||
const toggleMinWindow = (windowUUId: string) => {
|
||||
const windowIndex = "";
|
||||
};
|
||||
|
||||
// Title
|
||||
useSeoMeta({
|
||||
title: "Desktop",
|
||||
});
|
||||
watchEffect(() => {
|
||||
useSeoMeta({
|
||||
title: titleAppName.value + " - Desktop",
|
||||
});
|
||||
});
|
||||
// Booting animation
|
||||
onMounted(() => {
|
||||
const changeLang = route.query.changelang;
|
||||
if (changeLang) {
|
||||
bootingAnimation.value = false;
|
||||
changeLangAnimation.value = true;
|
||||
}
|
||||
setTimeout(() => {
|
||||
changeLangAnimation.value = false;
|
||||
}, 4000);
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// booting animation bypass
|
||||
const bootingHeaderParams = route.query.bypass;
|
||||
if (bootingHeaderParams) {
|
||||
bootingAnimation.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (bootingAnimation.value) {
|
||||
gsap.to(popMessage.value, {
|
||||
duration: 0.5,
|
||||
text: t("app.booting"),
|
||||
ease: "none",
|
||||
});
|
||||
}
|
||||
setTimeout(() => {
|
||||
bootingAnimation.value = false;
|
||||
}, 2000);
|
||||
});
|
||||
|
||||
watchEffect((cleanupFn) => {
|
||||
const tier = setTimeout(() => (progress.value = 10), Math.random() * 50);
|
||||
const timer = setTimeout(() => (progress.value = 30), Math.random() * 100);
|
||||
const timmer = setTimeout(() => (progress.value = 70), Math.random() * 150);
|
||||
const timmmer = setTimeout(() => (progress.value = 100), 1800);
|
||||
cleanupFn(() => clearTimeout(tier));
|
||||
cleanupFn(() => clearTimeout(timer));
|
||||
cleanupFn(() => clearTimeout(timmer));
|
||||
cleanupFn(() => clearTimeout(timmmer));
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div v-if="changeLangAnimation">
|
||||
<div
|
||||
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-0 overscroll-none bg-gray-600/50 z-[999999]"
|
||||
>
|
||||
<span>{{ t("app.changelangmessage") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="bootingAnimation">
|
||||
<div
|
||||
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-0 overscroll-none"
|
||||
>
|
||||
<Progress
|
||||
v-model="progress"
|
||||
class="w-3/5 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-gradient-to-r from-[#2a7b9b] then-[#8d57c7] to-[#ed4242]"
|
||||
/>
|
||||
<br />
|
||||
<span class="text-xl text-bold mt-3 text-sky-200">{{
|
||||
t("app.launchtext")
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
@ -2,27 +2,31 @@
|
||||
const localePath = useLocalePath();
|
||||
// Import Icons
|
||||
import { SearchXIcon, CircleSlash2Icon } from "lucide-vue-next";
|
||||
const { t } = useI18n();
|
||||
// Array
|
||||
const tools = [
|
||||
{
|
||||
name: "檢查偏色情標體",
|
||||
content: "這個工具檢查新聞記者是不是使用偏色情的標體 (台灣的很愛用)",
|
||||
name: t("tools.name.checkweirdkeywords"),
|
||||
content: t("tools.content.checkweirdkeywords"),
|
||||
icon: SearchXIcon,
|
||||
go: localePath("/tools/checkweirdkeywords"),
|
||||
},
|
||||
{
|
||||
name: "無廣告新聞",
|
||||
content: "提供無廣告的LINE Today 新聞",
|
||||
name: t("tools.name.noadlinetoday"),
|
||||
content: t("tools.content.noadlinetoday"),
|
||||
icon: CircleSlash2Icon,
|
||||
go: localePath("/tools/freelinetoday"),
|
||||
},
|
||||
];
|
||||
useSeoMeta({
|
||||
title: `${t("tools.title")}`
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
class="justify-center align-center absolute inset-0 flex flex-col w-full h-screen"
|
||||
>
|
||||
<h1 class="text-5xl text-bold m-4 text-center">Tools</h1>
|
||||
<h1 class="text-5xl text-bold m-4 text-center">{{ t("tools.title") }}</h1>
|
||||
<div
|
||||
class="justify-center align-center gap-2 p-2 w-full flex flex-row flex-wrap relative"
|
||||
>
|
||||
|
@ -13,6 +13,7 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
const body = await readBody(event);
|
||||
const { username, password } = body;
|
||||
console.log(password);
|
||||
if (!username || !password) {
|
||||
return {
|
||||
error: "NO_USER_AND_PASSWORD_SUBMITED",
|
||||
@ -25,45 +26,58 @@ export default defineEventHandler(async (event) => {
|
||||
};
|
||||
}
|
||||
// Server side hashing
|
||||
const hashedPassword = await argon2.hash(salt, password);
|
||||
|
||||
// Check if user exists, if not, create a user
|
||||
try {
|
||||
console.log(username);
|
||||
const fetchUserInfo = await sql`
|
||||
select * from users
|
||||
where user = ${username}`;
|
||||
if (!fetchUserInfo) {
|
||||
where username = ${username}`;
|
||||
console.log(fetchUserInfo[0]);
|
||||
if (fetchUserInfo.length === 0) {
|
||||
const hashedPassword = await argon2.hash(salt + password);
|
||||
const createNewUser = await sql`
|
||||
insert into users (uuid, username, passwordhash)
|
||||
values (${uuidv4()}, ${username}, ${hashedPassword})
|
||||
`;
|
||||
if (!createNewUser) {
|
||||
console.log(createNewUser);
|
||||
if (fetchUserInfo.length !== 0) {
|
||||
return {
|
||||
error: "CANNOT_CREATE_NEW_USER",
|
||||
};
|
||||
}
|
||||
const newToken = uuidv4();
|
||||
//const newToken64 = atob(newToken);
|
||||
return {
|
||||
user: fetchUserInfo,
|
||||
token: newToken,
|
||||
};
|
||||
} else {
|
||||
if (fetchUserInfo.password !== hashedPassword) {
|
||||
const isValid = await argon2.verify(
|
||||
fetchUserInfo[0].passwordhash,
|
||||
salt + password,
|
||||
);
|
||||
if (!isValid) {
|
||||
return {
|
||||
error: "PASSWORD_NO_MATCH",
|
||||
};
|
||||
}
|
||||
const newToken = uuidv4();
|
||||
const newToken64 = atob(newToken);
|
||||
const saveNewToken = await sql`
|
||||
insert into usertokens
|
||||
`;
|
||||
if (!saveNewToken) {
|
||||
return {
|
||||
error: "CANNOT_CREATE_NEW_TOKEN",
|
||||
};
|
||||
}
|
||||
return {
|
||||
user: fetchUserInfo.user,
|
||||
token: newToken,
|
||||
};
|
||||
}
|
||||
const newToken = uuidv4();
|
||||
const newToken64 = btoa(newToken);
|
||||
const fetchUserInfoAgain = await sql`
|
||||
select * from users
|
||||
where username = ${username}`;
|
||||
/*await sql`
|
||||
INSERT INTO usertokens (user, token)
|
||||
VALUES (${fetchUserInfo[0].username}, ${newToken64})
|
||||
`;*/
|
||||
return {
|
||||
user: fetchUserInfoAgain,
|
||||
token: newToken,
|
||||
};
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return {
|
||||
error: "UNABLE_TO_PROCESS",
|
||||
};
|
||||
|
14
server/routes/shortforward.ts
Normal file
14
server/routes/shortforward.ts
Normal file
@ -0,0 +1,14 @@
|
||||
export default defineEventHandler((event) => {
|
||||
const query = getQuery(event);
|
||||
const toolCall = query.tool;
|
||||
const forwardCall = query.forward;
|
||||
if (toolCall) {
|
||||
const buildUrl = "/desktop?openapp=" + toolCall;
|
||||
return sendRedirect(event, buildUrl, 302);
|
||||
}
|
||||
if (forwardCall) {
|
||||
const buildUrl = "/" + forwardCall;
|
||||
return sendRedirect(event, buildUrl, 302);
|
||||
}
|
||||
return sendRedirect(event, "/", 302)
|
||||
})
|
@ -25,8 +25,8 @@ async function lineToday(slug: string) {
|
||||
.text()
|
||||
.replaceAll("\n", "")
|
||||
.replace(" ", "");
|
||||
const paragraph = [];
|
||||
const images = [];
|
||||
const paragraph = <any[]>[];
|
||||
const images = <any[]>[];
|
||||
html("article.news-content")
|
||||
.contents()
|
||||
.each((i, element) => {
|
||||
|
@ -46,3 +46,4 @@
|
||||
--chart-5: 340 75% 55%;
|
||||
}
|
||||
}
|
||||
@plugin 'tailwind-scrollbar';
|
||||
|
Loading…
x
Reference in New Issue
Block a user