base page

This commit is contained in:
prabidhi 2025-12-10 12:34:05 +05:45
parent 8b898e1228
commit 2e7ba45484
17 changed files with 713 additions and 13 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1 @@
<svg xmlns='http://www.w3.org/2000/svg' width='750' height='625' viewBox='0 0 1080 900'><rect fill='#F6F8FF' width='1080' height='900'/><g fill-opacity='0.02'><polygon fill='#444' points='90 150 0 300 180 300'/><polygon points='90 150 180 0 0 0'/><polygon fill='#AAA' points='270 150 360 0 180 0'/><polygon fill='#DDD' points='450 150 360 300 540 300'/><polygon fill='#999' points='450 150 540 0 360 0'/><polygon points='630 150 540 300 720 300'/><polygon fill='#DDD' points='630 150 720 0 540 0'/><polygon fill='#444' points='810 150 720 300 900 300'/><polygon fill='#FFF' points='810 150 900 0 720 0'/><polygon fill='#DDD' points='990 150 900 300 1080 300'/><polygon fill='#444' points='990 150 1080 0 900 0'/><polygon fill='#DDD' points='90 450 0 600 180 600'/><polygon points='90 450 180 300 0 300'/><polygon fill='#666' points='270 450 180 600 360 600'/><polygon fill='#AAA' points='270 450 360 300 180 300'/><polygon fill='#DDD' points='450 450 360 600 540 600'/><polygon fill='#999' points='450 450 540 300 360 300'/><polygon fill='#999' points='630 450 540 600 720 600'/><polygon fill='#FFF' points='630 450 720 300 540 300'/><polygon points='810 450 720 600 900 600'/><polygon fill='#DDD' points='810 450 900 300 720 300'/><polygon fill='#AAA' points='990 450 900 600 1080 600'/><polygon fill='#444' points='990 450 1080 300 900 300'/><polygon fill='#222' points='90 750 0 900 180 900'/><polygon points='270 750 180 900 360 900'/><polygon fill='#DDD' points='270 750 360 600 180 600'/><polygon points='450 750 540 600 360 600'/><polygon points='630 750 540 900 720 900'/><polygon fill='#444' points='630 750 720 600 540 600'/><polygon fill='#AAA' points='810 750 720 900 900 900'/><polygon fill='#666' points='810 750 900 600 720 600'/><polygon fill='#999' points='990 750 900 900 1080 900'/><polygon fill='#999' points='180 0 90 150 270 150'/><polygon fill='#444' points='360 0 270 150 450 150'/><polygon fill='#FFF' points='540 0 450 150 630 150'/><polygon points='900 0 810 150 990 150'/><polygon fill='#222' points='0 300 -90 450 90 450'/><polygon fill='#FFF' points='0 300 90 150 -90 150'/><polygon fill='#FFF' points='180 300 90 450 270 450'/><polygon fill='#666' points='180 300 270 150 90 150'/><polygon fill='#222' points='360 300 270 450 450 450'/><polygon fill='#FFF' points='360 300 450 150 270 150'/><polygon fill='#444' points='540 300 450 450 630 450'/><polygon fill='#222' points='540 300 630 150 450 150'/><polygon fill='#AAA' points='720 300 630 450 810 450'/><polygon fill='#666' points='720 300 810 150 630 150'/><polygon fill='#FFF' points='900 300 810 450 990 450'/><polygon fill='#999' points='900 300 990 150 810 150'/><polygon points='0 600 -90 750 90 750'/><polygon fill='#666' points='0 600 90 450 -90 450'/><polygon fill='#AAA' points='180 600 90 750 270 750'/><polygon fill='#444' points='180 600 270 450 90 450'/><polygon fill='#444' points='360 600 270 750 450 750'/><polygon fill='#999' points='360 600 450 450 270 450'/><polygon fill='#666' points='540 600 630 450 450 450'/><polygon fill='#222' points='720 600 630 750 810 750'/><polygon fill='#FFF' points='900 600 810 750 990 750'/><polygon fill='#222' points='900 600 990 450 810 450'/><polygon fill='#DDD' points='0 900 90 750 -90 750'/><polygon fill='#444' points='180 900 270 750 90 750'/><polygon fill='#FFF' points='360 900 450 750 270 750'/><polygon fill='#AAA' points='540 900 630 750 450 750'/><polygon fill='#FFF' points='720 900 810 750 630 750'/><polygon fill='#222' points='900 900 990 750 810 750'/><polygon fill='#222' points='1080 300 990 450 1170 450'/><polygon fill='#FFF' points='1080 300 1170 150 990 150'/><polygon points='1080 600 990 750 1170 750'/><polygon fill='#666' points='1080 600 1170 450 990 450'/><polygon fill='#DDD' points='1080 900 1170 750 990 750'/></g></svg>

