diff --git a/package-lock.json b/package-lock.json
index 34a390f7..28075117 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"@tanstack/react-query": "5.24.1",
"@tanstack/react-query-devtools": "5.24.1",
"@tanstack/react-virtual": "3.2.0",
+ "@tippyjs/react": "4.2.6",
"@vanilla-extract/css": "1.9.3",
"@vanilla-extract/recipes": "0.3.0",
"@vanilla-extract/vite-plugin": "3.7.1",
@@ -31,8 +32,10 @@
"emojibase": "15.3.1",
"emojibase-data": "15.3.2",
"file-saver": "2.0.5",
+ "flux": "4.0.3",
"focus-trap-react": "10.0.2",
"folds": "2.2.0",
+ "formik": "2.4.6",
"html-dom-parser": "4.0.0",
"html-react-parser": "4.2.0",
"i18next": "23.12.2",
@@ -47,14 +50,17 @@
"millify": "6.1.0",
"pdfjs-dist": "4.2.67",
"prismjs": "1.30.0",
+ "prop-types": "15.8.1",
"react": "18.2.0",
"react-aria": "3.29.1",
+ "react-autosize-textarea": "7.1.0",
"react-blurhash": "0.2.0",
"react-colorful": "5.6.1",
"react-dom": "18.2.0",
"react-error-boundary": "4.0.13",
"react-google-recaptcha": "2.1.0",
"react-i18next": "15.0.0",
+ "react-modal": "3.16.1",
"react-range": "1.8.14",
"react-router-dom": "6.20.0",
"sanitize-html": "2.12.1",
@@ -62,6 +68,7 @@
"slate-dom": "0.112.2",
"slate-history": "0.110.3",
"slate-react": "0.112.1",
+ "tippy.js": "6.3.7",
"ua-parser-js": "1.0.35"
},
"devDependencies": {
@@ -90,6 +97,7 @@
"eslint-plugin-react": "7.31.11",
"eslint-plugin-react-hooks": "4.6.0",
"prettier": "2.8.1",
+ "sass": "1.56.2",
"typescript": "4.9.4",
"vite": "5.4.19",
"vite-plugin-pwa": "0.20.5",
@@ -2305,6 +2313,15 @@
"node": ">= 8"
}
},
+ "node_modules/@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
"node_modules/@react-aria/breadcrumbs": {
"version": "3.5.20",
"resolved": "https://registry.npmjs.org/@react-aria/breadcrumbs/-/breadcrumbs-3.5.20.tgz",
@@ -4507,6 +4524,18 @@
"url": "https://github.com/sponsors/tannerlinsley"
}
},
+ "node_modules/@tippyjs/react": {
+ "version": "4.2.6",
+ "resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz",
+ "integrity": "sha512-91RicDR+H7oDSyPycI13q3b7o4O60wa2oRbjlz2fyRLmHImc4vyDwuUP8NtZaN0VARJY5hybvDYrFzhY9+Lbyw==",
+ "dependencies": {
+ "tippy.js": "^6.3.1"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -4572,6 +4601,15 @@
"integrity": "sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ==",
"dev": true
},
+ "node_modules/@types/hoist-non-react-statics": {
+ "version": "3.3.6",
+ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz",
+ "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==",
+ "dependencies": {
+ "@types/react": "*",
+ "hoist-non-react-statics": "^3.3.0"
+ }
+ },
"node_modules/@types/is-hotkey": {
"version": "0.1.10",
"resolved": "https://registry.npmjs.org/@types/is-hotkey/-/is-hotkey-0.1.10.tgz",
@@ -4605,14 +4643,12 @@
"node_modules/@types/prop-types": {
"version": "15.7.14",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz",
- "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==",
- "dev": true
+ "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ=="
},
"node_modules/@types/react": {
"version": "18.2.39",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.39.tgz",
"integrity": "sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==",
- "dev": true,
"dependencies": {
"@types/prop-types": "*",
"@types/scheduler": "*",
@@ -4661,8 +4697,7 @@
"node_modules/@types/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz",
- "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==",
- "dev": true
+ "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw=="
},
"node_modules/@types/semver": {
"version": "7.5.8",
@@ -5285,6 +5320,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
+ },
"node_modules/ast-types-flow": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
@@ -5306,6 +5346,11 @@
"node": ">= 4.0.0"
}
},
+ "node_modules/autosize": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/autosize/-/autosize-4.0.4.tgz",
+ "integrity": "sha512-5yxLQ22O0fCRGoxGfeLSNt3J8LB1v+umtpMnPW6XjkTWXKoN0AmXAIhelJcDtFT/Y/wYWmfE+oqU10Q0b8FhaQ=="
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
@@ -5785,6 +5830,11 @@
"integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==",
"license": "MIT"
},
+ "node_modules/computed-style": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/computed-style/-/computed-style-0.1.4.tgz",
+ "integrity": "sha512-WpAmaKbMNmS3OProfHIdJiNleNJdgUrJfbKArXua28QF7+0CoZjlLn0lp6vlc+dl5r2/X9GQiQRQQU4BzSa69w=="
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -5846,6 +5896,14 @@
"url": "https://opencollective.com/core-js"
}
},
+ "node_modules/cross-fetch": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz",
+ "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==",
+ "dependencies": {
+ "node-fetch": "^2.7.0"
+ }
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -6961,6 +7019,11 @@
"node": ">=0.8.x"
}
},
+ "node_modules/exenv": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
+ "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw=="
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -7032,6 +7095,33 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/fbemitter": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz",
+ "integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==",
+ "dependencies": {
+ "fbjs": "^3.0.0"
+ }
+ },
+ "node_modules/fbjs": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz",
+ "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==",
+ "dependencies": {
+ "cross-fetch": "^3.1.5",
+ "fbjs-css-vars": "^1.0.0",
+ "loose-envify": "^1.0.0",
+ "object-assign": "^4.1.0",
+ "promise": "^7.1.1",
+ "setimmediate": "^1.0.5",
+ "ua-parser-js": "^1.0.35"
+ }
+ },
+ "node_modules/fbjs-css-vars": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz",
+ "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ=="
+ },
"node_modules/fdir": {
"version": "6.4.3",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz",
@@ -7140,6 +7230,18 @@
"integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
"dev": true
},
+ "node_modules/flux": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/flux/-/flux-4.0.3.tgz",
+ "integrity": "sha512-yKAbrp7JhZhj6uiT1FTuVMlIAT1J4jqEyBpFApi1kxpGZCvacMVc/t1pMQyotqHhAgvoE3bNvAykhCo2CLjnYw==",
+ "dependencies": {
+ "fbemitter": "^3.0.0",
+ "fbjs": "^3.0.1"
+ },
+ "peerDependencies": {
+ "react": "^15.0.2 || ^16.0.0 || ^17.0.0"
+ }
+ },
"node_modules/focus-trap": {
"version": "7.6.4",
"resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.4.tgz",
@@ -7184,6 +7286,38 @@
"is-callable": "^1.1.3"
}
},
+ "node_modules/formik": {
+ "version": "2.4.6",
+ "resolved": "https://registry.npmjs.org/formik/-/formik-2.4.6.tgz",
+ "integrity": "sha512-A+2EI7U7aG296q2TLGvNapDNTZp1khVt5Vk0Q/fyfSROss0V/V6+txt2aJnwEos44IxTCW/LYAi/zgWzlevj+g==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://opencollective.com/formik"
+ }
+ ],
+ "dependencies": {
+ "@types/hoist-non-react-statics": "^3.3.1",
+ "deepmerge": "^2.1.1",
+ "hoist-non-react-statics": "^3.3.0",
+ "lodash": "^4.17.21",
+ "lodash-es": "^4.17.21",
+ "react-fast-compare": "^2.0.1",
+ "tiny-warning": "^1.0.2",
+ "tslib": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8.0"
+ }
+ },
+ "node_modules/formik/node_modules/deepmerge": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz",
+ "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/fs-extra": {
"version": "11.3.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz",
@@ -7762,6 +7896,12 @@
"url": "https://opencollective.com/immer"
}
},
+ "node_modules/immutable": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
+ "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==",
+ "dev": true
+ },
"node_modules/import-fresh": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -8496,6 +8636,17 @@
"node": ">=10"
}
},
+ "node_modules/line-height": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/line-height/-/line-height-0.3.1.tgz",
+ "integrity": "sha512-YExecgqPwnp5gplD2+Y8e8A5+jKpr25+DzMbFdI1/1UAr0FJrTFv4VkHLf8/6B590i1wUPJWMKKldkd/bdQ//w==",
+ "dependencies": {
+ "computed-style": "~0.1.3"
+ },
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
"node_modules/linkify-react": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/linkify-react/-/linkify-react-4.1.3.tgz",
@@ -8529,6 +8680,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"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.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@@ -9385,6 +9541,14 @@
"node": ">=6"
}
},
+ "node_modules/promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "dependencies": {
+ "asap": "~2.0.3"
+ }
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -9508,6 +9672,20 @@
"react": ">=16.4.1"
}
},
+ "node_modules/react-autosize-textarea": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/react-autosize-textarea/-/react-autosize-textarea-7.1.0.tgz",
+ "integrity": "sha512-BHpjCDkuOlllZn3nLazY2F8oYO1tS2jHnWhcjTWQdcKiiMU6gHLNt/fzmqMSyerR0eTdKtfSIqtSeTtghNwS+g==",
+ "dependencies": {
+ "autosize": "^4.0.2",
+ "line-height": "^0.3.1",
+ "prop-types": "^15.5.6"
+ },
+ "peerDependencies": {
+ "react": "^0.14.0 || ^15.0.0 || ^16.0.0",
+ "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0"
+ }
+ },
"node_modules/react-blurhash": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/react-blurhash/-/react-blurhash-0.2.0.tgz",
@@ -9550,6 +9728,11 @@
"react": ">=16.13.1"
}
},
+ "node_modules/react-fast-compare": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
+ "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
+ },
"node_modules/react-google-recaptcha": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-2.1.0.tgz",
@@ -9588,6 +9771,29 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
+ "node_modules/react-lifecycles-compat": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+ },
+ "node_modules/react-modal": {
+ "version": "3.16.1",
+ "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz",
+ "integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==",
+ "dependencies": {
+ "exenv": "^1.2.0",
+ "prop-types": "^15.7.2",
+ "react-lifecycles-compat": "^3.0.0",
+ "warning": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "peerDependencies": {
+ "react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18",
+ "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18"
+ }
+ },
"node_modules/react-property": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.0.tgz",
@@ -10046,6 +10252,23 @@
"postcss": "^8.3.11"
}
},
+ "node_modules/sass": {
+ "version": "1.56.2",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.2.tgz",
+ "integrity": "sha512-ciEJhnyCRwzlBCB+h5cCPM6ie/6f8HrhZMQOf5vlU60Y1bI1rx5Zb0vlDZvaycHsg/MqFfF1Eq2eokAa32iw8w==",
+ "dev": true,
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0",
+ "immutable": "^4.0.0",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/scheduler": {
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
@@ -10145,6 +10368,11 @@
"node": ">= 0.4"
}
},
+ "node_modules/setimmediate": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
+ "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA=="
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -10741,6 +10969,14 @@
"node": ">=12.0.0"
}
},
+ "node_modules/tippy.js": {
+ "version": "6.3.7",
+ "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz",
+ "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==",
+ "dependencies": {
+ "@popperjs/core": "^2.9.0"
+ }
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -11655,6 +11891,14 @@
"node": ">=0.10.0"
}
},
+ "node_modules/warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
diff --git a/package.json b/package.json
index 0c06993e..60d9373e 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
"@tanstack/react-query": "5.24.1",
"@tanstack/react-query-devtools": "5.24.1",
"@tanstack/react-virtual": "3.2.0",
+ "@tippyjs/react": "4.2.6",
"@vanilla-extract/css": "1.9.3",
"@vanilla-extract/recipes": "0.3.0",
"@vanilla-extract/vite-plugin": "3.7.1",
@@ -42,8 +43,10 @@
"emojibase": "15.3.1",
"emojibase-data": "15.3.2",
"file-saver": "2.0.5",
+ "flux": "4.0.3",
"focus-trap-react": "10.0.2",
"folds": "2.2.0",
+ "formik": "2.4.6",
"html-dom-parser": "4.0.0",
"html-react-parser": "4.2.0",
"i18next": "23.12.2",
@@ -58,14 +61,17 @@
"millify": "6.1.0",
"pdfjs-dist": "4.2.67",
"prismjs": "1.30.0",
+ "prop-types": "15.8.1",
"react": "18.2.0",
"react-aria": "3.29.1",
+ "react-autosize-textarea": "7.1.0",
"react-blurhash": "0.2.0",
"react-colorful": "5.6.1",
"react-dom": "18.2.0",
"react-error-boundary": "4.0.13",
"react-google-recaptcha": "2.1.0",
"react-i18next": "15.0.0",
+ "react-modal": "3.16.1",
"react-range": "1.8.14",
"react-router-dom": "6.20.0",
"sanitize-html": "2.12.1",
@@ -73,6 +79,7 @@
"slate-dom": "0.112.2",
"slate-history": "0.110.3",
"slate-react": "0.112.1",
+ "tippy.js": "6.3.7",
"ua-parser-js": "1.0.35"
},
"devDependencies": {
@@ -101,6 +108,7 @@
"eslint-plugin-react": "7.31.11",
"eslint-plugin-react-hooks": "4.6.0",
"prettier": "2.8.1",
+ "sass": "1.56.2",
"typescript": "4.9.4",
"vite": "5.4.19",
"vite-plugin-pwa": "0.20.5",
diff --git a/public/res/ic/filled/category.svg b/public/res/ic/filled/category.svg
new file mode 100644
index 00000000..87b2588d
--- /dev/null
+++ b/public/res/ic/filled/category.svg
@@ -0,0 +1,18 @@
+
+
+
+
diff --git a/public/res/ic/filled/pin.svg b/public/res/ic/filled/pin.svg
new file mode 100644
index 00000000..6a701474
--- /dev/null
+++ b/public/res/ic/filled/pin.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/public/res/ic/filled/star.svg b/public/res/ic/filled/star.svg
new file mode 100644
index 00000000..378c891e
--- /dev/null
+++ b/public/res/ic/filled/star.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/public/res/ic/outlined/add-pin.svg b/public/res/ic/outlined/add-pin.svg
new file mode 100644
index 00000000..9634bede
--- /dev/null
+++ b/public/res/ic/outlined/add-pin.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/add-user.svg b/public/res/ic/outlined/add-user.svg
new file mode 100644
index 00000000..c3803d80
--- /dev/null
+++ b/public/res/ic/outlined/add-user.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/public/res/ic/outlined/ball.svg b/public/res/ic/outlined/ball.svg
new file mode 100644
index 00000000..d4b89ff5
--- /dev/null
+++ b/public/res/ic/outlined/ball.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/public/res/ic/outlined/bell-off.svg b/public/res/ic/outlined/bell-off.svg
new file mode 100644
index 00000000..79ce8a33
--- /dev/null
+++ b/public/res/ic/outlined/bell-off.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/public/res/ic/outlined/bell-ping.svg b/public/res/ic/outlined/bell-ping.svg
new file mode 100644
index 00000000..3431bea1
--- /dev/null
+++ b/public/res/ic/outlined/bell-ping.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/public/res/ic/outlined/bell-ring.svg b/public/res/ic/outlined/bell-ring.svg
new file mode 100644
index 00000000..57fc2679
--- /dev/null
+++ b/public/res/ic/outlined/bell-ring.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/public/res/ic/outlined/bell.svg b/public/res/ic/outlined/bell.svg
new file mode 100644
index 00000000..43d470b5
--- /dev/null
+++ b/public/res/ic/outlined/bell.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/public/res/ic/outlined/bin.svg b/public/res/ic/outlined/bin.svg
new file mode 100644
index 00000000..984be625
--- /dev/null
+++ b/public/res/ic/outlined/bin.svg
@@ -0,0 +1,18 @@
+
+
+
+
diff --git a/public/res/ic/outlined/bulb.svg b/public/res/ic/outlined/bulb.svg
new file mode 100644
index 00000000..00e80886
--- /dev/null
+++ b/public/res/ic/outlined/bulb.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/public/res/ic/outlined/category.svg b/public/res/ic/outlined/category.svg
new file mode 100644
index 00000000..c7c33b38
--- /dev/null
+++ b/public/res/ic/outlined/category.svg
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/public/res/ic/outlined/check.svg b/public/res/ic/outlined/check.svg
new file mode 100644
index 00000000..72a18327
--- /dev/null
+++ b/public/res/ic/outlined/check.svg
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/public/res/ic/outlined/chevron-bottom.svg b/public/res/ic/outlined/chevron-bottom.svg
new file mode 100644
index 00000000..5562b7aa
--- /dev/null
+++ b/public/res/ic/outlined/chevron-bottom.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/public/res/ic/outlined/chevron-left.svg b/public/res/ic/outlined/chevron-left.svg
new file mode 100644
index 00000000..ba9e12cc
--- /dev/null
+++ b/public/res/ic/outlined/chevron-left.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/public/res/ic/outlined/chevron-right.svg b/public/res/ic/outlined/chevron-right.svg
new file mode 100644
index 00000000..7f6a806e
--- /dev/null
+++ b/public/res/ic/outlined/chevron-right.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/public/res/ic/outlined/chevron-top.svg b/public/res/ic/outlined/chevron-top.svg
new file mode 100644
index 00000000..f5948fe9
--- /dev/null
+++ b/public/res/ic/outlined/chevron-top.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/public/res/ic/outlined/circle-plus.svg b/public/res/ic/outlined/circle-plus.svg
new file mode 100644
index 00000000..41690a08
--- /dev/null
+++ b/public/res/ic/outlined/circle-plus.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/cmd.svg b/public/res/ic/outlined/cmd.svg
new file mode 100644
index 00000000..75ae0d98
--- /dev/null
+++ b/public/res/ic/outlined/cmd.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/coin.svg b/public/res/ic/outlined/coin.svg
new file mode 100644
index 00000000..025424e8
--- /dev/null
+++ b/public/res/ic/outlined/coin.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/public/res/ic/outlined/cross.svg b/public/res/ic/outlined/cross.svg
new file mode 100644
index 00000000..0acda884
--- /dev/null
+++ b/public/res/ic/outlined/cross.svg
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/public/res/ic/outlined/cup.svg b/public/res/ic/outlined/cup.svg
new file mode 100644
index 00000000..8921e2c9
--- /dev/null
+++ b/public/res/ic/outlined/cup.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/public/res/ic/outlined/dog.svg b/public/res/ic/outlined/dog.svg
new file mode 100644
index 00000000..3b252956
--- /dev/null
+++ b/public/res/ic/outlined/dog.svg
@@ -0,0 +1,18 @@
+
+
+
+
diff --git a/public/res/ic/outlined/download.svg b/public/res/ic/outlined/download.svg
new file mode 100644
index 00000000..677014f3
--- /dev/null
+++ b/public/res/ic/outlined/download.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/public/res/ic/outlined/emoji-add.svg b/public/res/ic/outlined/emoji-add.svg
new file mode 100644
index 00000000..c4cacef2
--- /dev/null
+++ b/public/res/ic/outlined/emoji-add.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/public/res/ic/outlined/emoji.svg b/public/res/ic/outlined/emoji.svg
new file mode 100644
index 00000000..0daac879
--- /dev/null
+++ b/public/res/ic/outlined/emoji.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/public/res/ic/outlined/explore.svg b/public/res/ic/outlined/explore.svg
new file mode 100644
index 00000000..7cc2a479
--- /dev/null
+++ b/public/res/ic/outlined/explore.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/external.svg b/public/res/ic/outlined/external.svg
new file mode 100644
index 00000000..adade1bd
--- /dev/null
+++ b/public/res/ic/outlined/external.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/res/ic/outlined/eye-blind.svg b/public/res/ic/outlined/eye-blind.svg
new file mode 100644
index 00000000..fbc8e2ae
--- /dev/null
+++ b/public/res/ic/outlined/eye-blind.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/res/ic/outlined/eye.svg b/public/res/ic/outlined/eye.svg
new file mode 100644
index 00000000..1ce868bf
--- /dev/null
+++ b/public/res/ic/outlined/eye.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/res/ic/outlined/file.svg b/public/res/ic/outlined/file.svg
new file mode 100644
index 00000000..d6a2a27a
--- /dev/null
+++ b/public/res/ic/outlined/file.svg
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/public/res/ic/outlined/flag.svg b/public/res/ic/outlined/flag.svg
new file mode 100644
index 00000000..8fce98d6
--- /dev/null
+++ b/public/res/ic/outlined/flag.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/public/res/ic/outlined/hash-globe.svg b/public/res/ic/outlined/hash-globe.svg
new file mode 100644
index 00000000..ce3df083
--- /dev/null
+++ b/public/res/ic/outlined/hash-globe.svg
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/public/res/ic/outlined/hash-lock.svg b/public/res/ic/outlined/hash-lock.svg
new file mode 100644
index 00000000..ae263ced
--- /dev/null
+++ b/public/res/ic/outlined/hash-lock.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/public/res/ic/outlined/hash-plus.svg b/public/res/ic/outlined/hash-plus.svg
new file mode 100644
index 00000000..69737fd5
--- /dev/null
+++ b/public/res/ic/outlined/hash-plus.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/public/res/ic/outlined/hash-search.svg b/public/res/ic/outlined/hash-search.svg
new file mode 100644
index 00000000..f135e898
--- /dev/null
+++ b/public/res/ic/outlined/hash-search.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/public/res/ic/outlined/hash-shield.svg b/public/res/ic/outlined/hash-shield.svg
new file mode 100644
index 00000000..dfd344b1
--- /dev/null
+++ b/public/res/ic/outlined/hash-shield.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/hash.svg b/public/res/ic/outlined/hash.svg
new file mode 100644
index 00000000..dcb8b964
--- /dev/null
+++ b/public/res/ic/outlined/hash.svg
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/public/res/ic/outlined/heart.svg b/public/res/ic/outlined/heart.svg
new file mode 100644
index 00000000..c5b940b6
--- /dev/null
+++ b/public/res/ic/outlined/heart.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/public/res/ic/outlined/home.svg b/public/res/ic/outlined/home.svg
new file mode 100644
index 00000000..3c7a02df
--- /dev/null
+++ b/public/res/ic/outlined/home.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/public/res/ic/outlined/horizontal-menu.svg b/public/res/ic/outlined/horizontal-menu.svg
new file mode 100644
index 00000000..a19b3c35
--- /dev/null
+++ b/public/res/ic/outlined/horizontal-menu.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/inbox.svg b/public/res/ic/outlined/inbox.svg
new file mode 100644
index 00000000..65435876
--- /dev/null
+++ b/public/res/ic/outlined/inbox.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/public/res/ic/outlined/info.svg b/public/res/ic/outlined/info.svg
new file mode 100644
index 00000000..30a57887
--- /dev/null
+++ b/public/res/ic/outlined/info.svg
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/public/res/ic/outlined/invite-arrow.svg b/public/res/ic/outlined/invite-arrow.svg
new file mode 100644
index 00000000..370bf8e8
--- /dev/null
+++ b/public/res/ic/outlined/invite-arrow.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/invite-cancel-arrow.svg b/public/res/ic/outlined/invite-cancel-arrow.svg
new file mode 100644
index 00000000..795a773a
--- /dev/null
+++ b/public/res/ic/outlined/invite-cancel-arrow.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/invite.svg b/public/res/ic/outlined/invite.svg
new file mode 100644
index 00000000..3896e15e
--- /dev/null
+++ b/public/res/ic/outlined/invite.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/join-arrow.svg b/public/res/ic/outlined/join-arrow.svg
new file mode 100644
index 00000000..90cfa651
--- /dev/null
+++ b/public/res/ic/outlined/join-arrow.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/public/res/ic/outlined/leave-arrow.svg b/public/res/ic/outlined/leave-arrow.svg
new file mode 100644
index 00000000..a51ac1d1
--- /dev/null
+++ b/public/res/ic/outlined/leave-arrow.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/public/res/ic/outlined/lock.svg b/public/res/ic/outlined/lock.svg
new file mode 100644
index 00000000..77021f0f
--- /dev/null
+++ b/public/res/ic/outlined/lock.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/markdown.svg b/public/res/ic/outlined/markdown.svg
new file mode 100644
index 00000000..775afbfb
--- /dev/null
+++ b/public/res/ic/outlined/markdown.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/public/res/ic/outlined/message-unread.svg b/public/res/ic/outlined/message-unread.svg
new file mode 100644
index 00000000..fc5e9ff0
--- /dev/null
+++ b/public/res/ic/outlined/message-unread.svg
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/public/res/ic/outlined/message.svg b/public/res/ic/outlined/message.svg
new file mode 100644
index 00000000..d36e9a30
--- /dev/null
+++ b/public/res/ic/outlined/message.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/public/res/ic/outlined/pause.svg b/public/res/ic/outlined/pause.svg
new file mode 100644
index 00000000..c312613b
--- /dev/null
+++ b/public/res/ic/outlined/pause.svg
@@ -0,0 +1,16 @@
+
+
+
+
diff --git a/public/res/ic/outlined/peace.svg b/public/res/ic/outlined/peace.svg
new file mode 100644
index 00000000..8a7c81a3
--- /dev/null
+++ b/public/res/ic/outlined/peace.svg
@@ -0,0 +1,9 @@
+
+
+
+
diff --git a/public/res/ic/outlined/pencil.svg b/public/res/ic/outlined/pencil.svg
new file mode 100644
index 00000000..1b8ac24a
--- /dev/null
+++ b/public/res/ic/outlined/pencil.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/public/res/ic/outlined/photo.svg b/public/res/ic/outlined/photo.svg
new file mode 100644
index 00000000..af01a330
--- /dev/null
+++ b/public/res/ic/outlined/photo.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/pin.svg b/public/res/ic/outlined/pin.svg
new file mode 100644
index 00000000..211242cd
--- /dev/null
+++ b/public/res/ic/outlined/pin.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/public/res/ic/outlined/play.svg b/public/res/ic/outlined/play.svg
new file mode 100644
index 00000000..87b3a8f6
--- /dev/null
+++ b/public/res/ic/outlined/play.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/plus.svg b/public/res/ic/outlined/plus.svg
new file mode 100644
index 00000000..ce37594e
--- /dev/null
+++ b/public/res/ic/outlined/plus.svg
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/public/res/ic/outlined/power.svg b/public/res/ic/outlined/power.svg
new file mode 100644
index 00000000..8aeb6db8
--- /dev/null
+++ b/public/res/ic/outlined/power.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/recent-clock.svg b/public/res/ic/outlined/recent-clock.svg
new file mode 100644
index 00000000..30b10d59
--- /dev/null
+++ b/public/res/ic/outlined/recent-clock.svg
@@ -0,0 +1,17 @@
+
+
+
+
diff --git a/public/res/ic/outlined/reply-arrow.svg b/public/res/ic/outlined/reply-arrow.svg
new file mode 100644
index 00000000..3cda01cd
--- /dev/null
+++ b/public/res/ic/outlined/reply-arrow.svg
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/public/res/ic/outlined/search.svg b/public/res/ic/outlined/search.svg
new file mode 100644
index 00000000..75dd6320
--- /dev/null
+++ b/public/res/ic/outlined/search.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/public/res/ic/outlined/send.svg b/public/res/ic/outlined/send.svg
new file mode 100644
index 00000000..aa487132
--- /dev/null
+++ b/public/res/ic/outlined/send.svg
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/public/res/ic/outlined/settings.svg b/public/res/ic/outlined/settings.svg
new file mode 100644
index 00000000..ee640b39
--- /dev/null
+++ b/public/res/ic/outlined/settings.svg
@@ -0,0 +1,22 @@
+
+
+
+
diff --git a/public/res/ic/outlined/shield-empty.svg b/public/res/ic/outlined/shield-empty.svg
new file mode 100644
index 00000000..6bc9d304
--- /dev/null
+++ b/public/res/ic/outlined/shield-empty.svg
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/public/res/ic/outlined/shield-user.svg b/public/res/ic/outlined/shield-user.svg
new file mode 100644
index 00000000..bd5f07c5
--- /dev/null
+++ b/public/res/ic/outlined/shield-user.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/shield.svg b/public/res/ic/outlined/shield.svg
new file mode 100644
index 00000000..9bb46fa1
--- /dev/null
+++ b/public/res/ic/outlined/shield.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/public/res/ic/outlined/space-globe.svg b/public/res/ic/outlined/space-globe.svg
new file mode 100644
index 00000000..63d71f1d
--- /dev/null
+++ b/public/res/ic/outlined/space-globe.svg
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/public/res/ic/outlined/space-lock.svg b/public/res/ic/outlined/space-lock.svg
new file mode 100644
index 00000000..b15705ca
--- /dev/null
+++ b/public/res/ic/outlined/space-lock.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/public/res/ic/outlined/space-plus.svg b/public/res/ic/outlined/space-plus.svg
new file mode 100644
index 00000000..4d69a1ef
--- /dev/null
+++ b/public/res/ic/outlined/space-plus.svg
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/public/res/ic/outlined/space.svg b/public/res/ic/outlined/space.svg
new file mode 100644
index 00000000..a4b54b3e
--- /dev/null
+++ b/public/res/ic/outlined/space.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/public/res/ic/outlined/star.svg b/public/res/ic/outlined/star.svg
new file mode 100644
index 00000000..290f159a
--- /dev/null
+++ b/public/res/ic/outlined/star.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/public/res/ic/outlined/sticker.svg b/public/res/ic/outlined/sticker.svg
new file mode 100644
index 00000000..bc486e5e
--- /dev/null
+++ b/public/res/ic/outlined/sticker.svg
@@ -0,0 +1,4 @@
+
diff --git a/public/res/ic/outlined/sun.svg b/public/res/ic/outlined/sun.svg
new file mode 100644
index 00000000..d8ed06fd
--- /dev/null
+++ b/public/res/ic/outlined/sun.svg
@@ -0,0 +1,34 @@
+
+
+
+
diff --git a/public/res/ic/outlined/tick-mark.svg b/public/res/ic/outlined/tick-mark.svg
new file mode 100644
index 00000000..8e76ed55
--- /dev/null
+++ b/public/res/ic/outlined/tick-mark.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/user.svg b/public/res/ic/outlined/user.svg
new file mode 100644
index 00000000..6756a1b2
--- /dev/null
+++ b/public/res/ic/outlined/user.svg
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/public/res/ic/outlined/vertical-menu.svg b/public/res/ic/outlined/vertical-menu.svg
new file mode 100644
index 00000000..ec5c544c
--- /dev/null
+++ b/public/res/ic/outlined/vertical-menu.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/public/res/ic/outlined/vlc.svg b/public/res/ic/outlined/vlc.svg
new file mode 100644
index 00000000..8a2b844f
--- /dev/null
+++ b/public/res/ic/outlined/vlc.svg
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/public/res/ic/outlined/volume-full.svg b/public/res/ic/outlined/volume-full.svg
new file mode 100644
index 00000000..20419e72
--- /dev/null
+++ b/public/res/ic/outlined/volume-full.svg
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/public/res/ic/outlined/volume-mute.svg b/public/res/ic/outlined/volume-mute.svg
new file mode 100644
index 00000000..beb06771
--- /dev/null
+++ b/public/res/ic/outlined/volume-mute.svg
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/src/app/atoms/avatar/Avatar.jsx b/src/app/atoms/avatar/Avatar.jsx
new file mode 100644
index 00000000..27bf7c90
--- /dev/null
+++ b/src/app/atoms/avatar/Avatar.jsx
@@ -0,0 +1,69 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import './Avatar.scss';
+
+import Text from '../text/Text';
+import RawIcon from '../system-icons/RawIcon';
+
+import ImageBrokenSVG from '../../../../public/res/svg/image-broken.svg';
+import { avatarInitials } from '../../../util/common';
+
+const Avatar = React.forwardRef(({ text, bgColor, iconSrc, iconColor, imageSrc, size }, ref) => {
+ let textSize = 's1';
+ if (size === 'large') textSize = 'h1';
+ if (size === 'small') textSize = 'b1';
+ if (size === 'extra-small') textSize = 'b3';
+
+ return (
+
+ {imageSrc !== null ? (
+

{
+ e.target.style.backgroundColor = 'transparent';
+ }}
+ onError={(e) => {
+ e.target.src = ImageBrokenSVG;
+ }}
+ alt=""
+ />
+ ) : (
+
+ {iconSrc !== null ? (
+
+ ) : (
+ text !== null && (
+
+ {avatarInitials(text)}
+
+ )
+ )}
+
+ )}
+
+ );
+});
+
+Avatar.defaultProps = {
+ text: null,
+ bgColor: 'transparent',
+ iconSrc: null,
+ iconColor: null,
+ imageSrc: null,
+ size: 'normal',
+};
+
+Avatar.propTypes = {
+ text: PropTypes.string,
+ bgColor: PropTypes.string,
+ iconSrc: PropTypes.string,
+ iconColor: PropTypes.string,
+ imageSrc: PropTypes.string,
+ size: PropTypes.oneOf(['large', 'normal', 'small', 'extra-small']),
+};
+
+export default Avatar;
diff --git a/src/app/atoms/avatar/Avatar.scss b/src/app/atoms/avatar/Avatar.scss
new file mode 100644
index 00000000..ea69c9e8
--- /dev/null
+++ b/src/app/atoms/avatar/Avatar.scss
@@ -0,0 +1,56 @@
+@use '../../partials/flex';
+
+.avatar-container {
+ display: inline-flex;
+ width: 42px;
+ height: 42px;
+ border-radius: var(--bo-radius);
+ position: relative;
+
+ &__large {
+ width: var(--av-large);
+ height: var(--av-large);
+ }
+ &__normal {
+ width: var(--av-normal);
+ height: var(--av-normal);
+ }
+
+ &__small {
+ width: var(--av-small);
+ height: var(--av-small);
+ }
+
+ &__extra-small {
+ width: var(--av-extra-small);
+ height: var(--av-extra-small);
+ }
+
+ > img {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+ border-radius: inherit;
+ background-color: var(--bg-surface-hover);
+ }
+
+ .avatar__border {
+ @extend .cp-fx__row--c-c;
+
+ position: absolute;
+ top: 0;
+ left: 0;
+
+ width: 100%;
+ height: 100%;
+ border-radius: inherit;
+
+ .text {
+ color: white;
+ }
+ &--active {
+ @extend .avatar__border;
+ box-shadow: var(--bs-surface-border);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/app/atoms/avatar/render.js b/src/app/atoms/avatar/render.js
new file mode 100644
index 00000000..e8cf1a66
--- /dev/null
+++ b/src/app/atoms/avatar/render.js
@@ -0,0 +1,57 @@
+import { avatarInitials, cssVar } from '../../../util/common';
+
+// renders the avatar and returns it as an URL
+export default async function renderAvatar({
+ text, bgColor, imageSrc, size, borderRadius, scale,
+}) {
+ try {
+ const canvas = document.createElement('canvas');
+ canvas.width = size * scale;
+ canvas.height = size * scale;
+
+ const ctx = canvas.getContext('2d');
+
+ ctx.scale(scale, scale);
+
+ // rounded corners
+ ctx.beginPath();
+ ctx.moveTo(size, size);
+ ctx.arcTo(0, size, 0, 0, borderRadius);
+ ctx.arcTo(0, 0, size, 0, borderRadius);
+ ctx.arcTo(size, 0, size, size, borderRadius);
+ ctx.arcTo(size, size, 0, size, borderRadius);
+
+ if (imageSrc) {
+ // clip corners of image
+ ctx.closePath();
+ ctx.clip();
+
+ const img = new Image();
+ img.crossOrigin = 'anonymous';
+ const promise = new Promise((resolve, reject) => {
+ img.onerror = reject;
+ img.onload = resolve;
+ });
+ img.src = imageSrc;
+ await promise;
+
+ ctx.drawImage(img, 0, 0, size, size);
+ } else {
+ // colored background
+ ctx.fillStyle = cssVar(bgColor);
+ ctx.fill();
+
+ // centered letter
+ ctx.fillStyle = '#fff';
+ ctx.font = `${cssVar('--fs-s1')} ${cssVar('--font-primary')}`;
+ ctx.textBaseline = 'middle';
+ ctx.textAlign = 'center';
+ ctx.fillText(avatarInitials(text), size / 2, size / 2);
+ }
+
+ return canvas.toDataURL();
+ } catch (e) {
+ console.error(e);
+ return imageSrc;
+ }
+}
diff --git a/src/app/atoms/badge/NotificationBadge.jsx b/src/app/atoms/badge/NotificationBadge.jsx
new file mode 100644
index 00000000..12c1bd44
--- /dev/null
+++ b/src/app/atoms/badge/NotificationBadge.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import './NotificationBadge.scss';
+
+import Text from '../text/Text';
+
+function NotificationBadge({ alert, content }) {
+ const notificationClass = alert ? ' notification-badge--alert' : '';
+ return (
+
+ {content !== null && {content}}
+
+ );
+}
+
+NotificationBadge.defaultProps = {
+ alert: false,
+ content: null,
+};
+
+NotificationBadge.propTypes = {
+ alert: PropTypes.bool,
+ content: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number,
+ ]),
+};
+
+export default NotificationBadge;
diff --git a/src/app/atoms/badge/NotificationBadge.scss b/src/app/atoms/badge/NotificationBadge.scss
new file mode 100644
index 00000000..f5cfa73f
--- /dev/null
+++ b/src/app/atoms/badge/NotificationBadge.scss
@@ -0,0 +1,21 @@
+.notification-badge {
+ min-width: 16px;
+ min-height: 8px;
+ padding: 0 var(--sp-ultra-tight);
+ background-color: var(--bg-badge);
+ border-radius: var(--bo-radius);
+
+ .text {
+ color: var(--tc-badge);
+ text-align: center;
+ }
+
+ &--alert {
+ background-color: var(--bg-positive);
+ }
+
+ &:empty {
+ min-width: 8px;
+ margin: 0 var(--sp-ultra-tight);
+ }
+}
\ No newline at end of file
diff --git a/src/app/atoms/button/Button.jsx b/src/app/atoms/button/Button.jsx
new file mode 100644
index 00000000..1c1c950c
--- /dev/null
+++ b/src/app/atoms/button/Button.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import './Button.scss';
+
+import Text from '../text/Text';
+import RawIcon from '../system-icons/RawIcon';
+import { blurOnBubbling } from './script';
+
+const Button = React.forwardRef(({
+ id, className, variant, iconSrc,
+ type, onClick, children, disabled,
+}, ref) => {
+ const iconClass = (iconSrc === null) ? '' : `btn-${variant}--icon`;
+ return (
+
+ );
+});
+
+Button.defaultProps = {
+ id: '',
+ className: null,
+ variant: 'surface',
+ iconSrc: null,
+ type: 'button',
+ onClick: null,
+ disabled: false,
+};
+
+Button.propTypes = {
+ id: PropTypes.string,
+ className: PropTypes.string,
+ variant: PropTypes.oneOf(['surface', 'primary', 'positive', 'caution', 'danger']),
+ iconSrc: PropTypes.string,
+ type: PropTypes.oneOf(['button', 'submit', 'reset']),
+ onClick: PropTypes.func,
+ children: PropTypes.node.isRequired,
+ disabled: PropTypes.bool,
+};
+
+export default Button;
diff --git a/src/app/atoms/button/Button.scss b/src/app/atoms/button/Button.scss
new file mode 100644
index 00000000..e1a01bb0
--- /dev/null
+++ b/src/app/atoms/button/Button.scss
@@ -0,0 +1,81 @@
+@use 'state';
+@use '../../partials/dir';
+@use '../../partials/text';
+
+.btn-surface,
+.btn-primary,
+.btn-positive,
+.btn-caution,
+.btn-danger {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+
+ min-width: 80px;
+ padding: var(--sp-extra-tight) var(--sp-normal);
+ background-color: transparent;
+ border: none;
+ border-radius: var(--bo-radius);
+ cursor: pointer;
+ @include state.disabled;
+
+ & .text {
+ @extend .cp-txt__ellipsis;
+ }
+
+ &--icon {
+ @include dir.side(padding, var(--sp-tight), var(--sp-loose));
+
+ }
+ .ic-raw {
+ @include dir.side(margin, 0, var(--sp-extra-tight));
+ flex-shrink: 0;
+ }
+}
+
+@mixin color($textColor, $iconColor) {
+ .text {
+ color: $textColor;
+ }
+ .ic-raw {
+ background-color: $iconColor;
+ }
+}
+
+
+.btn-surface {
+ box-shadow: var(--bs-surface-border);
+ @include color(var(--tc-surface-high), var(--ic-surface-normal));
+ @include state.hover(var(--bg-surface-hover));
+ @include state.focus(var(--bs-surface-outline));
+ @include state.active(var(--bg-surface-active));
+}
+
+.btn-primary {
+ background-color: var(--bg-primary);
+ @include color(var(--tc-primary-high), var(--ic-primary-normal));
+ @include state.hover(var(--bg-primary-hover));
+ @include state.focus(var(--bs-primary-outline));
+ @include state.active(var(--bg-primary-active));
+}
+.btn-positive {
+ box-shadow: var(--bs-positive-border);
+ @include color(var(--tc-positive-high), var(--ic-positive-normal));
+ @include state.hover(var(--bg-positive-hover));
+ @include state.focus(var(--bs-positive-outline));
+ @include state.active(var(--bg-positive-active));
+}
+.btn-caution {
+ box-shadow: var(--bs-caution-border);
+ @include color(var(--tc-caution-high), var(--ic-caution-normal));
+ @include state.hover(var(--bg-caution-hover));
+ @include state.focus(var(--bs-caution-outline));
+ @include state.active(var(--bg-caution-active));
+}
+.btn-danger {
+ box-shadow: var(--bs-danger-border);
+ @include color(var(--tc-danger-high), var(--ic-danger-normal));
+ @include state.hover(var(--bg-danger-hover));
+ @include state.focus(var(--bs-danger-outline));
+ @include state.active(var(--bg-danger-active));
+}
\ No newline at end of file
diff --git a/src/app/atoms/button/Checkbox.jsx b/src/app/atoms/button/Checkbox.jsx
new file mode 100644
index 00000000..7fcea3b5
--- /dev/null
+++ b/src/app/atoms/button/Checkbox.jsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import './Checkbox.scss';
+
+function Checkbox({
+ variant, isActive, onToggle,
+ disabled, tabIndex,
+}) {
+ const className = `checkbox checkbox-${variant}${isActive ? ' checkbox--active' : ''}`;
+ if (onToggle === null) return ;
+ return (
+ // eslint-disable-next-line jsx-a11y/control-has-associated-label
+