mirror of
https://github.com/fergalmoran/mixyboos.git
synced 2025-12-22 09:41:39 +00:00
Added some layout stuff
This commit is contained in:
@@ -7,16 +7,12 @@ await import("./src/env.mjs");
|
||||
/** @type {import("next").NextConfig} */
|
||||
const config = {
|
||||
reactStrictMode: true,
|
||||
|
||||
/**
|
||||
* If you have `experimental: { appDir: true }` set, then you must comment the below `i18n` config
|
||||
* out.
|
||||
*
|
||||
* @see https://github.com/vercel/next.js/issues/41980
|
||||
*/
|
||||
i18n: {
|
||||
locales: ["en"],
|
||||
defaultLocale: "en",
|
||||
experimental: {
|
||||
appDir: true,
|
||||
},
|
||||
// i18n: {
|
||||
// locales: ["en"],
|
||||
// defaultLocale: "en",
|
||||
// },
|
||||
};
|
||||
export default config;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"@trpc/next": "^10.18.0",
|
||||
"@trpc/react-query": "^10.18.0",
|
||||
"@trpc/server": "^10.18.0",
|
||||
"classnames": "^2.3.2",
|
||||
"install": "^0.13.0",
|
||||
"next": "13.3.4",
|
||||
"react": "18.2.0",
|
||||
@@ -32,17 +33,21 @@
|
||||
"@types/prettier": "^2.7.2",
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.56.0",
|
||||
"@typescript-eslint/parser": "^5.56.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "^8.36.0",
|
||||
"eslint-config-next": "^13.2.4",
|
||||
"formik": "^2.2.9",
|
||||
"postcss": "^8.4.21",
|
||||
"prettier": "^2.8.6",
|
||||
"prettier-plugin-tailwindcss": "^0.2.6",
|
||||
"prisma": "^4.13.0",
|
||||
"react-dropzone": "^14.2.3",
|
||||
"tailwindcss": "^3.3.0",
|
||||
"typescript": "^5.0.2"
|
||||
"typescript": "^5.0.2",
|
||||
"uuid": "^9.0.0"
|
||||
},
|
||||
"ct3aMetadata": {
|
||||
"initVersion": "7.12.2"
|
||||
|
||||
123
pnpm-lock.yaml
generated
123
pnpm-lock.yaml
generated
@@ -25,6 +25,12 @@ dependencies:
|
||||
'@trpc/server':
|
||||
specifier: ^10.18.0
|
||||
version: 10.18.0
|
||||
classnames:
|
||||
specifier: ^2.3.2
|
||||
version: 2.3.2
|
||||
crypto:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1
|
||||
install:
|
||||
specifier: ^0.13.0
|
||||
version: 0.13.0
|
||||
@@ -63,6 +69,9 @@ devDependencies:
|
||||
'@types/react-dom':
|
||||
specifier: ^18.0.11
|
||||
version: 18.0.11
|
||||
'@types/uuid':
|
||||
specifier: ^9.0.1
|
||||
version: 9.0.1
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^5.56.0
|
||||
version: 5.56.0(@typescript-eslint/parser@5.56.0)(eslint@8.36.0)(typescript@5.0.2)
|
||||
@@ -78,6 +87,9 @@ devDependencies:
|
||||
eslint-config-next:
|
||||
specifier: ^13.2.4
|
||||
version: 13.2.4(eslint@8.36.0)(typescript@5.0.2)
|
||||
formik:
|
||||
specifier: ^2.2.9
|
||||
version: 2.2.9(react@18.2.0)
|
||||
postcss:
|
||||
specifier: ^8.4.21
|
||||
version: 8.4.21
|
||||
@@ -90,12 +102,18 @@ devDependencies:
|
||||
prisma:
|
||||
specifier: ^4.13.0
|
||||
version: 4.13.0
|
||||
react-dropzone:
|
||||
specifier: ^14.2.3
|
||||
version: 14.2.3(react@18.2.0)
|
||||
tailwindcss:
|
||||
specifier: ^3.3.0
|
||||
version: 3.3.0(postcss@8.4.21)
|
||||
typescript:
|
||||
specifier: ^5.0.2
|
||||
version: 5.0.2
|
||||
uuid:
|
||||
specifier: ^9.0.0
|
||||
version: 9.0.0
|
||||
|
||||
packages:
|
||||
|
||||
@@ -389,14 +407,14 @@ packages:
|
||||
dependencies:
|
||||
asn1js: 3.0.5
|
||||
pvtsutils: 1.3.2
|
||||
tslib: 2.4.1
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@peculiar/json-schema@1.1.12:
|
||||
resolution: {integrity: sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
dependencies:
|
||||
tslib: 2.4.1
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/@peculiar/webcrypto@1.4.1:
|
||||
@@ -406,7 +424,7 @@ packages:
|
||||
'@peculiar/asn1-schema': 2.3.6
|
||||
'@peculiar/json-schema': 1.1.12
|
||||
pvtsutils: 1.3.2
|
||||
tslib: 2.4.1
|
||||
tslib: 2.5.0
|
||||
webcrypto-core: 1.7.7
|
||||
dev: false
|
||||
|
||||
@@ -679,6 +697,10 @@ packages:
|
||||
'@types/node': 18.15.5
|
||||
dev: false
|
||||
|
||||
/@types/uuid@9.0.1:
|
||||
resolution: {integrity: sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==}
|
||||
dev: true
|
||||
|
||||
/@typescript-eslint/eslint-plugin@5.56.0(@typescript-eslint/parser@5.56.0)(eslint@8.36.0)(typescript@5.0.2):
|
||||
resolution: {integrity: sha512-ZNW37Ccl3oMZkzxrYDUX4o7cnuPgU+YrcaYXzsRtLB16I1FR5SHMqga3zGsaSliZADCWo2v8qHWqAYIj8nWCCg==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
@@ -929,7 +951,7 @@ packages:
|
||||
dependencies:
|
||||
pvtsutils: 1.3.2
|
||||
pvutils: 1.1.3
|
||||
tslib: 2.4.1
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/ast-types-flow@0.0.7:
|
||||
@@ -940,6 +962,11 @@ packages:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
dev: false
|
||||
|
||||
/attr-accept@2.2.2:
|
||||
resolution: {integrity: sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/autoprefixer@10.4.14(postcss@8.4.21):
|
||||
resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
@@ -1089,6 +1116,10 @@ packages:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/classnames@2.3.2:
|
||||
resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==}
|
||||
dev: false
|
||||
|
||||
/client-only@0.0.1:
|
||||
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
|
||||
dev: false
|
||||
@@ -1141,6 +1172,11 @@ packages:
|
||||
which: 2.0.2
|
||||
dev: true
|
||||
|
||||
/crypto@1.0.1:
|
||||
resolution: {integrity: sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==}
|
||||
deprecated: This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in.
|
||||
dev: false
|
||||
|
||||
/cssesc@3.0.0:
|
||||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -1209,6 +1245,11 @@ packages:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
dev: true
|
||||
|
||||
/deepmerge@2.2.1:
|
||||
resolution: {integrity: sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/deepmerge@4.2.2:
|
||||
resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -1283,7 +1324,7 @@ packages:
|
||||
resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
|
||||
dependencies:
|
||||
no-case: 3.0.4
|
||||
tslib: 2.4.1
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/electron-to-chromium@1.4.385:
|
||||
@@ -1744,6 +1785,13 @@ packages:
|
||||
flat-cache: 3.0.4
|
||||
dev: true
|
||||
|
||||
/file-selector@0.6.0:
|
||||
resolution: {integrity: sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==}
|
||||
engines: {node: '>= 12'}
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
dev: true
|
||||
|
||||
/fill-range@7.0.1:
|
||||
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -1786,6 +1834,21 @@ packages:
|
||||
mime-types: 2.1.35
|
||||
dev: false
|
||||
|
||||
/formik@2.2.9(react@18.2.0):
|
||||
resolution: {integrity: sha512-LQLcISMmf1r5at4/gyJigGn0gOwFbeEAlji+N9InZF6LIMXnFNkO42sCI8Jt84YZggpD4cPWObAZaxpEFtSzNA==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
dependencies:
|
||||
deepmerge: 2.2.1
|
||||
hoist-non-react-statics: 3.3.2
|
||||
lodash: 4.17.21
|
||||
lodash-es: 4.17.21
|
||||
react: 18.2.0
|
||||
react-fast-compare: 2.0.4
|
||||
tiny-warning: 1.0.3
|
||||
tslib: 1.14.1
|
||||
dev: true
|
||||
|
||||
/fraction.js@4.2.0:
|
||||
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
|
||||
dev: true
|
||||
@@ -1982,6 +2045,12 @@ packages:
|
||||
function-bind: 1.1.1
|
||||
dev: true
|
||||
|
||||
/hoist-non-react-statics@3.3.2:
|
||||
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
||||
dependencies:
|
||||
react-is: 16.13.1
|
||||
dev: true
|
||||
|
||||
/human-signals@2.1.0:
|
||||
resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
|
||||
engines: {node: '>=10.17.0'}
|
||||
@@ -2314,10 +2383,18 @@ packages:
|
||||
p-locate: 5.0.0
|
||||
dev: true
|
||||
|
||||
/lodash-es@4.17.21:
|
||||
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
|
||||
dev: true
|
||||
|
||||
/lodash.merge@4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
dev: true
|
||||
|
||||
/lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
dev: true
|
||||
|
||||
/loose-envify@1.4.0:
|
||||
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||
hasBin: true
|
||||
@@ -2327,7 +2404,7 @@ packages:
|
||||
/lower-case@2.0.2:
|
||||
resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
|
||||
dependencies:
|
||||
tslib: 2.4.1
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/lru-cache@6.0.0:
|
||||
@@ -2468,7 +2545,7 @@ packages:
|
||||
resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
|
||||
dependencies:
|
||||
lower-case: 2.0.2
|
||||
tslib: 2.4.1
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/node-fetch-native@1.0.1:
|
||||
@@ -2857,7 +2934,7 @@ packages:
|
||||
/pvtsutils@1.3.2:
|
||||
resolution: {integrity: sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==}
|
||||
dependencies:
|
||||
tslib: 2.4.1
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/pvutils@1.1.3:
|
||||
@@ -2889,6 +2966,22 @@ packages:
|
||||
scheduler: 0.23.0
|
||||
dev: false
|
||||
|
||||
/react-dropzone@14.2.3(react@18.2.0):
|
||||
resolution: {integrity: sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==}
|
||||
engines: {node: '>= 10.13'}
|
||||
peerDependencies:
|
||||
react: '>= 16.8 || 18.0.0'
|
||||
dependencies:
|
||||
attr-accept: 2.2.2
|
||||
file-selector: 0.6.0
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
dev: true
|
||||
|
||||
/react-fast-compare@2.0.4:
|
||||
resolution: {integrity: sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==}
|
||||
dev: true
|
||||
|
||||
/react-icons@4.8.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-N6+kOLcihDiAnj5Czu637waJqSnwlMNROzVZMhfX68V/9bu9qHaMIJC4UdozWoOk57gahFCNHwVvWzm0MTzRjg==}
|
||||
peerDependencies:
|
||||
@@ -2914,7 +3007,6 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
dev: false
|
||||
|
||||
/read-cache@1.0.0:
|
||||
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
|
||||
@@ -3055,7 +3147,7 @@ packages:
|
||||
resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==}
|
||||
dependencies:
|
||||
dot-case: 3.0.4
|
||||
tslib: 2.4.1
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/snakecase-keys@3.2.1:
|
||||
@@ -3279,6 +3371,10 @@ packages:
|
||||
any-promise: 1.3.0
|
||||
dev: true
|
||||
|
||||
/tiny-warning@1.0.3:
|
||||
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
|
||||
dev: true
|
||||
|
||||
/titleize@3.0.0:
|
||||
resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -3415,6 +3511,11 @@ packages:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
dev: true
|
||||
|
||||
/uuid@9.0.0:
|
||||
resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/webcrypto-core@1.7.7:
|
||||
resolution: {integrity: sha512-7FjigXNsBfopEj+5DV2nhNpfic2vumtjjgPmeDKk45z+MJwXKKfhPB7118Pfzrmh4jqOMST6Ch37iPAHoImg5g==}
|
||||
dependencies:
|
||||
@@ -3422,7 +3523,7 @@ packages:
|
||||
'@peculiar/json-schema': 1.1.12
|
||||
asn1js: 3.0.5
|
||||
pvtsutils: 1.3.2
|
||||
tslib: 2.4.1
|
||||
tslib: 2.5.0
|
||||
dev: false
|
||||
|
||||
/which-boxed-primitive@1.0.2:
|
||||
|
||||
3
src/app/globals.css
Normal file
3
src/app/globals.css
Normal file
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
24
src/app/layout.tsx
Normal file
24
src/app/layout.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import Navbar from "@/lib/components/layout/Navbar";
|
||||
import { ClerkProvider } from "@clerk/nextjs";
|
||||
import "./globals.css";
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<ClerkProvider>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<Navbar />
|
||||
<div className="pt-16">{children}</div>
|
||||
</body>
|
||||
</html>
|
||||
</ClerkProvider>
|
||||
);
|
||||
}
|
||||
export const metadata = {
|
||||
title: "Mixy::Boos",
|
||||
description: "Robot Powered Mixes",
|
||||
};
|
||||
8
src/app/mix/create/page.tsx
Normal file
8
src/app/mix/create/page.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import MixCreateComponent from "@/lib/components/mix/create/MixCreateComponent";
|
||||
import React from "react";
|
||||
|
||||
const MixCreatePage = () => {
|
||||
return <MixCreateComponent />;
|
||||
};
|
||||
|
||||
export default MixCreatePage;
|
||||
11
src/app/page.tsx
Normal file
11
src/app/page.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
const Home = () => {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center justify-center">
|
||||
<div></div>
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
@@ -1,3 +1,4 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { GiHamburgerMenu } from "react-icons/gi";
|
||||
import { RiFindReplaceLine } from "react-icons/ri";
|
||||
|
||||
177
src/lib/components/layout/sidebar/Sidebar.tsx
Normal file
177
src/lib/components/layout/sidebar/Sidebar.tsx
Normal file
@@ -0,0 +1,177 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { Sidebar, TextInput, Avatar } from "flowbite-react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import classNames from "classnames";
|
||||
import { UserModel } from "@lib/data/models";
|
||||
import {
|
||||
HiShoppingBag,
|
||||
HiPencil,
|
||||
HiLogin,
|
||||
HiThumbUp,
|
||||
HiOutlineDeviceMobile,
|
||||
HiPhotograph,
|
||||
HiPresentationChartBar,
|
||||
} from "react-icons/hi";
|
||||
import { FiTrendingUp } from "react-icons/fi";
|
||||
import { BsPersonBoundingBox, BsPersonVcard } from "react-icons/bs";
|
||||
import {
|
||||
MdDynamicFeed,
|
||||
MdFavoriteBorder,
|
||||
MdMusicVideo,
|
||||
MdOutlineRecentActors,
|
||||
MdQueryStats,
|
||||
} from "react-icons/md";
|
||||
import { CgSandClock } from "react-icons/cg";
|
||||
import { BiCategoryAlt } from "react-icons/bi";
|
||||
import Loading from "../../widgets/Loading";
|
||||
|
||||
interface IIDashboardSidebarProps {
|
||||
user: UserModel | undefined;
|
||||
}
|
||||
|
||||
const DashboardSidebar = ({ user }: IIDashboardSidebarProps) => {
|
||||
const router = useRouter();
|
||||
const _sidebarItemClick = (path: string | undefined): void => {
|
||||
if (!path) return;
|
||||
if (path.includes("dashboard")) {
|
||||
} else {
|
||||
router.push(path);
|
||||
}
|
||||
};
|
||||
|
||||
return !user ? (
|
||||
<Loading />
|
||||
) : (
|
||||
<div className="h-full w-60 space-y-2 p-3 dark:bg-slate-900 dark:text-gray-100">
|
||||
<div className="flex items-center space-x-4 p-2">
|
||||
{user.profileImage && (
|
||||
<UserImage src={user.profileImage} status={"offline"} size={"md"} />
|
||||
)}
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold">{user.displayName}</h2>
|
||||
<span className="flex items-center space-x-1">
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
href="#"
|
||||
className="text-xs hover:underline dark:text-gray-400"
|
||||
>
|
||||
{user.biography}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="divide-y divide-gray-700">
|
||||
<ul className="space-y-1 pb-4 pt-2 text-sm">
|
||||
<li className="dark:bg-slate-800 dark:text-gray-50">
|
||||
<Link
|
||||
rel="noopener noreferrer"
|
||||
href="dashboard/shows"
|
||||
className="flex items-center space-x-3 rounded-md p-2"
|
||||
>
|
||||
<BsPersonVcard className="h-5 w-5 fill-current dark:text-gray-400" />
|
||||
<span>My Shows</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="dark:bg-slate-800 dark:text-gray-50">
|
||||
<Link
|
||||
rel="noopener noreferrer"
|
||||
href="dashboard/mixes"
|
||||
className="flex items-center space-x-3 rounded-md p-2"
|
||||
>
|
||||
<BsPersonBoundingBox className="h-5 w-5 fill-current dark:text-gray-400" />
|
||||
<span>My Mixes</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="dark:bg-slate-800 dark:text-gray-50">
|
||||
<Link
|
||||
rel="noopener noreferrer"
|
||||
href="stats"
|
||||
className="flex items-center space-x-3 rounded-md p-2"
|
||||
>
|
||||
<MdQueryStats className="h-5 w-5 fill-current dark:text-gray-400" />
|
||||
<span>Stats</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="space-y-1 pb-2 pt-4 text-sm">
|
||||
<li className="dark:bg-slate-800 dark:text-gray-50">
|
||||
<Link
|
||||
rel="noopener noreferrer"
|
||||
href="feed"
|
||||
className="flex items-center space-x-3 rounded-md p-2"
|
||||
>
|
||||
<MdDynamicFeed className="h-5 w-5 fill-current dark:text-gray-400" />
|
||||
<span>Feed</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="dark:bg-slate-800 dark:text-gray-50">
|
||||
<Link
|
||||
rel="noopener noreferrer"
|
||||
href="/shows/new"
|
||||
className="flex items-center space-x-3 rounded-md p-2"
|
||||
>
|
||||
<MdOutlineRecentActors className="h-5 w-5 fill-current dark:text-gray-400" />
|
||||
<span>New Shows</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="dark:bg-slate-800 dark:text-gray-50">
|
||||
<Link
|
||||
rel="noopener noreferrer"
|
||||
href="favourites"
|
||||
className="flex items-center space-x-3 rounded-md p-2"
|
||||
>
|
||||
<MdFavoriteBorder className="h-5 w-5 fill-current dark:text-gray-400" />
|
||||
<span>Favourites</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="dark:bg-slate-800 dark:text-gray-50">
|
||||
<Link
|
||||
rel="noopener noreferrer"
|
||||
href="/dashboard/listen-later"
|
||||
className="flex items-center space-x-3 rounded-md p-2"
|
||||
>
|
||||
<CgSandClock className="h-5 w-5 fill-current dark:text-gray-400" />
|
||||
<span>Listen Later</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>{" "}
|
||||
<ul className="space-y-1 pb-2 pt-4 text-sm">
|
||||
<li className="dark:bg-slate-800 dark:text-gray-50">
|
||||
<Link
|
||||
rel="noopener noreferrer"
|
||||
href="categories"
|
||||
className="flex items-center space-x-3 rounded-md p-2"
|
||||
>
|
||||
<BiCategoryAlt className="h-5 w-5 fill-current dark:text-gray-400" />
|
||||
<span>Categories</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="dark:bg-slate-800 dark:text-gray-50">
|
||||
<Link
|
||||
rel="noopener noreferrer"
|
||||
href="trending"
|
||||
className="flex items-center space-x-3 rounded-md p-2"
|
||||
>
|
||||
<FiTrendingUp className="h-5 w-5 fill-current dark:text-gray-400" />
|
||||
<span>Trending</span>
|
||||
</Link>
|
||||
</li>
|
||||
<li className="dark:bg-slate-800 dark:text-gray-50">
|
||||
<Link
|
||||
rel="noopener noreferrer"
|
||||
href="livenow"
|
||||
className="flex items-center space-x-3 rounded-md p-2"
|
||||
>
|
||||
<MdMusicVideo className="h-5 w-5 fill-current dark:text-gray-400" />
|
||||
<span>Live Now</span>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DashboardSidebar;
|
||||
99
src/lib/components/layout/sidebar/sidebarItems.ts
Normal file
99
src/lib/components/layout/sidebar/sidebarItems.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
interface ISidebarItem {
|
||||
id: number;
|
||||
title: string;
|
||||
path?: string;
|
||||
icon?: any;
|
||||
}
|
||||
|
||||
import { HiAcademicCap } from "react-icons/hi2";
|
||||
import {
|
||||
HiThumbUp,
|
||||
HiLogin,
|
||||
HiPencil,
|
||||
HiShoppingBag,
|
||||
HiOutlineDeviceMobile,
|
||||
HiPresentationChartBar,
|
||||
} from "react-icons/hi";
|
||||
|
||||
const sidebarItems: ISidebarItem[] = [
|
||||
{
|
||||
id: 0,
|
||||
icon: HiShoppingBag,
|
||||
path: "dashboard/shows",
|
||||
title: "My Shows",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
icon: HiPencil,
|
||||
path: "/dashboard/mixes",
|
||||
title: "My Mixes",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
icon: HiLogin,
|
||||
path: "/stats",
|
||||
title: "Stats",
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "SPACER",
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
icon: HiPencil,
|
||||
path: "feed",
|
||||
title: "Feed",
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
icon: HiPencil,
|
||||
path: "/shows/new",
|
||||
title: "New Shows",
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
title: "SPACER",
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
icon: HiThumbUp,
|
||||
path: "/favourites",
|
||||
title: "Favourites",
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
icon: HiAcademicCap,
|
||||
path: "/dashboard/listen-later",
|
||||
title: "Listen Later",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
icon: HiShoppingBag,
|
||||
path: "history",
|
||||
title: "History",
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
title: "SPACER",
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
icon: HiOutlineDeviceMobile,
|
||||
path: "/categories",
|
||||
title: "Categories",
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
icon: "HiPhotograph",
|
||||
path: "trending",
|
||||
title: "Trending",
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
icon: HiPresentationChartBar,
|
||||
path: "/livenow",
|
||||
title: "Live Now",
|
||||
},
|
||||
];
|
||||
|
||||
export default sidebarItems;
|
||||
91
src/lib/components/mix/create/MixCreateComponent.tsx
Normal file
91
src/lib/components/mix/create/MixCreateComponent.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { MdOutlineErrorOutline } from "react-icons/md";
|
||||
|
||||
import PageHeader from "@/lib/components/widgets/PageHeader";
|
||||
import Progress from "@/lib/components/widgets/Progress";
|
||||
import FileUpload from "@/lib/components/widgets/FileUpload";
|
||||
import MixCreateDetailsComponent from "./MixCreateDetailsComponent";
|
||||
enum CreateState {
|
||||
new,
|
||||
editing,
|
||||
done,
|
||||
error,
|
||||
}
|
||||
enum UploadState {
|
||||
new,
|
||||
uploading,
|
||||
processing,
|
||||
done,
|
||||
error,
|
||||
}
|
||||
const MixCreateComponent = () => {
|
||||
const [errors, setErrors] = React.useState<string[]>([]);
|
||||
const [createState, setCreateState] = React.useState(CreateState.new);
|
||||
const [uploadState, setUploadState] = React.useState(UploadState.new);
|
||||
const [percentageUploaded, setPercentageUploaded] = React.useState(0);
|
||||
const [mixId] = React.useState(uuidv4());
|
||||
const [fileName, setFilename] = React.useState("");
|
||||
const router = useRouter();
|
||||
return (
|
||||
<div className="flex flex-col justify-center space-y-4">
|
||||
<PageHeader title="Let's create a mix" />
|
||||
<div className="flex items-center justify-center">
|
||||
<div className="w-3/4 max-w-2xl">
|
||||
{errors.length !== 0 && (
|
||||
<div className="mx-auto flex w-full max-w-lg overflow-hidden rounded-lg bg-white shadow-md dark:bg-slate-800">
|
||||
<div className="flex w-12 items-center justify-center bg-red-500">
|
||||
<MdOutlineErrorOutline className="h-6 w-6 fill-current text-white" />
|
||||
</div>
|
||||
<div className="-mx-3 px-4 py-2">
|
||||
<div className="mx-3">
|
||||
<span className="font-semibold text-red-500 dark:text-red-400">
|
||||
Ooopsies...
|
||||
</span>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-200">
|
||||
{errors}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{uploadState === UploadState.uploading && (
|
||||
<Progress percentage={percentageUploaded} title="Uploading audio" />
|
||||
)}
|
||||
{uploadState === UploadState.new && (
|
||||
<FileUpload
|
||||
mixId={mixId}
|
||||
onError={(e) => {
|
||||
setCreateState(CreateState.error);
|
||||
setErrors([...errors, e]);
|
||||
}}
|
||||
onUploadComplete={() => {
|
||||
setUploadState(UploadState.done);
|
||||
}}
|
||||
onUploadStart={(fileName) => {
|
||||
setFilename(fileName);
|
||||
setUploadState(UploadState.uploading);
|
||||
}}
|
||||
onUploadProgress={(total, loaded) => {
|
||||
setPercentageUploaded(Math.round((loaded * 100) / total));
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{createState === CreateState.new &&
|
||||
uploadState !== UploadState.new && (
|
||||
<MixCreateDetailsComponent
|
||||
// mix={{ id: mixId, title: fileName } as MixModel}
|
||||
// onMixCreated={(mix) => {
|
||||
// setCreateState(mix ? CreateState.done : CreateState.error);
|
||||
// }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MixCreateComponent;
|
||||
147
src/lib/components/mix/create/MixCreateDetailsComponent.tsx
Normal file
147
src/lib/components/mix/create/MixCreateDetailsComponent.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
"use client";
|
||||
import { Formik } from "formik";
|
||||
|
||||
import React from "react";
|
||||
import ImageUpload from "@/lib/components/widgets/ImageUpload";
|
||||
|
||||
const MixCreateDetailsComponent = () => {
|
||||
const [image, setImage] = React.useState<File | undefined>();
|
||||
return (
|
||||
<div className="flex space-x-4">
|
||||
<div className="w-1/2">
|
||||
<h2 className="mb-2 text-xl font-bold dark:text-white">Mix info</h2>
|
||||
<Formik
|
||||
initialValues={{ title: "Fuck", description: "You" }}
|
||||
onSubmit={(values, { setSubmitting }) => {
|
||||
alert("Some bang off these yokes");
|
||||
}}
|
||||
>
|
||||
{({
|
||||
values,
|
||||
handleChange,
|
||||
handleBlur,
|
||||
handleSubmit,
|
||||
isSubmitting,
|
||||
}) => (
|
||||
<form
|
||||
onSubmit={() => handleSubmit()}
|
||||
className="flex flex-col border border-gray-300 p-4 text-gray-800 shadow-lg"
|
||||
>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="title"
|
||||
className="mb-2 block text-sm font-medium text-gray-900 dark:text-gray-300"
|
||||
>
|
||||
Mix title
|
||||
</label>
|
||||
<input
|
||||
autoFocus
|
||||
className="block w-full rounded-lg border border-gray-300 bg-transparent p-2.5 text-gray-900 focus:border-fuchsia-300 focus:ring-2 focus:ring-fuchsia-50 dark:text-white sm:text-sm"
|
||||
id="title"
|
||||
name="title"
|
||||
spellCheck="false"
|
||||
placeholder="Mix Title"
|
||||
type="text"
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
value={values.title}
|
||||
/>
|
||||
<div className="mt-4">
|
||||
<label
|
||||
htmlFor="message"
|
||||
className="mb-2 block text-sm font-medium text-gray-900 dark:text-gray-400"
|
||||
>
|
||||
Description
|
||||
</label>
|
||||
<textarea
|
||||
className="block w-full rounded-lg border border-gray-300 bg-transparent p-2.5 text-gray-900 focus:border-fuchsia-300 focus:ring-2 focus:ring-fuchsia-50 dark:text-white sm:text-sm"
|
||||
id="description"
|
||||
name="description"
|
||||
spellCheck="true"
|
||||
rows={5}
|
||||
placeholder="Tell us something about the mix"
|
||||
onChange={handleChange}
|
||||
onBlur={handleBlur}
|
||||
value={values.description}
|
||||
/>
|
||||
</div>
|
||||
<div className="icons m-2 flex text-gray-500">
|
||||
<svg
|
||||
className="mr-2 h-7 cursor-pointer rounded-full border p-1 hover:text-gray-700"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
|
||||
/>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
className="mr-2 h-7 cursor-pointer rounded-full border p-1 hover:text-gray-700"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
className="mr-2 h-7 cursor-pointer rounded-full border p-1 hover:text-gray-700"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"
|
||||
/>
|
||||
</svg>
|
||||
<div className="count ml-auto text-xs font-semibold text-gray-400">
|
||||
0/300
|
||||
</div>
|
||||
</div>
|
||||
<div className="buttons flex">
|
||||
<div className="ml-auto p-1 px-4 ">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
title="Create"
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</Formik>
|
||||
</div>
|
||||
<div className="w-1/2 content-center">
|
||||
<h2 className="mb-2 text-xl font-bold dark:text-white">Mix image</h2>
|
||||
<ImageUpload
|
||||
onImageChanged={(image) => {
|
||||
console.log("MixDetailsForm", "onImageChanged", image);
|
||||
setImage(image);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default MixCreateDetailsComponent;
|
||||
80
src/lib/components/widgets/FileUpload.tsx
Normal file
80
src/lib/components/widgets/FileUpload.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import { FaFileAudio } from "react-icons/fa";
|
||||
import { VscCloudUpload } from "react-icons/vsc";
|
||||
import React from "react";
|
||||
import { getFileNameFromInput } from "@/lib/services/utils/fileUtils";
|
||||
|
||||
interface IFileUploadProps {
|
||||
mixId: string;
|
||||
onError: (error: string) => void;
|
||||
onUploadStart: (fileName: string) => void;
|
||||
onUploadComplete: () => void;
|
||||
onUploadProgress: (total: number, loaded: number) => void;
|
||||
}
|
||||
|
||||
const FileUpload = ({
|
||||
mixId,
|
||||
onError,
|
||||
onUploadStart,
|
||||
onUploadComplete,
|
||||
onUploadProgress,
|
||||
}: IFileUploadProps) => {
|
||||
const startUpload = async (event: React.FormEvent<HTMLInputElement>) => {
|
||||
if (!event.currentTarget.files) return;
|
||||
if (!event.currentTarget.files[0]) return;
|
||||
|
||||
// const uploadService = new UploadService();
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append("file", event.currentTarget.files[0]);
|
||||
try {
|
||||
onUploadStart(getFileNameFromInput(event.currentTarget.files[0].name));
|
||||
// const result = await uploadService.uploadAudio(
|
||||
// mixId,
|
||||
// formData,
|
||||
// onUploadProgress
|
||||
// );
|
||||
onUploadComplete();
|
||||
} catch (err) {
|
||||
console.error("Upload", "Error", err);
|
||||
onError(
|
||||
"Error uploading file, please refresh your browser and try again!"
|
||||
);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="shadow-cocoa-100 rounded-2xl p-4 shadow-md dark:shadow-gray-400">
|
||||
<div className="flex items-center">
|
||||
<div className="bg-cocoa-500 dark:bg-cerise-400 inline-flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-lg text-white">
|
||||
<FaFileAudio className="h-8 w-8" fill="currentColor" />
|
||||
</div>
|
||||
<div className="ml-3 flex-shrink-0">
|
||||
<span className="text-2xl font-bold leading-none text-gray-900 dark:text-gray-200 sm:text-3xl">
|
||||
Choose your file
|
||||
</span>
|
||||
<h3 className="text-base font-normal text-gray-500">
|
||||
And we‘ll do our best to process it.
|
||||
</h3>
|
||||
</div>
|
||||
<div className="ml-5 flex w-0 flex-1 items-center justify-end text-base font-bold">
|
||||
<label className="text-blue border-blue hover:bg-blue flex w-64 cursor-pointer flex-col items-center rounded-lg border bg-white px-4 py-6 uppercase tracking-wide text-gray-600 shadow-lg hover:text-gray-400">
|
||||
<VscCloudUpload className="h-8 w-8" fill="currentColor" />
|
||||
<span className="mt-2 text-base leading-normal">Browse</span>
|
||||
<input
|
||||
type="file"
|
||||
className="hidden"
|
||||
onChange={(e) => {
|
||||
startUpload(e).catch((err) => {
|
||||
console.error("FileUpload", "Error starting upload", err);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
};
|
||||
export default FileUpload;
|
||||
87
src/lib/components/widgets/ImageUpload.tsx
Normal file
87
src/lib/components/widgets/ImageUpload.tsx
Normal file
@@ -0,0 +1,87 @@
|
||||
/* eslint-disable @next/next/no-img-element */
|
||||
import React from "react";
|
||||
import Dropzone, { DropzoneRef, useDropzone } from "react-dropzone";
|
||||
|
||||
type ImageUploadProps = {
|
||||
onImageChanged: (newImage: File | undefined) => void;
|
||||
};
|
||||
const ImageUpload = ({ onImageChanged }: ImageUploadProps) => {
|
||||
const dropzoneRef = React.createRef<DropzoneRef>();
|
||||
|
||||
return (
|
||||
<Dropzone
|
||||
accept={{
|
||||
"image/png": [".png"],
|
||||
"image/jpg": [".jpg", ".jpeg"],
|
||||
}}
|
||||
maxFiles={1}
|
||||
ref={dropzoneRef}
|
||||
onDrop={(acceptedFiles) => {
|
||||
onImageChanged(
|
||||
acceptedFiles.length !== 0 ? acceptedFiles[0] : undefined
|
||||
);
|
||||
}}
|
||||
>
|
||||
{({ getRootProps, getInputProps, acceptedFiles }) => {
|
||||
return (
|
||||
<div className="container">
|
||||
<div {...getRootProps({ className: "dropzone" })}>
|
||||
{acceptedFiles?.length ? (
|
||||
<div id="preview">
|
||||
{acceptedFiles[0] && (
|
||||
<img
|
||||
className="object-cover"
|
||||
src={URL.createObjectURL(acceptedFiles[0])}
|
||||
alt="image preview"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div id="drop">
|
||||
<div className="flex w-full items-center justify-center">
|
||||
<label
|
||||
htmlFor="dropzone-file"
|
||||
className="dark:hover:bg-bray-800 flex h-64 w-full cursor-pointer flex-col items-center justify-center rounded-lg border-2 border-dashed border-gray-300 bg-gray-50 hover:bg-gray-100 dark:border-gray-600 dark:bg-slate-700 dark:hover:border-gray-500 dark:hover:bg-gray-600"
|
||||
>
|
||||
<div className="flex flex-col items-center justify-center pb-6 pt-5">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="mb-3 h-10 w-10 text-gray-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"
|
||||
></path>
|
||||
</svg>
|
||||
<p className="mb-2 text-sm text-gray-500 dark:text-gray-400">
|
||||
<span className="font-semibold">Click to upload</span>
|
||||
or drag and drop
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||
SVG, PNG, JPG or GIF (MAX. 800x400px)
|
||||
</p>
|
||||
</div>
|
||||
<input
|
||||
{...getInputProps()}
|
||||
id="dropzone-file"
|
||||
type="file"
|
||||
className="hidden"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Dropzone>
|
||||
);
|
||||
};
|
||||
export default ImageUpload;
|
||||
33
src/lib/components/widgets/Loading.tsx
Normal file
33
src/lib/components/widgets/Loading.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import React from "react";
|
||||
|
||||
interface ILoadingProps {
|
||||
message?: string;
|
||||
}
|
||||
const Loading = ({ message = "" }: ILoadingProps) => {
|
||||
return (
|
||||
<>
|
||||
<div role="status" className="mr-3 flex flex-row space-x-1">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="mr-2 h-5 w-5 animate-spin fill-blue-600 text-gray-200 dark:text-gray-600"
|
||||
viewBox="0 0 100 101"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Loading...</span>
|
||||
<span className="text-sm text-gray-700">{message}</span>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Loading;
|
||||
16
src/lib/components/widgets/PageHeader.tsx
Normal file
16
src/lib/components/widgets/PageHeader.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
|
||||
type PageHeaderProps = {
|
||||
title: string;
|
||||
buttons?: React.ReactNode[];
|
||||
};
|
||||
const PageHeader = ({ title, buttons = [] }: PageHeaderProps) => {
|
||||
return (
|
||||
<div className="flex flex-row border-b-2 pb-2 text-gray-800 dark:text-white ">
|
||||
<h2 className="flex-grow text-2xl font-bold">{title}</h2>
|
||||
<div id="button-bar">{buttons}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageHeader;
|
||||
29
src/lib/components/widgets/Progress.tsx
Normal file
29
src/lib/components/widgets/Progress.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from "react";
|
||||
|
||||
type ProgressProps = {
|
||||
title: string;
|
||||
percentage: number;
|
||||
};
|
||||
export const Progress = ({ title, percentage }: ProgressProps) => {
|
||||
return (
|
||||
<div className="flex w-full flex-col p-4">
|
||||
<div className="mb-1 flex justify-between">
|
||||
<span className="text-base font-medium text-fuchsia-700 dark:text-white">
|
||||
{title}
|
||||
</span>
|
||||
<span className="text-sm font-medium text-fuchsia-700 dark:text-white">
|
||||
{percentage}%
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="h-2.5 w-full rounded-full bg-gray-200 dark:bg-slate-700">
|
||||
<div
|
||||
className="h-2.5 rounded-full bg-blue-600"
|
||||
style={{ width: `${percentage}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Progress;
|
||||
49
src/lib/components/widgets/UserImage.tsx
Normal file
49
src/lib/components/widgets/UserImage.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import Image from "next/image";
|
||||
import React, { ComponentProps, PropsWithChildren } from "react";
|
||||
import classNames from "classnames";
|
||||
export interface AvatarSizes {
|
||||
xs: string;
|
||||
sm: string;
|
||||
md: string;
|
||||
lg: string;
|
||||
xl: string;
|
||||
[key: string]: string;
|
||||
}
|
||||
interface IUserImageProps {
|
||||
src: string;
|
||||
status?: "online" | "offline" | "donotdisturb" | "gone";
|
||||
size?: keyof AvatarSizes;
|
||||
}
|
||||
const sizes: AvatarSizes = {
|
||||
xs: "w-4 h-4",
|
||||
sm: "w-8 h-8",
|
||||
md: "w-10 h-10",
|
||||
lg: "w-12 h-14",
|
||||
xl: "w-14 h-14",
|
||||
};
|
||||
const UserImage: React.FC<IUserImageProps> = ({
|
||||
src,
|
||||
status = "gone",
|
||||
size = "md",
|
||||
}) => {
|
||||
const imgClassName = classNames(sizes[size]);
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"flex items-center justify-center space-x-4 rounded-full"
|
||||
)}
|
||||
>
|
||||
<div className="relative">
|
||||
<Image
|
||||
width={40}
|
||||
height={40}
|
||||
src={src}
|
||||
alt="Profile Image"
|
||||
className={classNames("rounded-full", imgClassName)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UserImage;
|
||||
15
src/lib/services/utils/fileUtils.ts
Normal file
15
src/lib/services/utils/fileUtils.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
const getFileExtension = (fileName: string): string =>
|
||||
fileName.split(".").pop() as string;
|
||||
|
||||
const getFileNameFromInput = (fullPath: string): string => {
|
||||
const startIndex =
|
||||
fullPath.indexOf("\\") >= 0
|
||||
? fullPath.lastIndexOf("\\")
|
||||
: fullPath.lastIndexOf("/");
|
||||
let filename = fullPath.substring(startIndex);
|
||||
if (filename.indexOf("\\") === 0 || filename.indexOf("/") === 0) {
|
||||
filename = filename.substring(1);
|
||||
}
|
||||
return filename.replace(/\.[^/.]+$/, "");
|
||||
};
|
||||
export { getFileExtension, getFileNameFromInput };
|
||||
@@ -1,16 +0,0 @@
|
||||
import { type AppType } from "next/app";
|
||||
|
||||
import { api } from "@/lib/utils/api";
|
||||
|
||||
import "@/styles/globals.css";
|
||||
import { ClerkProvider } from "@clerk/nextjs";
|
||||
|
||||
const MyApp: AppType = ({ Component, pageProps }) => {
|
||||
return (
|
||||
<ClerkProvider {...pageProps}>
|
||||
<Component {...pageProps} />
|
||||
</ClerkProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default api.withTRPC(MyApp);
|
||||
@@ -1,26 +0,0 @@
|
||||
import Navbar from "@/lib/components/layout/Navbar";
|
||||
import { api } from "@/lib/utils/api";
|
||||
import { SignInButton, useUser, UserButton } from "@clerk/nextjs";
|
||||
import { type NextPage } from "next";
|
||||
import Head from "next/head";
|
||||
|
||||
const Home: NextPage = () => {
|
||||
const user = useUser();
|
||||
const { data } = api.mix.getAll.useQuery();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Mixy::Boos</title>
|
||||
<meta name="description" content="Robot Powered Mixes" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<Navbar />
|
||||
<main className="flex min-h-screen flex-col items-center justify-center">
|
||||
<div></div>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
@@ -1,7 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"skipLibCheck": true,
|
||||
@@ -18,8 +22,15 @@
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
".eslintrc.cjs",
|
||||
@@ -27,7 +38,10 @@
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.cjs",
|
||||
"**/*.mjs"
|
||||
"**/*.mjs",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user