mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-23 17:18:32 +02:00
Zoom, better sizes, color picker, sidebar footer
This commit is contained in:
131
package-lock.json
generated
131
package-lock.json
generated
@@ -34,6 +34,7 @@
|
|||||||
"parse-color": "^1.0.0",
|
"parse-color": "^1.0.0",
|
||||||
"parse-json": "^6.0.2",
|
"parse-json": "^6.0.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-color": "^2.19.3",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-helmet-async": "^1.3.0",
|
"react-helmet-async": "^1.3.0",
|
||||||
"react-router-dom": "^6.8.1"
|
"react-router-dom": "^6.8.1"
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
"@types/parse-color": "^1.0.1",
|
"@types/parse-color": "^1.0.1",
|
||||||
"@types/parse-json": "^4.0.0",
|
"@types/parse-json": "^4.0.0",
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.0.15",
|
||||||
|
"@types/react-color": "^3.0.6",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
||||||
"@typescript-eslint/parser": "^5.52.0",
|
"@typescript-eslint/parser": "^5.52.0",
|
||||||
@@ -1049,6 +1051,14 @@
|
|||||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
|
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@icons/material": {
|
||||||
|
"version": "0.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
|
||||||
|
"integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@jridgewell/gen-mapping": {
|
"node_modules/@jridgewell/gen-mapping": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
|
||||||
@@ -2254,6 +2264,16 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-color": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-OzPIO5AyRmLA7PlOyISlgabpYUa3En74LP8mTMa0veCA719SvYQov4WLMsHvCgXP+L+KI9yGhYnqZafVGG0P4w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/reactcss": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/react-dom": {
|
"node_modules/@types/react-dom": {
|
||||||
"version": "18.0.11",
|
"version": "18.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz",
|
||||||
@@ -2263,6 +2283,15 @@
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/reactcss": {
|
||||||
|
"version": "1.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.6.tgz",
|
||||||
|
"integrity": "sha512-qaIzpCuXNWomGR1Xq8SCFTtF4v8V27Y6f+b9+bzHiv087MylI/nTCqqdChNeWS7tslgROmYB7yeiruWX7WnqNg==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/scheduler": {
|
"node_modules/@types/scheduler": {
|
||||||
"version": "0.16.2",
|
"version": "0.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
||||||
@@ -5309,6 +5338,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash-es": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||||
|
},
|
||||||
"node_modules/lodash.merge": {
|
"node_modules/lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
@@ -5356,6 +5390,11 @@
|
|||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/material-colors": {
|
||||||
|
"version": "1.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
|
||||||
|
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
|
||||||
|
},
|
||||||
"node_modules/merge2": {
|
"node_modules/merge2": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||||
@@ -6061,6 +6100,23 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-color": {
|
||||||
|
"version": "2.19.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz",
|
||||||
|
"integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@icons/material": "^0.2.4",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"lodash-es": "^4.17.15",
|
||||||
|
"material-colors": "^1.2.1",
|
||||||
|
"prop-types": "^15.5.10",
|
||||||
|
"reactcss": "^1.2.0",
|
||||||
|
"tinycolor2": "^1.4.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||||
@@ -6220,6 +6276,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||||
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/reactcss": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "^4.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/read-cache": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
@@ -6782,6 +6846,11 @@
|
|||||||
"integrity": "sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==",
|
"integrity": "sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/tinycolor2": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
|
||||||
|
},
|
||||||
"node_modules/tinypool": {
|
"node_modules/tinypool": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.1.tgz",
|
||||||
@@ -8138,6 +8207,12 @@
|
|||||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
|
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@icons/material": {
|
||||||
|
"version": "0.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
|
||||||
|
"integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"@jridgewell/gen-mapping": {
|
"@jridgewell/gen-mapping": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
|
||||||
@@ -9001,6 +9076,16 @@
|
|||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/react-color": {
|
||||||
|
"version": "3.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-color/-/react-color-3.0.6.tgz",
|
||||||
|
"integrity": "sha512-OzPIO5AyRmLA7PlOyISlgabpYUa3En74LP8mTMa0veCA719SvYQov4WLMsHvCgXP+L+KI9yGhYnqZafVGG0P4w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/reactcss": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/react-dom": {
|
"@types/react-dom": {
|
||||||
"version": "18.0.11",
|
"version": "18.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz",
|
||||||
@@ -9010,6 +9095,15 @@
|
|||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/reactcss": {
|
||||||
|
"version": "1.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.6.tgz",
|
||||||
|
"integrity": "sha512-qaIzpCuXNWomGR1Xq8SCFTtF4v8V27Y6f+b9+bzHiv087MylI/nTCqqdChNeWS7tslgROmYB7yeiruWX7WnqNg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/scheduler": {
|
"@types/scheduler": {
|
||||||
"version": "0.16.2",
|
"version": "0.16.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
|
||||||
@@ -11225,6 +11319,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||||
},
|
},
|
||||||
|
"lodash-es": {
|
||||||
|
"version": "4.17.21",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||||
|
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||||
|
},
|
||||||
"lodash.merge": {
|
"lodash.merge": {
|
||||||
"version": "4.6.2",
|
"version": "4.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
@@ -11266,6 +11365,11 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.13"
|
"@jridgewell/sourcemap-codec": "^1.4.13"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"material-colors": {
|
||||||
|
"version": "1.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
|
||||||
|
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
|
||||||
|
},
|
||||||
"merge2": {
|
"merge2": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||||
@@ -11739,6 +11843,20 @@
|
|||||||
"loose-envify": "^1.1.0"
|
"loose-envify": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-color": {
|
||||||
|
"version": "2.19.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz",
|
||||||
|
"integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==",
|
||||||
|
"requires": {
|
||||||
|
"@icons/material": "^0.2.4",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"lodash-es": "^4.17.15",
|
||||||
|
"material-colors": "^1.2.1",
|
||||||
|
"prop-types": "^15.5.10",
|
||||||
|
"reactcss": "^1.2.0",
|
||||||
|
"tinycolor2": "^1.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-dom": {
|
"react-dom": {
|
||||||
"version": "18.2.0",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||||
@@ -11845,6 +11963,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"reactcss": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
|
||||||
|
"requires": {
|
||||||
|
"lodash": "^4.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"read-cache": {
|
"read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
@@ -12259,6 +12385,11 @@
|
|||||||
"integrity": "sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==",
|
"integrity": "sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"tinycolor2": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="
|
||||||
|
},
|
||||||
"tinypool": {
|
"tinypool": {
|
||||||
"version": "0.3.1",
|
"version": "0.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.3.1.tgz",
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
"parse-color": "^1.0.0",
|
"parse-color": "^1.0.0",
|
||||||
"parse-json": "^6.0.2",
|
"parse-json": "^6.0.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-color": "^2.19.3",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-helmet-async": "^1.3.0",
|
"react-helmet-async": "^1.3.0",
|
||||||
"react-router-dom": "^6.8.1"
|
"react-router-dom": "^6.8.1"
|
||||||
@@ -52,6 +53,7 @@
|
|||||||
"@types/parse-color": "^1.0.1",
|
"@types/parse-color": "^1.0.1",
|
||||||
"@types/parse-json": "^4.0.0",
|
"@types/parse-json": "^4.0.0",
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.0.15",
|
||||||
|
"@types/react-color": "^3.0.6",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
"@typescript-eslint/eslint-plugin": "^5.52.0",
|
||||||
"@typescript-eslint/parser": "^5.52.0",
|
"@typescript-eslint/parser": "^5.52.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#![cfg_attr(
|
#![cfg_attr(
|
||||||
all(not(debug_assertions), target_os = "windows"),
|
all(not(debug_assertions), target_os = "windows"),
|
||||||
windows_subsystem = "windows"
|
windows_subsystem = "windows"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
@@ -18,7 +18,7 @@ use sqlx::sqlite::SqlitePoolOptions;
|
|||||||
use sqlx::types::Json;
|
use sqlx::types::Json;
|
||||||
use sqlx::{Pool, Sqlite};
|
use sqlx::{Pool, Sqlite};
|
||||||
use tauri::regex::Regex;
|
use tauri::regex::Regex;
|
||||||
use tauri::{AppHandle, State, Wry};
|
use tauri::{AppHandle, Menu, MenuItem, State, Submenu, Wry};
|
||||||
use tauri::{CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, WindowEvent};
|
use tauri::{CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu, WindowEvent};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
@@ -224,8 +224,8 @@ async fn update_request(
|
|||||||
request.headers.0,
|
request.headers.0,
|
||||||
pool,
|
pool,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to update request");
|
.expect("Failed to update request");
|
||||||
|
|
||||||
app_handle
|
app_handle
|
||||||
.emit_all("updated_request", updated_request)
|
.emit_all("updated_request", updated_request)
|
||||||
@@ -317,12 +317,19 @@ fn greet(name: &str) -> String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// here `"quit".to_string()` defines the menu item id, and the second parameter is the menu item label.
|
|
||||||
let quit = CustomMenuItem::new("quit".to_string(), "Quit");
|
let quit = CustomMenuItem::new("quit".to_string(), "Quit");
|
||||||
let tray_menu = SystemTrayMenu::new().add_item(quit);
|
let tray_menu = SystemTrayMenu::new().add_item(quit);
|
||||||
let system_tray = SystemTray::new().with_menu(tray_menu);
|
let system_tray = SystemTray::new().with_menu(tray_menu);
|
||||||
|
|
||||||
|
let submenu = Submenu::new("View", Menu::new()
|
||||||
|
.add_item(CustomMenuItem::new("zoom_reset".to_string(), "Zoom to Actual Size").accelerator("CmdOrCtrl+0"))
|
||||||
|
.add_item(CustomMenuItem::new("zoom_in".to_string(), "Zoom In").accelerator("CmdOrCtrl+Plus"))
|
||||||
|
.add_item(CustomMenuItem::new("zoom_out".to_string(), "Zoom Out").accelerator("CmdOrCtrl+-")),
|
||||||
|
);
|
||||||
|
let menu = Menu::new().add_native_item(MenuItem::Quit).add_submenu(submenu);
|
||||||
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.menu(menu)
|
||||||
.system_tray(system_tray)
|
.system_tray(system_tray)
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
let win = app.get_window("main").unwrap();
|
let win = app.get_window("main").unwrap();
|
||||||
@@ -360,9 +367,19 @@ fn main() {
|
|||||||
window.hide().unwrap();
|
window.hide().unwrap();
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.on_menu_event(|event| {
|
||||||
|
match event.menu_item_id() {
|
||||||
|
"quit" => std::process::exit(0),
|
||||||
|
"close" => event.window().close().unwrap(),
|
||||||
|
"zoom_reset" => event.window().emit("zoom", 0).unwrap(),
|
||||||
|
"zoom_in" => event.window().emit("zoom", 1).unwrap(),
|
||||||
|
"zoom_out" => event.window().emit("zoom", -1).unwrap(),
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
})
|
||||||
.on_window_event(|e| {
|
.on_window_event(|e| {
|
||||||
let apply_offset = || {
|
let apply_offset = || {
|
||||||
let win = e.window();
|
let win = e.window();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use tauri::{Runtime, Window};
|
use tauri::{Runtime, Window};
|
||||||
|
|
||||||
const TRAFFIC_LIGHT_OFFSET_X: f64 = 15.0;
|
const TRAFFIC_LIGHT_OFFSET_X: f64 = 15.0;
|
||||||
const TRAFFIC_LIGHT_OFFSET_Y: f64 = 18.0;
|
const TRAFFIC_LIGHT_OFFSET_Y: f64 = 22.0;
|
||||||
|
|
||||||
pub trait WindowExt {
|
pub trait WindowExt {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ function App() {
|
|||||||
<div className="grid grid-rows-[auto_1fr] h-full overflow-hidden">
|
<div className="grid grid-rows-[auto_1fr] h-full overflow-hidden">
|
||||||
<HStack
|
<HStack
|
||||||
as={WindowDragRegion}
|
as={WindowDragRegion}
|
||||||
className="px-3 bg-background text-sm text-gray-900 border-b border-b-gray-200 pt-[1px]"
|
className="px-3 bg-background text-gray-900 border-b border-b-gray-200 pt-[1px]"
|
||||||
items="center"
|
alignItems="center"
|
||||||
>
|
>
|
||||||
{request.name}
|
{request.name}
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|||||||
@@ -1,65 +1,57 @@
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import type {
|
import type { ButtonHTMLAttributes, ForwardedRef } from 'react';
|
||||||
ButtonHTMLAttributes,
|
|
||||||
ComponentPropsWithoutRef,
|
|
||||||
ElementType,
|
|
||||||
ForwardedRef,
|
|
||||||
} from 'react';
|
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
import { Icon } from './Icon';
|
import { Icon } from './Icon';
|
||||||
|
|
||||||
const colorStyles = {
|
const colorStyles = {
|
||||||
default: 'hover:bg-gray-700/10 text-gray-700 hover:text-gray-1000',
|
custom: '',
|
||||||
gray: 'text-gray-800 bg-gray-100 hover:bg-gray-500/20 hover:text-gray-1000',
|
default: 'text-gray-700 enabled:hover:bg-gray-700/10 enabled:hover:text-gray-1000',
|
||||||
primary: 'bg-blue-400 text-white',
|
gray: 'text-gray-800 bg-gray-100 enabled:hover:bg-gray-500/20 enabled:hover:text-gray-1000',
|
||||||
secondary: 'bg-violet-400 text-white',
|
primary: 'bg-blue-400 text-white hover:bg-blue-500',
|
||||||
warning: 'bg-orange-400 text-white',
|
secondary: 'bg-violet-400 text-white hover:bg-violet-500',
|
||||||
danger: 'bg-red-400 text-white',
|
warning: 'bg-orange-400 text-white hover:bg-orange-500',
|
||||||
|
danger: 'bg-red-400 text-white hover:bg-red-500',
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ButtonProps<T extends ElementType> = ButtonHTMLAttributes<HTMLButtonElement> & {
|
export type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||||
color?: keyof typeof colorStyles;
|
color?: keyof typeof colorStyles;
|
||||||
size?: 'xs' | 'sm' | 'md';
|
size?: 'sm' | 'md';
|
||||||
justify?: 'start' | 'center';
|
justify?: 'start' | 'center';
|
||||||
forDropdown?: boolean;
|
forDropdown?: boolean;
|
||||||
as?: T;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Button = forwardRef(function Button<T extends ElementType>(
|
export const Button = forwardRef(function Button(
|
||||||
{
|
{
|
||||||
className,
|
className,
|
||||||
as,
|
|
||||||
justify = 'center',
|
|
||||||
children,
|
children,
|
||||||
size = 'md',
|
|
||||||
forDropdown,
|
forDropdown,
|
||||||
color,
|
color,
|
||||||
|
justify = 'center',
|
||||||
|
size = 'md',
|
||||||
|
type = 'button',
|
||||||
...props
|
...props
|
||||||
}: ButtonProps<T> & Omit<ComponentPropsWithoutRef<T>, keyof ButtonProps<T>>,
|
}: ButtonProps,
|
||||||
ref: ForwardedRef<HTMLButtonElement>,
|
ref: ForwardedRef<HTMLButtonElement>,
|
||||||
) {
|
) {
|
||||||
const Component = as || 'button';
|
|
||||||
return (
|
return (
|
||||||
<Component
|
<button
|
||||||
ref={ref}
|
ref={ref}
|
||||||
type="button"
|
type={type}
|
||||||
className={classnames(
|
className={classnames(
|
||||||
className,
|
className,
|
||||||
'outline-none',
|
'outline-none',
|
||||||
'border border-transparent focus-visible:border-blue-300',
|
'border border-transparent focus-visible:border-blue-300',
|
||||||
'transition-all rounded-md flex items-center',
|
'transition-all rounded-md flex items-center',
|
||||||
'bg-opacity-90 hover:bg-opacity-100',
|
|
||||||
colorStyles[color || 'default'],
|
colorStyles[color || 'default'],
|
||||||
justify === 'start' && 'justify-start',
|
justify === 'start' && 'justify-start',
|
||||||
justify === 'center' && 'justify-center',
|
justify === 'center' && 'justify-center',
|
||||||
size === 'md' && 'h-10 px-4',
|
size === 'md' && 'h-9 px-3',
|
||||||
size === 'sm' && 'h-8 px-3 text-sm',
|
size === 'sm' && 'h-7 px-2.5 text-sm',
|
||||||
size === 'xs' && 'h-7 px-2.5 text-sm',
|
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
{forDropdown && <Icon icon="triangleDown" className="ml-1 -mr-1" />}
|
{forDropdown && <Icon icon="triangleDown" className="ml-1 -mr-1" />}
|
||||||
</Component>
|
</button>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,25 @@
|
|||||||
|
import classnames from 'classnames';
|
||||||
import type { LinkProps } from 'react-router-dom';
|
import type { LinkProps } from 'react-router-dom';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import type { ButtonProps } from './Button';
|
import type { ButtonProps } from './Button';
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
|
|
||||||
type Props = ButtonProps<typeof Link> & LinkProps;
|
type Props = ButtonProps & LinkProps;
|
||||||
|
|
||||||
export function ButtonLink({ ...props }: Props) {
|
export function ButtonLink({
|
||||||
return <Button as={Link} {...props} />;
|
reloadDocument,
|
||||||
|
replace,
|
||||||
|
state,
|
||||||
|
preventScrollReset,
|
||||||
|
relative,
|
||||||
|
to,
|
||||||
|
className,
|
||||||
|
...buttonProps
|
||||||
|
}: Props) {
|
||||||
|
const linkProps = { reloadDocument, replace, state, preventScrollReset, relative, to };
|
||||||
|
return (
|
||||||
|
<Link {...linkProps}>
|
||||||
|
<Button className={classnames(className, 'w-full')} {...buttonProps} />
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export function Dialog({
|
|||||||
<IconButton aria-label="Close" icon="x" size="sm" />
|
<IconButton aria-label="Close" icon="x" size="sm" />
|
||||||
</D.Close>
|
</D.Close>
|
||||||
<VStack space={3}>
|
<VStack space={3}>
|
||||||
<HStack items="center" className="pb-3">
|
<HStack alignItems="center" className="pb-3">
|
||||||
<D.Title className="text-xl font-semibold">{title}</D.Title>
|
<D.Title className="text-xl font-semibold">{title}</D.Title>
|
||||||
</HStack>
|
</HStack>
|
||||||
{description && <D.Description>{description}</D.Description>}
|
{description && <D.Description>{description}</D.Description>}
|
||||||
|
|||||||
@@ -25,19 +25,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cm-gutters {
|
.cm-gutters {
|
||||||
@apply border-0 text-gray-500 text-opacity-30;
|
@apply border-0 text-gray-500/60;
|
||||||
|
|
||||||
.cm-gutterElement {
|
.cm-gutterElement {
|
||||||
@apply cursor-default;
|
@apply cursor-default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.cm-focused .cm-gutters {
|
|
||||||
@apply text-opacity-60;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder-widget {
|
.placeholder-widget {
|
||||||
@apply text-[0.9em] text-gray-800 dark:text-gray-1000 px-1 rounded cursor-default dark:shadow;
|
@apply text-[0.9em] text-gray-800 dark:text-gray-900 px-1 rounded cursor-default dark:shadow;
|
||||||
|
|
||||||
/* NOTE: Background and border are translucent so we can see text selection through it */
|
/* NOTE: Background and border are translucent so we can see text selection through it */
|
||||||
@apply bg-gray-300/40 border border-gray-300 border-opacity-40 hover:border-opacity-80;
|
@apply bg-gray-300/40 border border-gray-300 border-opacity-40 hover:border-opacity-80;
|
||||||
@@ -105,11 +101,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .fold-gutter-icon:hover {
|
.cm-editor .fold-gutter-icon:hover {
|
||||||
@apply text-gray-400 bg-gray-100/20;
|
@apply text-gray-900 bg-gray-300/50;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .cm-foldPlaceholder {
|
.cm-editor .cm-foldPlaceholder {
|
||||||
@apply px-2 border border-gray-200 bg-gray-100;
|
@apply px-2 border border-gray-400/50 bg-gray-300/50 cursor-default;
|
||||||
|
@apply hover:text-gray-800 hover:border-gray-400;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-editor .cm-activeLineGutter,
|
.cm-editor .cm-activeLineGutter,
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ import {
|
|||||||
} from '@codemirror/view';
|
} from '@codemirror/view';
|
||||||
import { tags as t } from '@lezer/highlight';
|
import { tags as t } from '@lezer/highlight';
|
||||||
import { debouncedAutocompletionDisplay } from './autocomplete';
|
import { debouncedAutocompletionDisplay } from './autocomplete';
|
||||||
import { readOnlyTransactionFilter } from './readOnlyTransactionFilter';
|
|
||||||
import { twig } from './twig/extension';
|
import { twig } from './twig/extension';
|
||||||
import { url } from './url/extension';
|
import { url } from './url/extension';
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ function FormRow({
|
|||||||
defaultValue={value}
|
defaultValue={value}
|
||||||
onChange={onChangeValue}
|
onChange={onChangeValue}
|
||||||
/>
|
/>
|
||||||
{onDelete && <IconButton size="sm" icon="trash" onClick={onDelete} />}
|
{onDelete && <IconButton icon="trash" onClick={onDelete} />}
|
||||||
</HStack>
|
</HStack>
|
||||||
{addSubmit && <input type="submit" value="Add" className="sr-only" />}
|
{addSubmit && <input type="submit" value="Add" className="sr-only" />}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ import {
|
|||||||
CheckIcon,
|
CheckIcon,
|
||||||
ClockIcon,
|
ClockIcon,
|
||||||
CodeIcon,
|
CodeIcon,
|
||||||
|
ColorWheelIcon,
|
||||||
Cross2Icon,
|
Cross2Icon,
|
||||||
EyeOpenIcon,
|
EyeOpenIcon,
|
||||||
GearIcon,
|
GearIcon,
|
||||||
HomeIcon,
|
HomeIcon,
|
||||||
MoonIcon,
|
MoonIcon,
|
||||||
|
ListBulletIcon,
|
||||||
PaperPlaneIcon,
|
PaperPlaneIcon,
|
||||||
PlusCircledIcon,
|
PlusCircledIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
@@ -19,59 +21,40 @@ import {
|
|||||||
TriangleLeftIcon,
|
TriangleLeftIcon,
|
||||||
TriangleRightIcon,
|
TriangleRightIcon,
|
||||||
UpdateIcon,
|
UpdateIcon,
|
||||||
|
RowsIcon,
|
||||||
} from '@radix-ui/react-icons';
|
} from '@radix-ui/react-icons';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import type { NamedExoticComponent } from 'react';
|
|
||||||
|
|
||||||
type IconName =
|
const icons = {
|
||||||
| 'archive'
|
|
||||||
| 'home'
|
|
||||||
| 'camera'
|
|
||||||
| 'gear'
|
|
||||||
| 'eye'
|
|
||||||
| 'triangleDown'
|
|
||||||
| 'triangleLeft'
|
|
||||||
| 'triangleRight'
|
|
||||||
| 'paperPlane'
|
|
||||||
| 'update'
|
|
||||||
| 'question'
|
|
||||||
| 'check'
|
|
||||||
| 'plus'
|
|
||||||
| 'plusCircle'
|
|
||||||
| 'clock'
|
|
||||||
| 'sun'
|
|
||||||
| 'code'
|
|
||||||
| 'x'
|
|
||||||
| 'trash'
|
|
||||||
| 'moon';
|
|
||||||
|
|
||||||
const icons: Record<IconName, NamedExoticComponent<{ className: string }>> = {
|
|
||||||
paperPlane: PaperPlaneIcon,
|
|
||||||
triangleDown: TriangleDownIcon,
|
|
||||||
plus: PlusIcon,
|
|
||||||
plusCircle: PlusCircledIcon,
|
|
||||||
clock: ClockIcon,
|
|
||||||
archive: ArchiveIcon,
|
archive: ArchiveIcon,
|
||||||
camera: CameraIcon,
|
camera: CameraIcon,
|
||||||
check: CheckIcon,
|
check: CheckIcon,
|
||||||
triangleLeft: TriangleLeftIcon,
|
clock: ClockIcon,
|
||||||
triangleRight: TriangleRightIcon,
|
code: CodeIcon,
|
||||||
|
colorWheel: ColorWheelIcon,
|
||||||
|
eye: EyeOpenIcon,
|
||||||
gear: GearIcon,
|
gear: GearIcon,
|
||||||
home: HomeIcon,
|
home: HomeIcon,
|
||||||
update: UpdateIcon,
|
listBullet: ListBulletIcon,
|
||||||
sun: SunIcon,
|
|
||||||
moon: MoonIcon,
|
moon: MoonIcon,
|
||||||
x: Cross2Icon,
|
paperPlane: PaperPlaneIcon,
|
||||||
|
plus: PlusIcon,
|
||||||
|
plusCircle: PlusCircledIcon,
|
||||||
question: QuestionMarkIcon,
|
question: QuestionMarkIcon,
|
||||||
eye: EyeOpenIcon,
|
rows: RowsIcon,
|
||||||
code: CodeIcon,
|
sun: SunIcon,
|
||||||
trash: TrashIcon,
|
trash: TrashIcon,
|
||||||
|
triangleDown: TriangleDownIcon,
|
||||||
|
triangleLeft: TriangleLeftIcon,
|
||||||
|
triangleRight: TriangleRightIcon,
|
||||||
|
update: UpdateIcon,
|
||||||
|
x: Cross2Icon,
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IconProps {
|
export interface IconProps {
|
||||||
icon: IconName;
|
icon: keyof typeof icons;
|
||||||
className?: string;
|
className?: string;
|
||||||
size?: 'md';
|
size?: 'xs' | 'sm' | 'md';
|
||||||
spin?: boolean;
|
spin?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +66,8 @@ export function Icon({ icon, spin, size = 'md', className }: IconProps) {
|
|||||||
className,
|
className,
|
||||||
'text-gray-800',
|
'text-gray-800',
|
||||||
size === 'md' && 'h-4 w-4',
|
size === 'md' && 'h-4 w-4',
|
||||||
|
size === 'sm' && 'h-3 w-3',
|
||||||
|
size === 'xs' && 'h-2 w-2',
|
||||||
spin && 'animate-spin',
|
spin && 'animate-spin',
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,22 +1,20 @@
|
|||||||
|
import classnames from 'classnames';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
import type { IconProps } from './Icon';
|
|
||||||
import { Icon } from './Icon';
|
|
||||||
import type { ButtonProps } from './Button';
|
import type { ButtonProps } from './Button';
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
import classnames from 'classnames';
|
import type { IconProps } from './Icon';
|
||||||
|
import { Icon } from './Icon';
|
||||||
|
|
||||||
type Props = Omit<IconProps, 'size'> &
|
type Props = IconProps & ButtonProps & { iconClassName?: string; iconSize?: IconProps['size'] };
|
||||||
ButtonProps<typeof Button> & {
|
|
||||||
iconClassName?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const IconButton = forwardRef<HTMLButtonElement, Props>(function IconButton(
|
export const IconButton = forwardRef<HTMLButtonElement, Props>(function IconButton(
|
||||||
{ icon, spin, className, iconClassName, ...props }: Props,
|
{ icon, spin, className, iconClassName, size, iconSize, ...props }: Props,
|
||||||
ref,
|
ref,
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<Button ref={ref} className={classnames(className, 'group')} {...props}>
|
<Button ref={ref} className={classnames(className, 'group')} size={size} {...props}>
|
||||||
<Icon
|
<Icon
|
||||||
|
size={iconSize}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
spin={spin}
|
spin={spin}
|
||||||
className={classnames(
|
className={classnames(
|
||||||
|
|||||||
@@ -59,13 +59,13 @@ export function Input({
|
|||||||
{label}
|
{label}
|
||||||
</label>
|
</label>
|
||||||
<HStack
|
<HStack
|
||||||
items="center"
|
alignItems="center"
|
||||||
className={classnames(
|
className={classnames(
|
||||||
containerClassName,
|
containerClassName,
|
||||||
'relative w-full rounded-md text-gray-900',
|
'relative w-full rounded-md text-gray-900',
|
||||||
'border border-gray-200 focus-within:border-blue-400/40',
|
'border border-gray-200 focus-within:border-blue-400/40',
|
||||||
size === 'md' && 'h-10',
|
size === 'md' && 'h-9',
|
||||||
size === 'sm' && 'h-8',
|
size === 'sm' && 'h-7',
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{leftSlot}
|
{leftSlot}
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ export function RequestPane({ fullHeight, request, className }: Props) {
|
|||||||
{['JSON', 'Params', 'Headers', 'Auth'].map((label, i) => (
|
{['JSON', 'Params', 'Headers', 'Auth'].map((label, i) => (
|
||||||
<Button
|
<Button
|
||||||
key={label}
|
key={label}
|
||||||
size="xs"
|
size="sm"
|
||||||
color={i === 0 && 'gray'}
|
color={i === 0 ? 'gray' : undefined}
|
||||||
className={i !== 0 && 'opacity-80 hover:opacity-100'}
|
className={i !== 0 ? 'opacity-80 hover:opacity-100' : undefined}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export function ResponsePane({ requestId, className }: Props) {
|
|||||||
{response && (
|
{response && (
|
||||||
<>
|
<>
|
||||||
<HStack
|
<HStack
|
||||||
items="center"
|
alignItems="center"
|
||||||
className="italic text-gray-600 text-sm w-full mb-1 flex-shrink-0 pl-2"
|
className="italic text-gray-600 text-sm w-full mb-1 flex-shrink-0 pl-2"
|
||||||
>
|
>
|
||||||
{response.status > 0 && (
|
{response.status > 0 && (
|
||||||
@@ -76,7 +76,7 @@ export function ResponsePane({ requestId, className }: Props) {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<HStack items="center" className="ml-auto h-8">
|
<HStack alignItems="center" className="ml-auto h-8">
|
||||||
{contentType.includes('html') && (
|
{contentType.includes('html') && (
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={viewMode === 'pretty' ? 'eye' : 'code'}
|
icon={viewMode === 'pretty' ? 'eye' : 'code'}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import type { HTMLAttributes } from 'react';
|
import type { HTMLAttributes } from 'react';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { SketchPicker } from 'react-color';
|
||||||
import { useRequestCreate } from '../hooks/useRequest';
|
import { useRequestCreate } from '../hooks/useRequest';
|
||||||
import useTheme from '../hooks/useTheme';
|
import useTheme from '../hooks/useTheme';
|
||||||
import type { HttpRequest } from '../lib/models';
|
import type { HttpRequest } from '../lib/models';
|
||||||
import { Button } from './Button';
|
import { Button } from './Button';
|
||||||
|
import { ButtonLink } from './ButtonLink';
|
||||||
import { Dialog } from './Dialog';
|
import { Dialog } from './Dialog';
|
||||||
import { HeaderEditor } from './HeaderEditor';
|
import { HeaderEditor } from './HeaderEditor';
|
||||||
import { IconButton } from './IconButton';
|
import { IconButton } from './IconButton';
|
||||||
@@ -20,28 +21,27 @@ interface Props extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
|
|||||||
|
|
||||||
export function Sidebar({ className, activeRequestId, workspaceId, requests, ...props }: Props) {
|
export function Sidebar({ className, activeRequestId, workspaceId, requests, ...props }: Props) {
|
||||||
const createRequest = useRequestCreate({ workspaceId, navigateAfter: true });
|
const createRequest = useRequestCreate({ workspaceId, navigateAfter: true });
|
||||||
const { appearance, toggleAppearance } = useTheme();
|
const { appearance, toggleAppearance, forceSetTheme } = useTheme();
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
|
const [color, setColor] = useState<string>('blue');
|
||||||
|
const [showPicker, setShowPicker] = useState<boolean>(false);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames(className, 'w-52 bg-gray-100 h-full border-r border-gray-200')}
|
className={classnames(
|
||||||
|
className,
|
||||||
|
'min-w-[10rem] bg-gray-100 h-full border-r border-gray-200 relative',
|
||||||
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<HStack as={WindowDragRegion} items="center" justify="end">
|
<HStack as={WindowDragRegion} alignItems="center" justifyContent="end">
|
||||||
<Dialog wide open={open} onOpenChange={setOpen} title="Edit Headers">
|
<Dialog wide open={open} onOpenChange={setOpen} title="Edit Headers">
|
||||||
<HeaderEditor />
|
<HeaderEditor />
|
||||||
<Button className="ml-auto mt-5" color="primary" onClick={() => setOpen(false)}>
|
<Button className="ml-auto mt-5" color="primary" onClick={() => setOpen(false)}>
|
||||||
Save
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<IconButton size="sm" icon="camera" onClick={() => setOpen(true)} />
|
|
||||||
<IconButton
|
<IconButton
|
||||||
size="sm"
|
className="mx-1"
|
||||||
icon={appearance === 'dark' ? 'moon' : 'sun'}
|
|
||||||
onClick={toggleAppearance}
|
|
||||||
/>
|
|
||||||
<IconButton
|
|
||||||
size="sm"
|
|
||||||
icon="plusCircle"
|
icon="plusCircle"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await createRequest.mutate({ name: 'Test Request' });
|
await createRequest.mutate({ name: 'Test Request' });
|
||||||
@@ -53,6 +53,27 @@ export function Sidebar({ className, activeRequestId, workspaceId, requests, ...
|
|||||||
<SidebarItem key={r.id} request={r} active={r.id === activeRequestId} />
|
<SidebarItem key={r.id} request={r} active={r.id === activeRequestId} />
|
||||||
))}
|
))}
|
||||||
{/*<Colors />*/}
|
{/*<Colors />*/}
|
||||||
|
|
||||||
|
<HStack
|
||||||
|
className="absolute bottom-1 left-1 right-0 mx-1"
|
||||||
|
alignItems="center"
|
||||||
|
justifyContent="end"
|
||||||
|
>
|
||||||
|
<IconButton icon="colorWheel" onClick={() => setShowPicker((p) => !p)} />
|
||||||
|
<IconButton icon={appearance === 'dark' ? 'moon' : 'sun'} onClick={toggleAppearance} />
|
||||||
|
<IconButton icon="rows" onClick={() => setOpen(true)} />
|
||||||
|
</HStack>
|
||||||
|
|
||||||
|
{showPicker && (
|
||||||
|
<SketchPicker
|
||||||
|
className="fixed z-10 bottom-2 right-2"
|
||||||
|
color={color}
|
||||||
|
onChange={(c) => {
|
||||||
|
setColor(c.hex);
|
||||||
|
forceSetTheme(c.hex);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -61,15 +82,16 @@ export function Sidebar({ className, activeRequestId, workspaceId, requests, ...
|
|||||||
function SidebarItem({ request, active }: { request: HttpRequest; active: boolean }) {
|
function SidebarItem({ request, active }: { request: HttpRequest; active: boolean }) {
|
||||||
return (
|
return (
|
||||||
<li key={request.id}>
|
<li key={request.id}>
|
||||||
<Button
|
<ButtonLink
|
||||||
as={Link}
|
color="custom"
|
||||||
to={`/workspaces/${request.workspaceId}/requests/${request.id}`}
|
to={`/workspaces/${request.workspaceId}/requests/${request.id}`}
|
||||||
className={classnames('w-full', active ? 'bg-gray-200/70 text-gray-900' : 'text-gray-500')}
|
disabled={active}
|
||||||
size="xs"
|
className={classnames('w-full', active ? 'bg-gray-200/70 text-gray-900' : 'text-gray-600')}
|
||||||
|
size="sm"
|
||||||
justify="start"
|
justify="start"
|
||||||
>
|
>
|
||||||
{request.name || request.url}
|
{request.name || request.url}
|
||||||
</Button>
|
</ButtonLink>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { HTMLAttributes, ReactNode } from 'react';
|
|
||||||
import React, { Children, Fragment } from 'react';
|
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import type { ReactNode } from 'react';
|
||||||
|
import React, { Children, Fragment } from 'react';
|
||||||
|
|
||||||
const spaceClassesX = {
|
const spaceClassesX = {
|
||||||
0: 'pr-0',
|
0: 'pr-0',
|
||||||
@@ -78,26 +78,35 @@ export function VStack({ className, space, children, ...props }: VStackProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BaseStackProps extends HTMLAttributes<HTMLElement> {
|
interface BaseStackProps {
|
||||||
items?: 'start' | 'center';
|
|
||||||
justify?: 'start' | 'center' | 'end';
|
|
||||||
as?: React.ElementType;
|
as?: React.ElementType;
|
||||||
|
alignItems?: 'start' | 'center';
|
||||||
|
justifyContent?: 'start' | 'center' | 'end';
|
||||||
|
className?: string;
|
||||||
|
children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function BaseStack({ className, items, justify, as = 'div', ...props }: BaseStackProps) {
|
function BaseStack({
|
||||||
|
className,
|
||||||
|
alignItems,
|
||||||
|
justifyContent,
|
||||||
|
children,
|
||||||
|
as = 'div',
|
||||||
|
}: BaseStackProps) {
|
||||||
const Component = as;
|
const Component = as;
|
||||||
return (
|
return (
|
||||||
<Component
|
<Component
|
||||||
className={classnames(
|
className={classnames(
|
||||||
className,
|
className,
|
||||||
'flex flex-grow-0',
|
'flex flex-grow-0',
|
||||||
items === 'center' && 'items-center',
|
alignItems === 'center' && 'items-center',
|
||||||
items === 'start' && 'items-start',
|
alignItems === 'start' && 'items-start',
|
||||||
justify === 'start' && 'justify-start',
|
justifyContent === 'start' && 'justify-start',
|
||||||
justify === 'center' && 'justify-center',
|
justifyContent === 'center' && 'justify-center',
|
||||||
justify === 'end' && 'justify-end',
|
justifyContent === 'end' && 'justify-end',
|
||||||
)}
|
)}
|
||||||
{...props}
|
>
|
||||||
/>
|
{children}
|
||||||
|
</Component>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { DropdownMenuRadio } from './Dropdown';
|
|
||||||
import { Button } from './Button';
|
|
||||||
import { Input } from './Input';
|
|
||||||
import type { FormEvent } from 'react';
|
import type { FormEvent } from 'react';
|
||||||
|
import { Button } from './Button';
|
||||||
|
import { DropdownMenuRadio } from './Dropdown';
|
||||||
import { IconButton } from './IconButton';
|
import { IconButton } from './IconButton';
|
||||||
|
import { Input } from './Input';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
sendRequest: () => void;
|
sendRequest: () => void;
|
||||||
@@ -24,7 +24,6 @@ export function UrlBar({ sendRequest, loading, onMethodChange, method, onUrlChan
|
|||||||
<Input
|
<Input
|
||||||
hideLabel
|
hideLabel
|
||||||
useEditor={{ useTemplating: true, contentType: 'url' }}
|
useEditor={{ useTemplating: true, contentType: 'url' }}
|
||||||
size="sm"
|
|
||||||
className="font-mono px-0"
|
className="font-mono px-0"
|
||||||
name="url"
|
name="url"
|
||||||
label="Enter URL"
|
label="Enter URL"
|
||||||
@@ -46,7 +45,7 @@ export function UrlBar({ sendRequest, loading, onMethodChange, method, onUrlChan
|
|||||||
{ label: 'HEAD', value: 'HEAD' },
|
{ label: 'HEAD', value: 'HEAD' },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Button type="button" disabled={loading} size="xs" className="mx-0.5" justify="start">
|
<Button type="button" disabled={loading} size="sm" className="mx-0.5" justify="start">
|
||||||
{method.toUpperCase()}
|
{method.toUpperCase()}
|
||||||
</Button>
|
</Button>
|
||||||
</DropdownMenuRadio>
|
</DropdownMenuRadio>
|
||||||
@@ -55,7 +54,7 @@ export function UrlBar({ sendRequest, loading, onMethodChange, method, onUrlChan
|
|||||||
<IconButton
|
<IconButton
|
||||||
type="submit"
|
type="submit"
|
||||||
className="mr-0.5"
|
className="mr-0.5"
|
||||||
size="xs"
|
size="sm"
|
||||||
icon={loading ? 'update' : 'paperPlane'}
|
icon={loading ? 'update' : 'paperPlane'}
|
||||||
spin={loading}
|
spin={loading}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export function WindowDragRegion({ className, ...props }: Props) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
data-tauri-drag-region
|
data-tauri-drag-region
|
||||||
className={classnames(className, 'w-full h-10 flex-shrink-0')}
|
className={classnames(className, 'w-full h-12 flex-shrink-0')}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { debounce } from 'lodash';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import type { Appearance } from '../lib/theme/window';
|
import type { Appearance } from '../lib/theme/window';
|
||||||
import {
|
import {
|
||||||
@@ -10,13 +11,17 @@ import {
|
|||||||
|
|
||||||
const appearanceQueryKey = ['theme', 'appearance'];
|
const appearanceQueryKey = ['theme', 'appearance'];
|
||||||
|
|
||||||
|
const forceSetTheme = debounce((gray: string) => {
|
||||||
|
setAppearance(getAppearance(), gray);
|
||||||
|
}, 200);
|
||||||
|
|
||||||
export default function useTheme() {
|
export default function useTheme() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const appearance = useQuery({
|
const appearance = useQuery({
|
||||||
queryKey: appearanceQueryKey,
|
queryKey: appearanceQueryKey,
|
||||||
queryFn: getAppearance,
|
queryFn: getAppearance,
|
||||||
initialData: getAppearance(),
|
initialData: getAppearance(),
|
||||||
});
|
}).data;
|
||||||
|
|
||||||
const themeChange = (appearance: Appearance) => {
|
const themeChange = (appearance: Appearance) => {
|
||||||
setAppearance(appearance);
|
setAppearance(appearance);
|
||||||
@@ -32,7 +37,8 @@ export default function useTheme() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
appearance: appearance.data,
|
appearance,
|
||||||
|
forceSetTheme,
|
||||||
toggleAppearance: handleToggleAppearance,
|
toggleAppearance: handleToggleAppearance,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
1
src-web/lib/constants.ts
Normal file
1
src-web/lib/constants.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export const DEFAULT_FONT_SIZE = 16;
|
||||||
@@ -28,7 +28,7 @@ const lightTheme: AppTheme = {
|
|||||||
appearance: 'light',
|
appearance: 'light',
|
||||||
layers: {
|
layers: {
|
||||||
root: {
|
root: {
|
||||||
whitePoint: 0.98,
|
whitePoint: 0.95,
|
||||||
colors: {
|
colors: {
|
||||||
gray: '#7f8fb0',
|
gray: '#7f8fb0',
|
||||||
red: '#da4545',
|
red: '#da4545',
|
||||||
@@ -59,9 +59,15 @@ export function toggleAppearance(): Appearance {
|
|||||||
return newAppearance;
|
return newAppearance;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setAppearance(a?: Appearance) {
|
export function setAppearance(a?: Appearance, gray?: string) {
|
||||||
const appearance = a ?? getPreferredAppearance();
|
const appearance = a ?? getPreferredAppearance();
|
||||||
const theme = appearance === 'dark' ? darkTheme : lightTheme;
|
const theme = appearance === 'dark' ? darkTheme : lightTheme;
|
||||||
|
|
||||||
|
// Hack to update the gray color for a demo
|
||||||
|
if (theme.layers.root && gray) {
|
||||||
|
theme.layers.root.colors.gray = gray;
|
||||||
|
}
|
||||||
|
|
||||||
document.documentElement.setAttribute('data-appearance', appearance);
|
document.documentElement.setAttribute('data-appearance', appearance);
|
||||||
document.documentElement.setAttribute('data-theme', theme.name);
|
document.documentElement.setAttribute('data-theme', theme.name);
|
||||||
|
|
||||||
|
|||||||
@@ -2,49 +2,30 @@
|
|||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
:root {
|
|
||||||
color-scheme: light dark;
|
|
||||||
--transition-duration: 100ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
:not(input):not(textarea),
|
|
||||||
:not(input):not(textarea)::after,
|
|
||||||
:not(input):not(textarea)::before {
|
|
||||||
-webkit-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
html, body, #root {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
/* Default colors */
|
|
||||||
background-color: hsl(var(--color-background));
|
|
||||||
color: hsl(var(--color-gray-900));
|
|
||||||
}
|
|
||||||
|
|
||||||
* {
|
|
||||||
transition: background-color var(--transition-duration),
|
|
||||||
border-color var(--transition-duration),
|
|
||||||
box-shadow var(--transition-duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*.hide-scrollbar {*/
|
|
||||||
/* &::-webkit-scrollbar-corner,*/
|
|
||||||
/* &::-webkit-scrollbar {*/
|
|
||||||
/* @apply w-[5px] h-[5px];*/
|
|
||||||
/* background-color: transparent; !* or add it to the track *!*/
|
|
||||||
/* }*/
|
|
||||||
|
|
||||||
/* &::-webkit-scrollbar-thumb {*/
|
|
||||||
/* @apply bg-gray-100 bg-opacity-20 rounded-full;*/
|
|
||||||
/* }*/
|
|
||||||
/*}*/
|
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
|
html, body, #root {
|
||||||
|
@apply w-full h-full overflow-hidden bg-gray-50 text-gray-900;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup default transitions for elements */
|
||||||
|
* {
|
||||||
|
transition: background-color var(--transition-duration),
|
||||||
|
border-color var(--transition-duration),
|
||||||
|
box-shadow var(--transition-duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable user selection to make it more "app-like" */
|
||||||
|
:not(input):not(textarea),
|
||||||
|
:not(input):not(textarea)::after,
|
||||||
|
:not(input):not(textarea)::before {
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
color-scheme: light dark;
|
||||||
|
--transition-duration: 100ms ease-in-out;
|
||||||
--color-white: 255 100% 100%;
|
--color-white: 255 100% 100%;
|
||||||
--color-black: 255 0% 0%;
|
--color-black: 255 0% 0%;
|
||||||
--color-background: var(--color-gray-50);
|
--color-background: var(--color-gray-50);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { Layout } from './components/Layout';
|
|||||||
import { RouterError } from './components/RouterError';
|
import { RouterError } from './components/RouterError';
|
||||||
import { requestsQueryKey } from './hooks/useRequest';
|
import { requestsQueryKey } from './hooks/useRequest';
|
||||||
import { responsesQueryKey } from './hooks/useResponses';
|
import { responsesQueryKey } from './hooks/useResponses';
|
||||||
|
import { DEFAULT_FONT_SIZE } from './lib/constants';
|
||||||
import type { HttpRequest, HttpResponse } from './lib/models';
|
import type { HttpRequest, HttpResponse } from './lib/models';
|
||||||
import { convertDates } from './lib/models';
|
import { convertDates } from './lib/models';
|
||||||
import { setAppearance } from './lib/theme/window';
|
import { setAppearance } from './lib/theme/window';
|
||||||
@@ -75,6 +76,21 @@ await listen('updated_response', ({ payload: response }: { payload: HttpResponse
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await listen('zoom', ({ payload: zoomDelta }: { payload: number }) => {
|
||||||
|
const fontSize = parseFloat(window.getComputedStyle(document.documentElement).fontSize);
|
||||||
|
|
||||||
|
let newFontSize;
|
||||||
|
if (zoomDelta === 0) {
|
||||||
|
newFontSize = DEFAULT_FONT_SIZE;
|
||||||
|
} else if (zoomDelta > 0) {
|
||||||
|
newFontSize = Math.min(fontSize * 1.1, DEFAULT_FONT_SIZE * 5);
|
||||||
|
} else if (zoomDelta < 0) {
|
||||||
|
newFontSize = Math.max(fontSize * 0.9, DEFAULT_FONT_SIZE * 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.documentElement.style.fontSize = `${newFontSize}px`;
|
||||||
|
});
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
|
|||||||
@@ -1,56 +1,65 @@
|
|||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import("tailwindcss").Config} */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
darkMode: ['class', '[data-appearance="dark"]'],
|
darkMode: ["class", "[data-appearance=\"dark\"]"],
|
||||||
content: [
|
content: [
|
||||||
"./index.html",
|
"./index.html",
|
||||||
"./src-web/**/*.{html,tsx}",
|
"./src-web/**/*.{html,tsx}"
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
'mono': ['JetBrains Mono', "Menlo", 'monospace'],
|
"mono": ["JetBrains Mono", "Menlo", "monospace"]
|
||||||
},
|
|
||||||
borderRadius: {
|
|
||||||
none: '0px',
|
|
||||||
sm: 'var(--border-radius-sm)',
|
|
||||||
DEFAULT: 'var(--border-radius)',
|
|
||||||
md: 'var(--border-radius-md)',
|
|
||||||
lg: 'var(--border-radius-lg)',
|
|
||||||
full: '9999px',
|
|
||||||
},
|
|
||||||
colors: {
|
|
||||||
transparent: 'transparent',
|
|
||||||
white: 'hsl(0 100% 100% / <alpha-value>)',
|
|
||||||
black: 'hsl(0 100% 0% / <alpha-value>)',
|
|
||||||
background: 'hsl(var(--color-background) / <alpha-value>)',
|
|
||||||
placeholder: 'hsl(var(--color-gray-300) / <alpha-value>)',
|
|
||||||
red: color('red'),
|
|
||||||
orange: color('orange'),
|
|
||||||
yellow: color('yellow'),
|
|
||||||
gray: color('gray'),
|
|
||||||
blue: color('blue'),
|
|
||||||
green: color('green'),
|
|
||||||
pink: color('pink'),
|
|
||||||
violet: color('violet'),
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
plugins: [],
|
fontSize: {
|
||||||
}
|
sm: "0.9rem",
|
||||||
|
base: "1rem",
|
||||||
|
xl: "1.25rem",
|
||||||
|
"2xl": "1.563rem",
|
||||||
|
"3xl": "1.953rem",
|
||||||
|
"4xl": "2.441rem",
|
||||||
|
"5xl": "3.052rem"
|
||||||
|
},
|
||||||
|
borderRadius: {
|
||||||
|
none: "0px",
|
||||||
|
sm: "var(--border-radius-sm)",
|
||||||
|
DEFAULT: "var(--border-radius)",
|
||||||
|
md: "var(--border-radius-md)",
|
||||||
|
lg: "var(--border-radius-lg)",
|
||||||
|
full: "9999px"
|
||||||
|
},
|
||||||
|
colors: {
|
||||||
|
transparent: "transparent",
|
||||||
|
white: "hsl(0 100% 100% / <alpha-value>)",
|
||||||
|
black: "hsl(0 100% 0% / <alpha-value>)",
|
||||||
|
background: "hsl(var(--color-background) / <alpha-value>)",
|
||||||
|
placeholder: "hsl(var(--color-gray-400) / <alpha-value>)",
|
||||||
|
red: color("red"),
|
||||||
|
orange: color("orange"),
|
||||||
|
yellow: color("yellow"),
|
||||||
|
gray: color("gray"),
|
||||||
|
blue: color("blue"),
|
||||||
|
green: color("green"),
|
||||||
|
pink: color("pink"),
|
||||||
|
violet: color("violet")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: []
|
||||||
|
};
|
||||||
|
|
||||||
function color(name) {
|
function color(name) {
|
||||||
return {
|
return {
|
||||||
0: `hsl(var(--color-${name}-0) / <alpha-value>)`,
|
0: `hsl(var(--color-${name}-0) / <alpha-value>)`,
|
||||||
50: `hsl(var(--color-${name}-50) / <alpha-value>)`,
|
50: `hsl(var(--color-${name}-50) / <alpha-value>)`,
|
||||||
100: `hsl(var(--color-${name}-100) / <alpha-value>)`,
|
100: `hsl(var(--color-${name}-100) / <alpha-value>)`,
|
||||||
200: `hsl(var(--color-${name}-200) / <alpha-value>)`,
|
200: `hsl(var(--color-${name}-200) / <alpha-value>)`,
|
||||||
300: `hsl(var(--color-${name}-300) / <alpha-value>)`,
|
300: `hsl(var(--color-${name}-300) / <alpha-value>)`,
|
||||||
400: `hsl(var(--color-${name}-400) / <alpha-value>)`,
|
400: `hsl(var(--color-${name}-400) / <alpha-value>)`,
|
||||||
500: `hsl(var(--color-${name}-500) / <alpha-value>)`,
|
500: `hsl(var(--color-${name}-500) / <alpha-value>)`,
|
||||||
600: `hsl(var(--color-${name}-600) / <alpha-value>)`,
|
600: `hsl(var(--color-${name}-600) / <alpha-value>)`,
|
||||||
700: `hsl(var(--color-${name}-700) / <alpha-value>)`,
|
700: `hsl(var(--color-${name}-700) / <alpha-value>)`,
|
||||||
800: `hsl(var(--color-${name}-800) / <alpha-value>)`,
|
800: `hsl(var(--color-${name}-800) / <alpha-value>)`,
|
||||||
900: `hsl(var(--color-${name}-900) / <alpha-value>)`,
|
900: `hsl(var(--color-${name}-900) / <alpha-value>)`,
|
||||||
950: `hsl(var(--color-${name}-950) / <alpha-value>)`,
|
950: `hsl(var(--color-${name}-950) / <alpha-value>)`,
|
||||||
1000: `hsl(var(--color-${name}-1000) / <alpha-value>)`,
|
1000: `hsl(var(--color-${name}-1000) / <alpha-value>)`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user