View File

@ -1,11 +1,7 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import { RouterView } from "vue-router";
</script>
<template>
<h1>You did it!</h1>
<p>
Visit <a href="https://vuejs.org/" target="_blank" rel="noopener">vuejs.org</a> to read the
documentation
</p>
<RouterView />
</template>
<style scoped></style>

View File

@ -0,0 +1,14 @@
@keyframes popUp {
0% {
transform: scale(0.5);
opacity: 0;
}
100% {
transform: scale(1);
opacity: 1;
}
}
.icon-pop-up {
animation: popUp 0.5s ease-out forwards;
}

242
src/assets/css/font.css Normal file
View File

@ -0,0 +1,242 @@
/* cyrillic-ext */
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO5CnqEu92Fr1Mu53ZEC9_Vu3r1gIhOszmkC3kaWzU.woff2) format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO5CnqEu92Fr1Mu53ZEC9_Vu3r1gIhOszmkAnkaWzU.woff2) format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO5CnqEu92Fr1Mu53ZEC9_Vu3r1gIhOszmkCnkaWzU.woff2) format("woff2");
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO5CnqEu92Fr1Mu53ZEC9_Vu3r1gIhOszmkBXkaWzU.woff2) format("woff2");
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* math */
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO5CnqEu92Fr1Mu53ZEC9_Vu3r1gIhOszmkenkaWzU.woff2) format("woff2");
unicode-range:
U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333,
U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1,
U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071,
U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F,
U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B,
U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF,
U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11,
U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
}
/* symbols */
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO5CnqEu92Fr1Mu53ZEC9_Vu3r1gIhOszmkaHkaWzU.woff2) format("woff2");
unicode-range:
U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199,
U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF,
U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB,
U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3,
U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E,
U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2,
U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F,
U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3,
U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6,
U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513,
U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD,
U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC,
U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB,
U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C,
U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
}
/* vietnamese */
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO5CnqEu92Fr1Mu53ZEC9_Vu3r1gIhOszmkCXkaWzU.woff2) format("woff2");
unicode-range:
U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304,
U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO5CnqEu92Fr1Mu53ZEC9_Vu3r1gIhOszmkCHkaWzU.woff2) format("woff2");
unicode-range:
U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Roboto";
font-style: italic;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO5CnqEu92Fr1Mu53ZEC9_Vu3r1gIhOszmkBnka.woff2) format("woff2");
unicode-range:
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3GUBGEe.woff2) format("woff2");
unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3iUBGEe.woff2) format("woff2");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3CUBGEe.woff2) format("woff2");
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3-UBGEe.woff2) format("woff2");
unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* math */
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMawCUBGEe.woff2) format("woff2");
unicode-range:
U+0302-0303, U+0305, U+0307-0308, U+0310, U+0312, U+0315, U+031A, U+0326-0327, U+032C, U+032F-0330, U+0332-0333,
U+0338, U+033A, U+0346, U+034D, U+0391-03A1, U+03A3-03A9, U+03B1-03C9, U+03D1, U+03D5-03D6, U+03F0-03F1,
U+03F4-03F5, U+2016-2017, U+2034-2038, U+203C, U+2040, U+2043, U+2047, U+2050, U+2057, U+205F, U+2070-2071,
U+2074-208E, U+2090-209C, U+20D0-20DC, U+20E1, U+20E5-20EF, U+2100-2112, U+2114-2115, U+2117-2121, U+2123-214F,
U+2190, U+2192, U+2194-21AE, U+21B0-21E5, U+21F1-21F2, U+21F4-2211, U+2213-2214, U+2216-22FF, U+2308-230B,
U+2310, U+2319, U+231C-2321, U+2336-237A, U+237C, U+2395, U+239B-23B7, U+23D0, U+23DC-23E1, U+2474-2475, U+25AF,
U+25B3, U+25B7, U+25BD, U+25C1, U+25CA, U+25CC, U+25FB, U+266D-266F, U+27C0-27FF, U+2900-2AFF, U+2B0E-2B11,
U+2B30-2B4C, U+2BFE, U+3030, U+FF5B, U+FF5D, U+1D400-1D7FF, U+1EE00-1EEFF;
}
/* symbols */
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMaxKUBGEe.woff2) format("woff2");
unicode-range:
U+0001-000C, U+000E-001F, U+007F-009F, U+20DD-20E0, U+20E2-20E4, U+2150-218F, U+2190, U+2192, U+2194-2199,
U+21AF, U+21E6-21F0, U+21F3, U+2218-2219, U+2299, U+22C4-22C6, U+2300-243F, U+2440-244A, U+2460-24FF,
U+25A0-27BF, U+2800-28FF, U+2921-2922, U+2981, U+29BF, U+29EB, U+2B00-2BFF, U+4DC0-4DFF, U+FFF9-FFFB,
U+10140-1018E, U+10190-1019C, U+101A0, U+101D0-101FD, U+102E0-102FB, U+10E60-10E7E, U+1D2C0-1D2D3,
U+1D2E0-1D37F, U+1F000-1F0FF, U+1F100-1F1AD, U+1F1E6-1F1FF, U+1F30D-1F30F, U+1F315, U+1F31C, U+1F31E,
U+1F320-1F32C, U+1F336, U+1F378, U+1F37D, U+1F382, U+1F393-1F39F, U+1F3A7-1F3A8, U+1F3AC-1F3AF, U+1F3C2,
U+1F3C4-1F3C6, U+1F3CA-1F3CE, U+1F3D4-1F3E0, U+1F3ED, U+1F3F1-1F3F3, U+1F3F5-1F3F7, U+1F408, U+1F415, U+1F41F,
U+1F426, U+1F43F, U+1F441-1F442, U+1F444, U+1F446-1F449, U+1F44C-1F44E, U+1F453, U+1F46A, U+1F47D, U+1F4A3,
U+1F4B0, U+1F4B3, U+1F4B9, U+1F4BB, U+1F4BF, U+1F4C8-1F4CB, U+1F4D6, U+1F4DA, U+1F4DF, U+1F4E3-1F4E6,
U+1F4EA-1F4ED, U+1F4F7, U+1F4F9-1F4FB, U+1F4FD-1F4FE, U+1F503, U+1F507-1F50B, U+1F50D, U+1F512-1F513,
U+1F53E-1F54A, U+1F54F-1F5FA, U+1F610, U+1F650-1F67F, U+1F687, U+1F68D, U+1F691, U+1F694, U+1F698, U+1F6AD,
U+1F6B2, U+1F6B9-1F6BA, U+1F6BC, U+1F6C6-1F6CF, U+1F6D3-1F6D7, U+1F6E0-1F6EA, U+1F6F0-1F6F3, U+1F6F7-1F6FC,
U+1F700-1F7FF, U+1F800-1F80B, U+1F810-1F847, U+1F850-1F859, U+1F860-1F887, U+1F890-1F8AD, U+1F8B0-1F8BB,
U+1F8C0-1F8C1, U+1F900-1F90B, U+1F93B, U+1F946, U+1F984, U+1F996, U+1F9E9, U+1FA00-1FA6F, U+1FA70-1FA7C,
U+1FA80-1FA89, U+1FA8F-1FAC6, U+1FACE-1FADC, U+1FADF-1FAE9, U+1FAF0-1FAF8, U+1FB00-1FBFF;
}
/* vietnamese */
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3OUBGEe.woff2) format("woff2");
unicode-range:
U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304,
U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3KUBGEe.woff2) format("woff2");
unicode-range:
U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: "Roboto";
font-style: normal;
font-weight: 100 900;
font-stretch: 100%;
font-display: swap;
src: url(https://fonts.gstatic.com/s/roboto/v47/KFO7CnqEu92Fr1ME7kSn66aGLdTylUAMa3yUBA.woff2) format("woff2");
unicode-range:
U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F,
U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
body {
font-family: "Roboto", sans-serif !important;
}

5
src/assets/css/main.css Normal file
View File

@ -0,0 +1,5 @@
@import "./tailwind.css";
@import "dolphin-components/dolphin-components.css";
@import "./font.css";
@import "./animation.css";

View File

@ -0,0 +1,46 @@
@import "tailwindcss";
@theme {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-modal: var(--card);
--color-modal-foreground: var(--card-foreground);
--color-modal: var(--card);
--color-modal-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-border: var(--border);
--color-border-foreground: var(--border-foreground);
--color-input: var(--input);
--color-input-focus: var(--input-focus);
--color-sidebar: var(--sidebar);
--color-scrollbar: var(--scrollbar);
--radius-default: var(--radius);
}
@layer base {
*,
::after,
::before,
::backdrop,
::file-selector-button {
border-color: var(--color-gray-200, currentColor);
}
}

0
src/assets/ts/main.ts Normal file
View File

View File

@ -0,0 +1,12 @@
<template>
<div>
<div
class="absolute w-[100%] z-2 border-t border-gray-200 bg-white bottom-0 text-[13px] p-1 text-end px-2 h-[30px]"
>
<span style="font-family: &quot;Raleway&quot;, sans-serif" class="font-bold">©</span>
2025, Mavorion Systems. All rights reserved.
</div>
</div>
</template>

View File

@ -0,0 +1,116 @@
<template>
<nav class="header-container">
<div class="px-[15px] flex justify-between items-center w-full h-full relative">
<div class="">
<img src="/img/Dolphin/dolphin-logo.png" alt="" class="w-32 my-auto" />
</div>
<div class="relative select-none" id="modal-div-nav-profile">
<div
class="w-[32px] rounded-full text-white h-[32px] flex justify-center bg-primary cursor-pointer"
@click="isUserMenuOpen = !isUserMenuOpen"
>
<span v-if="user.avatar" class="h-fit my-auto text-[16px]">
<img
:src="user.avatar"
alt="Profile photo"
class="w-[32px] h-[32px] object-cover rounded-full"
/>
</span>
<span v-else class="h-fit my-auto text-[16px]">
{{ getNameInitials(user.full_name || user.username) }}
</span>
</div>
<div
v-if="isUserMenuOpen"
class="absolute bg-white right-0 w-[200px] border shadow-sm"
tabindex="0"
ref="userProfileMenu"
>
<div>
<div class="px-[15px] py-[5px] border-b">
<div class="text-[12px] font-bold">Account</div>
<div class="flex gap-[5px]">
<div
class="text-white w-[24px] h-[24px] rounded-full flex justify-center item-center bg-primary"
@click="action('profile')"
>
<span v-if="user.avatar" class="h-fit my-auto text-[14px]">
<img
:src="user.avatar"
alt="Profile photo"
class="w-[24px] h-[24px] object-cover rounded-full"
/>
</span>
<span v-else class="h-fit my-auto text-[12px]">
{{ getNameInitials(user.full_name || user.username) }}
</span>
</div>
<div>
<div>{{ user.full_name || user.username }}</div>
<div class="text-[12px] text-secondary-foreground">{{ user.email }}</div>
</div>
</div>
</div>
<div
class="px-[15px] py-[5px] hover:bg-secondary cursor-pointer text-red-500"
@click="action('logout')"
>
Logout
</div>
</div>
</div>
</div>
</div>
</nav>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import { storeToRefs } from "pinia";
import { useAuth } from "@/stores/User/Auth";
import { useUser } from "@/stores/User/User";
const authStore = useAuth();
const userStore = useUser();
const { getUser: user } = storeToRefs(userStore);
const isUserMenuOpen = ref(false);
const getNameInitials = (name: string): string => {
if (!name) return '';
const names = name.trim().split(' ');
if (names.length === 1) {
return names[0].charAt(0).toUpperCase();
}
return (names[0].charAt(0) + names[names.length - 1].charAt(0)).toUpperCase();
};
function handleDocumentClick(event: any) {
const element = document.getElementById("modal-div-nav-profile");
if (isUserMenuOpen.value && !(event.target == element || element?.contains(event.target))) {
isUserMenuOpen.value = false;
}
}
onMounted(async () => {
document.addEventListener("click", handleDocumentClick);
});
onUnmounted(async () => {
document.removeEventListener("click", handleDocumentClick);
});
const action = (type: string) => {
switch (type) {
case "logout":
authStore.logout();
break;
}
isUserMenuOpen.value = false;
};
</script>

View File

@ -0,0 +1,195 @@
<template>
<div class="sidebar-container">
<aside
class="fixed left-0 z-50 w-[45px] h-screen transition-transform border-r select-none group hover:bg-secondary-10 cursor-pointer"
v-if="!isSidebarOpen"
@click="toggleSideBar"
>
<svg
data-v-3005ba44=""
class="mt-[15px] group-hover:fill-secondary-600 fill-secondary-400 mx-auto"
aria-hidden="true"
focusable="false"
width="20px"
height="20px"
data-prefix="fas"
data-icon="bars"
role="img"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 448 512"
data-fa-i2svg=""
>
<path
d="M0 96C0 78.3 14.3 64 32 64H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32C14.3 128 0 113.7 0 96zM0 256c0-17.7 14.3-32 32-32H416c17.7 0 32 14.3 32 32s-14.3 32-32 32H32c-17.7 0-32-14.3-32-32zM448 416c0 17.7-14.3 32-32 32H32c-17.7 0-32-14.3-32-32s14.3-32 32-32H416c17.7 0 32 14.3 32 32z"
></path>
</svg>
</aside>
<aside
id="logo-sidebar"
class="sidebar fixed left-0 z-1 w-[225px] h-screen transition-transform border-r border-gray-200 overflow-y-scroll overflow-x-hidden"
:class="isSidebarOpen ? '' : '-translate-x-full'"
aria-label="Sidebar"
v-hide-scrollbar
>
<div class="sidebar-items pb-[95px]">
<div class="absolute right-4">
<svg
@click="toggleSideBar"
class="stroke-secondary-700 hover:stroke-primary-700 duration-200 cursor-pointer"
width="25px"
height="25px"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g id="SVGRepo_iconCarrier">
<path
d="M6 12H18M6 12L11 7M6 12L11 17"
stroke-width="1.584"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
</svg>
</div>
<div v-for="(item, index) in sidebarItems">
<div
class="sidebar-header"
v-if="!item.to && !item.children && (item.isVisible != undefined ? item.isVisible : true)"
>
{{ item.label }}
</div>
<RouterLink
:to="item.to"
v-if="item.to && !item.children && (item.isVisible != undefined ? item.isVisible : true)"
class="sidebar-default"
:class="isActive(item) ? 'sidebar-item-active' : ''"
@click="closeAllDropdowns()"
>
<div>
<Icons :name="item.icon" size="20" />
</div>
<span>{{ item.label }}</span>
</RouterLink>
<div
v-if="item.children && !item.to && (item.isVisible != undefined ? item.isVisible : true)"
class="sidebar-dropdown"
:class="activeDropdown == index ? 'sidebar-item-open' : ''"
>
<div class="sidebar-dropdown-header" @click="toggleDropdown(index)">
<div>
<Icons :name="item.icon" size="20" />
</div>
<span>{{ item.label }}</span>
<div class="sidebar-chevron">
<Icons name="ChevronRight" size="14" />
</div>
</div>
<div
class="sidebar-dropdown-items"
v-if="activeDropdown == index && isSidebarOpen"
v-animate-dropdown
>
<div class="sidebar-dropdown-item" v-for="childitem in item.children">
<RouterLink
:to="childitem.to"
:class="isActive(childitem) ? 'sidebar-item-active' : ''"
v-if="childitem.isVisible != undefined ? childitem.isVisible : true"
>
<span>{{ childitem.label }}</span>
</RouterLink>
</div>
</div>
</div>
</div>
</div>
</aside>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, type PropType, ref } from "vue";
import { useRouter } from "vue-router";
import type { SidebarItem } from "@/dtos/common/Sidebar";
import { useSidebar } from "@/stores/App/App";
import { storeToRefs } from "pinia";
import { watch, nextTick } from "vue";
const router = useRouter();
const emit = defineEmits(["toggleSideBar"]);
const sidebarStore = useSidebar();
const { isSidebarOpen } = storeToRefs(sidebarStore);
const props = defineProps({
sidebarItems: {
type: Array as PropType<SidebarItem[]>,
required: true,
},
});
const toggleSideBar = () => {
sidebarStore.setSidebarStatus(!isSidebarOpen.value);
};
const activeDropdown = ref(-1);
const closeAllDropdowns = () => {
activeDropdown.value = -1;
};
const toggleDropdown = (val: number) => {
if (activeDropdown.value == val) {
activeDropdown.value = -1;
} else {
activeDropdown.value = val;
}
};
const isActive = (item: SidebarItem) => {
if (item.to == router.currentRoute.value.path) {
return true;
}
};
onMounted(() => {
checkDropDown();
});
const checkDropDown = () => {
if (props.sidebarItems) {
props.sidebarItems.forEach((item) => {
if (item.children && !item.to && (item.isVisible != undefined ? item.isVisible : true)) {
item.children.forEach((child) => {
if (
child.to == router.currentRoute.value.path &&
(child.isVisible != undefined ? child.isVisible : true)
) {
toggleDropdown(props.sidebarItems.indexOf(item));
}
});
}
});
}
};
watch(isSidebarOpen, (newVal) => {
if (newVal) {
nextTick(() => {
const sidebar = document.getElementById("logo-sidebar");
sidebar?.dispatchEvent(new Event("scroll"));
});
}
});
</script>
<style scoped>
#logo-sidebar {
scrollbar-width: thick;
}
#logo-sidebar::-webkit-scrollbar {
width: 10px !important;
}
</style>

