diff --git a/frontend/package.json b/frontend/package.json index 6f57298..6177d70 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,10 +10,10 @@ "preview": "vite preview" }, "dependencies": { - "@tailwindcss/vite": "^4.1.4", "react": "^19.0.0", "react-dom": "^19.0.0", - "tailwindcss": "^4.1.4" + "react-jss": "^10.10.0", + "zustand": "^5.0.3" }, "devDependencies": { "@eslint/js": "^9.22.0", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index f287b77..5258186 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -8,18 +8,18 @@ importers: .: dependencies: - '@tailwindcss/vite': - specifier: ^4.1.4 - version: 4.1.4(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2)) react: specifier: ^19.0.0 version: 19.1.0 react-dom: specifier: ^19.0.0 version: 19.1.0(react@19.1.0) - tailwindcss: - specifier: ^4.1.4 - version: 4.1.4 + react-jss: + specifier: ^10.10.0 + version: 10.10.0(react@19.1.0) + zustand: + specifier: ^5.0.3 + version: 5.0.3(@types/react@19.1.2)(react@19.1.0) devDependencies: '@eslint/js': specifier: ^9.22.0 @@ -128,6 +128,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.27.0': + resolution: {integrity: sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.0': resolution: {integrity: sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==} engines: {node: '>=6.9.0'} @@ -140,6 +144,12 @@ packages: resolution: {integrity: sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==} engines: {node: '>=6.9.0'} + '@emotion/is-prop-valid@0.7.3': + resolution: {integrity: sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==} + + '@emotion/memoize@0.7.1': + resolution: {integrity: sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==} + '@esbuild/aix-ppc64@0.25.3': resolution: {integrity: sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ==} engines: {node: '>=18'} @@ -489,100 +499,6 @@ packages: cpu: [x64] os: [win32] - '@tailwindcss/node@4.1.4': - resolution: {integrity: sha512-MT5118zaiO6x6hNA04OWInuAiP1YISXql8Z+/Y8iisV5nuhM8VXlyhRuqc2PEviPszcXI66W44bCIk500Oolhw==} - - '@tailwindcss/oxide-android-arm64@4.1.4': - resolution: {integrity: sha512-xMMAe/SaCN/vHfQYui3fqaBDEXMu22BVwQ33veLc8ep+DNy7CWN52L+TTG9y1K397w9nkzv+Mw+mZWISiqhmlA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-darwin-arm64@4.1.4': - resolution: {integrity: sha512-JGRj0SYFuDuAGilWFBlshcexev2hOKfNkoX+0QTksKYq2zgF9VY/vVMq9m8IObYnLna0Xlg+ytCi2FN2rOL0Sg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.1.4': - resolution: {integrity: sha512-sdDeLNvs3cYeWsEJ4H1DvjOzaGios4QbBTNLVLVs0XQ0V95bffT3+scptzYGPMjm7xv4+qMhCDrkHwhnUySEzA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-freebsd-x64@4.1.4': - resolution: {integrity: sha512-VHxAqxqdghM83HslPhRsNhHo91McsxRJaEnShJOMu8mHmEj9Ig7ToHJtDukkuLWLzLboh2XSjq/0zO6wgvykNA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.4': - resolution: {integrity: sha512-OTU/m/eV4gQKxy9r5acuesqaymyeSCnsx1cFto/I1WhPmi5HDxX1nkzb8KYBiwkHIGg7CTfo/AcGzoXAJBxLfg==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.4': - resolution: {integrity: sha512-hKlLNvbmUC6z5g/J4H+Zx7f7w15whSVImokLPmP6ff1QqTVE+TxUM9PGuNsjHvkvlHUtGTdDnOvGNSEUiXI1Ww==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@tailwindcss/oxide-linux-arm64-musl@4.1.4': - resolution: {integrity: sha512-X3As2xhtgPTY/m5edUtddmZ8rCruvBvtxYLMw9OsZdH01L2gS2icsHRwxdU0dMItNfVmrBezueXZCHxVeeb7Aw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@tailwindcss/oxide-linux-x64-gnu@4.1.4': - resolution: {integrity: sha512-2VG4DqhGaDSmYIu6C4ua2vSLXnJsb/C9liej7TuSO04NK+JJJgJucDUgmX6sn7Gw3Cs5ZJ9ZLrnI0QRDOjLfNQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@tailwindcss/oxide-linux-x64-musl@4.1.4': - resolution: {integrity: sha512-v+mxVgH2kmur/X5Mdrz9m7TsoVjbdYQT0b4Z+dr+I4RvreCNXyCFELZL/DO0M1RsidZTrm6O1eMnV6zlgEzTMQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@tailwindcss/oxide-wasm32-wasi@4.1.4': - resolution: {integrity: sha512-2TLe9ir+9esCf6Wm+lLWTMbgklIjiF0pbmDnwmhR9MksVOq+e8aP3TSsXySnBDDvTTVd/vKu1aNttEGj3P6l8Q==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.4': - resolution: {integrity: sha512-VlnhfilPlO0ltxW9/BgfLI5547PYzqBMPIzRrk4W7uupgCt8z6Trw/tAj6QUtF2om+1MH281Pg+HHUJoLesmng==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.1.4': - resolution: {integrity: sha512-+7S63t5zhYjslUGb8NcgLpFXD+Kq1F/zt5Xv5qTv7HaFTG/DHyHD9GA6ieNAxhgyA4IcKa/zy7Xx4Oad2/wuhw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide@4.1.4': - resolution: {integrity: sha512-p5wOpXyOJx7mKh5MXh5oKk+kqcz8T+bA3z/5VWWeQwFrmuBItGwz8Y2CHk/sJ+dNb9B0nYFfn0rj/cKHZyjahQ==} - engines: {node: '>= 10'} - - '@tailwindcss/vite@4.1.4': - resolution: {integrity: sha512-4UQeMrONbvrsXKXXp/uxmdEN5JIJ9RkH7YVzs6AMxC/KC1+Np7WZBaNIco7TEjlkthqxZbt8pU/ipD+hKjm80A==} - peerDependencies: - vite: ^5.2.0 || ^6 - '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -728,6 +644,12 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + css-jss@10.10.0: + resolution: {integrity: sha512-YyMIS/LsSKEGXEaVJdjonWe18p4vXLo8CMA4FrW/kcaEyqdIGKCFXao31gbJddXEdIxSXFFURWrenBJPlKTgAA==} + + css-vendor@2.0.8: + resolution: {integrity: sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==} + csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} @@ -750,10 +672,6 @@ packages: electron-to-chromium@1.5.143: resolution: {integrity: sha512-QqklJMOFBMqe46k8iIOwA9l2hz57V2OKMmP5eSWcUvwx+mASAsbU+wkF1pHjn9ZVSBPrsYWr4/W/95y5SwYg2g==} - enhanced-resolve@5.18.1: - resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} - engines: {node: '>=10.13.0'} - esbuild@0.25.3: resolution: {integrity: sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q==} engines: {node: '>=18'} @@ -892,9 +810,6 @@ packages: resolution: {integrity: sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==} engines: {node: '>=18'} - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -902,6 +817,12 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + + hyphenate-style-name@1.1.0: + resolution: {integrity: sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==} + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -922,6 +843,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-in-browser@1.1.3: + resolution: {integrity: sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -959,6 +883,48 @@ packages: engines: {node: '>=6'} hasBin: true + jss-plugin-camel-case@10.10.0: + resolution: {integrity: sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==} + + jss-plugin-compose@10.10.0: + resolution: {integrity: sha512-F5kgtWpI2XfZ3Z8eP78tZEYFdgTIbpA/TMuX3a8vwrNolYtN1N4qJR/Ob0LAsqIwCMLojtxN7c7Oo/+Vz6THow==} + + jss-plugin-default-unit@10.10.0: + resolution: {integrity: sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==} + + jss-plugin-expand@10.10.0: + resolution: {integrity: sha512-ymT62W2OyDxBxr7A6JR87vVX9vTq2ep5jZLIdUSusfBIEENLdkkc0lL/Xaq8W9s3opUq7R0sZQpzRWELrfVYzA==} + + jss-plugin-extend@10.10.0: + resolution: {integrity: sha512-sKYrcMfr4xxigmIwqTjxNcHwXJIfvhvjTNxF+Tbc1NmNdyspGW47Ey6sGH8BcQ4FFQhLXctpWCQSpDwdNmXSwg==} + + jss-plugin-global@10.10.0: + resolution: {integrity: sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==} + + jss-plugin-nested@10.10.0: + resolution: {integrity: sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==} + + jss-plugin-props-sort@10.10.0: + resolution: {integrity: sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==} + + jss-plugin-rule-value-function@10.10.0: + resolution: {integrity: sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==} + + jss-plugin-rule-value-observable@10.10.0: + resolution: {integrity: sha512-ZLMaYrR3QE+vD7nl3oNXuj79VZl9Kp8/u6A1IbTPDcuOu8b56cFdWRZNZ0vNr8jHewooEeq2doy8Oxtymr2ZPA==} + + jss-plugin-template@10.10.0: + resolution: {integrity: sha512-ocXZBIOJOA+jISPdsgkTs8wwpK6UbsvtZK5JI7VUggTD6LWKbtoxUzadd2TpfF+lEtlhUmMsCkTRNkITdPKa6w==} + + jss-plugin-vendor-prefixer@10.10.0: + resolution: {integrity: sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==} + + jss-preset-default@10.10.0: + resolution: {integrity: sha512-GL175Wt2FGhjE+f+Y3aWh+JioL06/QWFgZp53CbNNq6ZkVU0TDplD8Bxm9KnkotAYn3FlplNqoW5CjyLXcoJ7Q==} + + jss@10.10.0: + resolution: {integrity: sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -1041,6 +1007,10 @@ packages: lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -1073,6 +1043,10 @@ packages: node-releases@2.0.19: resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -1116,6 +1090,9 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1123,11 +1100,22 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + react-display-name@0.2.5: + resolution: {integrity: sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==} + react-dom@19.1.0: resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==} peerDependencies: react: ^19.1.0 + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-jss@10.10.0: + resolution: {integrity: sha512-WLiq84UYWqNBF6579/uprcIUnM1TSywYq6AIjKTTTG5ziJl9Uy+pwuvpN3apuyVwflMbD60PraeTKT7uWH9XEQ==} + peerDependencies: + react: '>=16.8.6' + react-refresh@0.17.0: resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} engines: {node: '>=0.10.0'} @@ -1136,6 +1124,9 @@ packages: resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} engines: {node: '>=0.10.0'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1164,6 +1155,9 @@ packages: engines: {node: '>=10'} hasBin: true + shallow-equal@1.2.1: + resolution: {integrity: sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1184,12 +1178,18 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} - tailwindcss@4.1.4: - resolution: {integrity: sha512-1ZIUqtPITFbv/DxRmDr5/agPqJwF69d24m9qmM1939TJehgY539CtzeZRjbLt5G6fSy/7YqqYsfvoTEw9xUI2A==} + symbol-observable@1.2.0: + resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==} + engines: {node: '>=0.10.0'} - tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} - engines: {node: '>=6'} + theming@3.3.0: + resolution: {integrity: sha512-u6l4qTJRDaWZsqa8JugaNt7Xd8PPl9+gonZaIe28vAhqgHMIG/DOyFPqiKN/gQLQYj05tHv+YQdNILL4zoiAVA==} + engines: {node: '>=8'} + peerDependencies: + react: '>=16.3' + + tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} tinyglobby@0.2.13: resolution: {integrity: sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==} @@ -1286,6 +1286,24 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + zustand@5.0.3: + resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + snapshots: '@ampproject/remapping@2.3.0': @@ -1380,6 +1398,10 @@ snapshots: '@babel/core': 7.26.10 '@babel/helper-plugin-utils': 7.26.5 + '@babel/runtime@7.27.0': + dependencies: + regenerator-runtime: 0.14.1 + '@babel/template@7.27.0': dependencies: '@babel/code-frame': 7.26.2 @@ -1403,6 +1425,12 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@emotion/is-prop-valid@0.7.3': + dependencies: + '@emotion/memoize': 0.7.1 + + '@emotion/memoize@0.7.1': {} + '@esbuild/aix-ppc64@0.25.3': optional: true @@ -1624,71 +1652,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.40.0': optional: true - '@tailwindcss/node@4.1.4': - dependencies: - enhanced-resolve: 5.18.1 - jiti: 2.4.2 - lightningcss: 1.29.2 - tailwindcss: 4.1.4 - - '@tailwindcss/oxide-android-arm64@4.1.4': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.1.4': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.1.4': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.1.4': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.4': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.4': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.1.4': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.1.4': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.1.4': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.1.4': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.4': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.1.4': - optional: true - - '@tailwindcss/oxide@4.1.4': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.4 - '@tailwindcss/oxide-darwin-arm64': 4.1.4 - '@tailwindcss/oxide-darwin-x64': 4.1.4 - '@tailwindcss/oxide-freebsd-x64': 4.1.4 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.4 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.4 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.4 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.4 - '@tailwindcss/oxide-linux-x64-musl': 4.1.4 - '@tailwindcss/oxide-wasm32-wasi': 4.1.4 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.4 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.4 - - '@tailwindcss/vite@4.1.4(vite@6.3.3(jiti@2.4.2)(lightningcss@1.29.2))': - dependencies: - '@tailwindcss/node': 4.1.4 - '@tailwindcss/oxide': 4.1.4 - tailwindcss: 4.1.4 - vite: 6.3.3(jiti@2.4.2)(lightningcss@1.29.2) - '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.0 @@ -1876,6 +1839,17 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + css-jss@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + jss-preset-default: 10.10.0 + + css-vendor@2.0.8: + dependencies: + '@babel/runtime': 7.27.0 + is-in-browser: 1.1.3 + csstype@3.1.3: {} debug@4.4.0: @@ -1884,15 +1858,11 @@ snapshots: deep-is@0.1.4: {} - detect-libc@2.0.4: {} + detect-libc@2.0.4: + optional: true electron-to-chromium@1.5.143: {} - enhanced-resolve@5.18.1: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.2.1 - esbuild@0.25.3: optionalDependencies: '@esbuild/aix-ppc64': 0.25.3 @@ -2063,12 +2033,16 @@ snapshots: globals@16.0.0: {} - graceful-fs@4.2.11: {} - graphemer@1.4.0: {} has-flag@4.0.0: {} + hoist-non-react-statics@3.3.2: + dependencies: + react-is: 16.13.1 + + hyphenate-style-name@1.1.0: {} + ignore@5.3.2: {} import-fresh@3.3.1: @@ -2084,11 +2058,14 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-in-browser@1.1.3: {} + is-number@7.0.0: {} isexe@2.0.0: {} - jiti@2.4.2: {} + jiti@2.4.2: + optional: true js-tokens@4.0.0: {} @@ -2106,6 +2083,98 @@ snapshots: json5@2.2.3: {} + jss-plugin-camel-case@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + hyphenate-style-name: 1.1.0 + jss: 10.10.0 + + jss-plugin-compose@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + tiny-warning: 1.0.3 + + jss-plugin-default-unit@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + + jss-plugin-expand@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + + jss-plugin-extend@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + tiny-warning: 1.0.3 + + jss-plugin-global@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + + jss-plugin-nested@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + tiny-warning: 1.0.3 + + jss-plugin-props-sort@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + + jss-plugin-rule-value-function@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + tiny-warning: 1.0.3 + + jss-plugin-rule-value-observable@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + symbol-observable: 1.2.0 + + jss-plugin-template@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + tiny-warning: 1.0.3 + + jss-plugin-vendor-prefixer@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + css-vendor: 2.0.8 + jss: 10.10.0 + + jss-preset-default@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + jss: 10.10.0 + jss-plugin-camel-case: 10.10.0 + jss-plugin-compose: 10.10.0 + jss-plugin-default-unit: 10.10.0 + jss-plugin-expand: 10.10.0 + jss-plugin-extend: 10.10.0 + jss-plugin-global: 10.10.0 + jss-plugin-nested: 10.10.0 + jss-plugin-props-sort: 10.10.0 + jss-plugin-rule-value-function: 10.10.0 + jss-plugin-rule-value-observable: 10.10.0 + jss-plugin-template: 10.10.0 + jss-plugin-vendor-prefixer: 10.10.0 + + jss@10.10.0: + dependencies: + '@babel/runtime': 7.27.0 + csstype: 3.1.3 + is-in-browser: 1.1.3 + tiny-warning: 1.0.3 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -2159,6 +2228,7 @@ snapshots: lightningcss-linux-x64-musl: 1.29.2 lightningcss-win32-arm64-msvc: 1.29.2 lightningcss-win32-x64-msvc: 1.29.2 + optional: true locate-path@6.0.0: dependencies: @@ -2166,6 +2236,10 @@ snapshots: lodash.merge@4.6.2: {} + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -2193,6 +2267,8 @@ snapshots: node-releases@2.0.19: {} + object-assign@4.1.1: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -2232,19 +2308,46 @@ snapshots: prelude-ls@1.2.1: {} + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + punycode@2.3.1: {} queue-microtask@1.2.3: {} + react-display-name@0.2.5: {} + react-dom@19.1.0(react@19.1.0): dependencies: react: 19.1.0 scheduler: 0.26.0 + react-is@16.13.1: {} + + react-jss@10.10.0(react@19.1.0): + dependencies: + '@babel/runtime': 7.27.0 + '@emotion/is-prop-valid': 0.7.3 + css-jss: 10.10.0 + hoist-non-react-statics: 3.3.2 + is-in-browser: 1.1.3 + jss: 10.10.0 + jss-preset-default: 10.10.0 + prop-types: 15.8.1 + react: 19.1.0 + shallow-equal: 1.2.1 + theming: 3.3.0(react@19.1.0) + tiny-warning: 1.0.3 + react-refresh@0.17.0: {} react@19.1.0: {} + regenerator-runtime@0.14.1: {} + resolve-from@4.0.0: {} reusify@1.1.0: {} @@ -2285,6 +2388,8 @@ snapshots: semver@7.7.1: {} + shallow-equal@1.2.1: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -2299,9 +2404,17 @@ snapshots: dependencies: has-flag: 4.0.0 - tailwindcss@4.1.4: {} + symbol-observable@1.2.0: {} - tapable@2.2.1: {} + theming@3.3.0(react@19.1.0): + dependencies: + hoist-non-react-statics: 3.3.2 + prop-types: 15.8.1 + react: 19.1.0 + react-display-name: 0.2.5 + tiny-warning: 1.0.3 + + tiny-warning@1.0.3: {} tinyglobby@0.2.13: dependencies: @@ -2364,3 +2477,8 @@ snapshots: yallist@3.1.1: {} yocto-queue@0.1.0: {} + + zustand@5.0.3(@types/react@19.1.2)(react@19.1.0): + optionalDependencies: + '@types/react': 19.1.2 + react: 19.1.0 diff --git a/frontend/src/App.css b/frontend/src/App.css deleted file mode 100644 index e69de29..0000000 diff --git a/frontend/src/component/button/u-button.tsx b/frontend/src/component/button/u-button.tsx new file mode 100644 index 0000000..1ea6371 --- /dev/null +++ b/frontend/src/component/button/u-button.tsx @@ -0,0 +1,33 @@ +import React, {ReactNode} from 'react'; +import {createUseStyles} from "react-jss"; + +const useStyle = createUseStyles({ + ubutton: { + backgroundColor: "#4CAF50", + color: "white", + padding: "10px 20px", + border: "none", + borderRadius: "5px", + cursor: "pointer", + transition: "background-color 0.3s", + "&:hover": { + backgroundColor: "#45a049", + }, + "&:disabled": { + backgroundColor: "#a5d6a7", + cursor: "not-allowed", + }, + } +}) +type Props = { + onClick: () => void; + children: ReactNode; + disabled?: boolean; + style?: React.CSSProperties | undefined; +}; +export const UButton: React.FC = ({onClick, children, style,disabled = false}) => { + const classes= useStyle() + return +} \ No newline at end of file diff --git a/frontend/src/page/component/panel-left.tsx b/frontend/src/page/component/panel-left.tsx new file mode 100644 index 0000000..9c97832 --- /dev/null +++ b/frontend/src/page/component/panel-left.tsx @@ -0,0 +1,85 @@ +import {createUseStyles} from "react-jss"; +import {UButton} from "../../component/button/u-button.tsx"; +import React from "react"; +import {useStore} from "../../store/share.ts"; + +const useStyle = createUseStyles({ + container: { + backgroundColor: "#e3f2fd", + display: "flex", + justifyContent: "center", + alignItems: "center", + }, + form: { + backgroundColor: "#C8E6C9", + boxShadow: "inset 0 0 15px rgba(56, 142, 60, 0.15)", + padding: "30px", + borderRadius: "15px", + width: "70%", + margin: "20px 60px 20px 0", + /*todo margin 不用 px*/ + }, + title: { + color: "#2c9678" + }, + file: { + display: 'none', + }, + preview: { + marginTop: '10px', + display: 'flex', + }, + name: { + color: "#2c9678", + marginLeft: '10px' + }, + clean: { + borderRadius: '50%', + cursor: 'pointer', + '&:hover': {} + } +}) +export const PanelLeft = () => { + const style = useStyle() + const {file, setFile} = useStore() + + function onFileSelect() { + // @ts-ignore + document.querySelector('#real-file-input').click(); + } + + function onFileChange(e: React.ChangeEvent) { + console.log('[D] onFileChange: e =', e) + setFile(e.currentTarget.files ? e.currentTarget.files[0] : null) + } + + function onFileUpload() { + console.log('[D] onFileUpload: upload file =', file) + } + + function onFileClean() { + setFile(null) + } + + return
+
+

上传文件

+ { + !file && + 选择文件 + } + { + file && + 上传文件 + } + + { + file && +
+
×
+
{file.name}
+
+ } +
+
+}; \ No newline at end of file diff --git a/frontend/src/page/component/panel-mid.tsx b/frontend/src/page/component/panel-mid.tsx new file mode 100644 index 0000000..e1be8a1 --- /dev/null +++ b/frontend/src/page/component/panel-mid.tsx @@ -0,0 +1,29 @@ +import {createUseStyles} from "react-jss"; + +const useStyle = createUseStyles({ + container: { + position: "relative", + overflow: "hidden", + }, + left: { + backgroundColor: "#e3f2fd", + position: "absolute", + width: "100%", + height: "100%", + clipPath: 'polygon(0 0, 100% 0, 0 100%)' + }, + right: { + backgroundColor: "#e8f5e9", + position: "absolute", + width: "100%", + height: "100%", + clipPath: 'polygon(100% 0, 100% 100%, 0 100%)' + }, +}) +export const PanelMid = () => { + const style = useStyle() + return
+
+
+
+}; diff --git a/frontend/src/page/component/panel-right.tsx b/frontend/src/page/component/panel-right.tsx new file mode 100644 index 0000000..b9d350e --- /dev/null +++ b/frontend/src/page/component/panel-right.tsx @@ -0,0 +1,68 @@ +import {createUseStyles} from "react-jss"; +import {UButton} from "../../component/button/u-button.tsx"; +import {useStore} from "../../store/share.ts"; + +const useStyle = createUseStyles({ + container: { + backgroundColor: "#e8f5e9", + display: "flex", + justifyContent: "center", + alignItems: "center", + }, + form: { + backgroundColor: "#BBDEFB", + boxShadow: "inset 0 0 15px rgba(33, 150, 243, 0.15)", + padding: "30px", + borderRadius: "15px", + width: "70%", + margin: "20px 0 20px 60px", + /*todo margin 不用 px*/ + }, + title: { + color: '#1661ab', // 靛青 + }, + code: { + padding: '11px', + margin: '20px 0', + width: '200px', + border: '2px solid #ddd', + borderRadius: '5px', + '&:active': { + border: '2px solid #1661ab', + } + } +}) +export const PanelRight = () => { + const style = useStyle() + const {code, setCode} = useStore() + + function onCodeChange(e: React.ChangeEvent) { + setCode(e.currentTarget.value) + } + + async function onFetchFile() { + const url = `/api/share/fetch?code=${code}` + console.log('[D] onFetchFile: url =', url) + const link = document.createElement('a'); + link.href = url; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + + return
+
+

获取文件

+
+ + 获取文件 +
+
+
+}; diff --git a/frontend/src/page/share.css b/frontend/src/page/share.css deleted file mode 100644 index 553f5b4..0000000 --- a/frontend/src/page/share.css +++ /dev/null @@ -1,15 +0,0 @@ -@import "tailwindcss"; - -.mid-left { - background-color: #e3f2fd; /* 柔和的浅蓝色 */ -} -.mid-right { - background-color: #e8f5e9; /* 柔和的浅绿色 */ -} - -.share-left { - background-color: #e3f2fd; /* 柔和的浅蓝色 */ -} -.share-right { - background-color: #e8f5e9; -} \ No newline at end of file diff --git a/frontend/src/page/share.tsx b/frontend/src/page/share.tsx index 848759c..e971755 100644 --- a/frontend/src/page/share.tsx +++ b/frontend/src/page/share.tsx @@ -1,130 +1,26 @@ -import "./share.css"; -// FileSharing.tsx -import { useRef, useState } from 'react'; +import {createUseStyles} from 'react-jss' +import {PanelLeft} from "./component/panel-left.tsx"; +import {PanelRight} from "./component/panel-right.tsx"; +import {PanelMid} from "./component/panel-mid.tsx"; -type FileItemProps = { - fileName: string; - onClear: () => void; -}; +const useStyle = createUseStyles({ + "@global": { + margin: 0, + padding: 0, + }, + container: { + margin: 0, + height: "100vh", + display: "grid", + gridTemplateColumns: "40% 20% 40%", + }, +}) -const FileItem = ({ fileName, onClear }: FileItemProps) => ( -
- - {fileName} +export const FileSharing = () => { + const style = useStyle() + return
+ + +
-); - -const MiddlePanel = () => ( -
-
-
-
-); - -const UploadPanel = () => { - const [selectedFile, setSelectedFile] = useState(null); - const fileInputRef = useRef(null); - - const handleFileSelect = () => { - if (!selectedFile && fileInputRef.current) { - fileInputRef.current.click(); - } else { - // Handle upload logic - if (selectedFile) { - const formData = new FormData(); - formData.append('file', selectedFile); - - // Replace with actual API call - fetch('https://your-upload-api.com/upload', { - method: 'POST', - body: formData - }) - .then(response => response.json()) - .then(data => { - alert(`Upload success! Code: ${data.code}`); - setSelectedFile(null); - }) - .catch(() => alert('Upload failed')); - } - } - }; - - return ( -
-
-

上传文件

- e.target.files?.[0] && setSelectedFile(e.target.files[0])} - /> - - {selectedFile && ( - setSelectedFile(null)} - /> - )} -
-
- ); -}; - -const DownloadPanel = () => { - const [downloadCode, setDownloadCode] = useState(''); - - const handleDownload = () => { - if (!downloadCode) { - alert('请输入下载码'); - return; - } - // Replace with actual download logic - window.location.href = `https://your-download-api.com/download?code=${downloadCode}`; - }; - - return ( -
-
-

下载文件

- setDownloadCode(e.target.value)} - /> - -
-
- ); -}; - -export const FileSharing = () => ( -
- - - -
-); \ No newline at end of file +}; \ No newline at end of file diff --git a/frontend/src/store/share.ts b/frontend/src/store/share.ts new file mode 100644 index 0000000..e6498c3 --- /dev/null +++ b/frontend/src/store/share.ts @@ -0,0 +1,23 @@ +import {create} from 'zustand' + +type Store = { + file: File | null, + setFile: (f: File | null) => void + code: string, + setCode: (value:string) => void +} + +export const useStore = create()((set) => ({ + file: null, + setFile: (f: File | null = null) => { + set(state => { + return {...state, file: f} + }) + }, + code: '', + setCode: (value:string= '') => { + set(state => { + return {...state, code: value} + }) + } +})) \ No newline at end of file diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index c4069b7..c755c1e 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,8 +1,15 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' // https://vite.dev/config/ export default defineConfig({ - plugins: [react(), tailwindcss()], + plugins: [react()], + server: { + proxy: { + '/api': { + target: 'http://127.0.0.1:9119', + changeOrigin: true + } + } + } }) diff --git a/go.mod b/go.mod index 7267e35..ac3ed9b 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,11 @@ module github.com/loveuer/ushare go 1.24.2 -require github.com/loveuer/nf v0.3.5 +require ( + github.com/loveuer/nf v0.3.5 + github.com/pkg/errors v0.9.1 + github.com/spf13/viper v1.20.1 +) require ( dario.cat/mergo v1.0.0 // indirect @@ -12,24 +16,37 @@ require ( github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.17.0 // indirect + github.com/fsnotify/fsnotify v1.8.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-git/go-git/v5 v5.12.0 // indirect + github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/uuid v1.6.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect + github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/skeema/knownhosts v1.2.2 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.12.0 // indirect + github.com/spf13/cast v1.7.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - golang.org/x/crypto v0.25.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/crypto v0.32.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.27.0 // indirect - golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.22.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.29.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 93b0620..75c8590 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,10 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M= +github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= @@ -34,6 +38,8 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= +github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= +github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -60,6 +66,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -68,26 +76,45 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo= +github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs= +github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4= +github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y= +github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= +github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= +golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= @@ -99,13 +126,13 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -120,15 +147,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -136,8 +163,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/internal/api/api.go b/internal/api/api.go index 42841d3..b5b6b4b 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -5,6 +5,7 @@ import ( "github.com/loveuer/nf" "github.com/loveuer/nf/nft/log" "github.com/loveuer/nf/nft/tool" + "github.com/loveuer/ushare/internal/handler" "github.com/loveuer/ushare/internal/opt" "net" "net/http" @@ -17,6 +18,8 @@ func Start(ctx context.Context) <-chan struct{} { return c.SendStatus(http.StatusOK) }) + app.Get("/api/share/fetch", handler.Fetch()) + ready := make(chan struct{}) ln, err := net.Listen("tcp", opt.Cfg.Address) if err != nil { diff --git a/internal/handler/share.go b/internal/handler/share.go new file mode 100644 index 0000000..b814116 --- /dev/null +++ b/internal/handler/share.go @@ -0,0 +1,42 @@ +package handler + +import ( + "fmt" + "github.com/loveuer/nf" + "github.com/loveuer/ushare/internal/model" + "github.com/loveuer/ushare/internal/opt" + "github.com/pkg/errors" + "github.com/spf13/viper" + "net/http" + "os" +) + +func Fetch() nf.HandlerFunc { + return func(c *nf.Ctx) error { + code := c.Query("code") + info := new(model.Meta) + _, err := os.Stat(opt.MetaPath(code)) + if err != nil { + if errors.Is(err, os.ErrNotExist) { + return c.Status(http.StatusNotFound).JSON(map[string]string{"msg": "文件不存在"}) + } + + return c.SendStatus(http.StatusInternalServerError) + } + + viper.SetConfigFile(opt.MetaPath(code)) + viper.SetConfigType("env") + if err = viper.ReadInConfig(); err != nil { + return c.SendStatus(http.StatusInternalServerError) + } + + if err = viper.Unmarshal(info); err != nil { + return c.SendStatus(http.StatusInternalServerError) + } + + c.SetHeader("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, info.Filename)) + http.ServeFile(c.Writer, c.Request, opt.FilePath(code)) + + return nil + } +} diff --git a/internal/model/meta.go b/internal/model/meta.go new file mode 100644 index 0000000..6a96ef5 --- /dev/null +++ b/internal/model/meta.go @@ -0,0 +1,8 @@ +package model + +type Meta struct { + Filename string `json:"filename" mapstructure:"filename"` + CreatedAt int64 `json:"created_at" mapstructure:"created_at"` + Size int64 `json:"size" mapstructure:"size"` + UploaderIp string `json:"uploader_ip" mapstructure:"uploader_ip"` +} diff --git a/internal/opt/opt.go b/internal/opt/opt.go index cf70c68..1cf532f 100644 --- a/internal/opt/opt.go +++ b/internal/opt/opt.go @@ -1,8 +1,9 @@ package opt type config struct { - Debug bool - Address string + Debug bool + Address string + DataPath string } var ( diff --git a/internal/opt/var.go b/internal/opt/var.go new file mode 100644 index 0000000..2181a7e --- /dev/null +++ b/internal/opt/var.go @@ -0,0 +1,15 @@ +package opt + +import "path/filepath" + +const ( + Meta = ".meta." +) + +func FilePath(code string) string { + return filepath.Join(Cfg.DataPath, code) +} + +func MetaPath(code string) string { + return filepath.Join(Cfg.DataPath, Meta+code) +} diff --git a/main.go b/main.go index 2ce8db6..1fd82a6 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( func init() { flag.BoolVar(&opt.Cfg.Debug, "debug", false, "debug mode") flag.StringVar(&opt.Cfg.Address, "address", "0.0.0.0:80", "") + flag.StringVar(&opt.Cfg.DataPath, "data", "/data", "") flag.Parse() }