View File

@ -0,0 +1,32 @@
<template>
<div class="app-container" :class="isSidebarOpen ? 'sidebar-open' : 'sidebar-close'">
<Navbar></Navbar>
<div class="body-container">
<Sidebar
:sidebarItems="SidebarItems"
@notVisible="sidebarVisible = false"
@visible="sidebarVisible = true"
></Sidebar>
<div class="main-container" :class="sidebarVisible ? '' : 'pl-0'">
<div class="relative">
<RouterView />
</div>
</div>
</div>
<Footer></Footer>
</div>
</template>
<script setup lang="ts">
import Sidebar from "@/components/navigation/Sidebar.vue";
import Navbar from "@/components/navigation/Navbar.vue";
import { ref, computed } from "vue";
import { useSidebarItems } from "@/utils/setup/SidebarItems";
import Footer from "@/components/navigation/Footer.vue";
import { useSidebar } from "@/stores/App/App";
import { storeToRefs } from "pinia";
const SidebarItems = computed(() => useSidebarItems());
const sidebarStore = useSidebar();
const { isSidebarOpen } = storeToRefs(sidebarStore);
const sidebarVisible = ref(true);
</script>

View File

@ -0,0 +1,7 @@
import type { RouteRecordRaw } from "vue-router";
// import { PERMISSIONS } from "@/constants/permissions";
const authChildren: Array<RouteRecordRaw> = [
];
export default authChildren;

View File

@ -1,8 +1,35 @@
import { createRouter, createWebHistory } from 'vue-router'
import { createRouter, createWebHistory } from "vue-router";
import authChildren from "./authChildren";
// import { PERMISSIONS } from "@/constants/permissions";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [],
})
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: "/",
name: "authLayout",
component: () => import("@/layouts/AuthLayout.vue"),
meta: {
requireAuth: true,
},
children: authChildren,
},
// {
// path: "/login",
// name: "login",
// component: () => import("@/views/Auth/Login.vue"),
// },
// {
// path: "/:pathMatch(.*)*",
// name: "404",
// component: () => import("@/views/404.vue"),
// },
// {
// path: "/403",
// name: "403",
// component: () => import("@/views/403.vue"),
// },
],
});
export default router
export default router;

View File

@ -3,16 +3,23 @@ import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
import tailwindcss from "@tailwindcss/vite";
// https://vite.dev/config/
export default defineConfig({
base: '/',
plugins: [
vue(),
vueDevTools(),
tailwindcss(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
server: {
port: 3000,
hmr: true,
},
})