major redesign: move to rounded and extra spaceous UI

+ fix `play next` bug
+ add new folder banner image
+ add new now playing component
+ move to gray4 for accent color
+ increase image sizes, for clean UI
This commit is contained in:
geoffrey45 2022-08-18 02:55:46 +03:00
parent a7dc2fa6bd
commit 5476575d10
40 changed files with 339 additions and 328 deletions

View File

@ -12,6 +12,7 @@
"@vueuse/core": "^8.5.0",
"axios": "^0.26.1",
"pinia": "^2.0.17",
"pinia-plugin-persistedstate": "^2.1.1",
"sass": "^1.49.0",
"sass-loader": "^10",
"vite-svg-loader": "^3.4.0",

View File

@ -14,9 +14,10 @@
<div id="acontent" class="rounded">
<router-view />
</div>
<BottomBar />
<SearchInput />
<RightSideBar />
<Tabs />
<!-- <Tabs /> -->
</div>
</template>
@ -33,13 +34,14 @@ import handleShortcuts from "@/composables/useKeyboard";
import Logo from "@/components/Logo.vue";
import Modal from "@/components/modal.vue";
import NavBar from "@/components/nav/NavBar.vue";
import Tabs from "@/components/RightSideBar/Tabs.vue";
// import Tabs from "@/components/RightSideBar/Tabs.vue";
import ContextMenu from "@/components/contextMenu.vue";
import Notification from "@/components/Notification.vue";
import Navigation from "@/components/LeftSidebar/Navigation.vue";
import nowPlaying from "@/components/LeftSidebar/nowPlaying.vue";
import RightSideBar from "@/components/RightSideBar/Main.vue";
import SearchInput from "@/components/RightSideBar/SearchInput.vue";
import BottomBar from "@/components/BottomBar/BottomBar.vue";
import { readLocalStorage, writeLocalStorage } from "@/utils";

View File

@ -0,0 +1,98 @@
<svg width="1600" height="548" viewBox="0 0 1600 548" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_7_2)" filter="url(#filter0_d_7_2)">
<path d="M1241.06 372.097L1280.6 358.972C1285.2 357.445 1286.98 353.889 1285.29 348.789L1277.15 324.265C1275.46 319.165 1271.88 317.39 1266.73 319.099L1244.64 326.433C1242.92 327.002 1241.77 326.961 1240.07 326.308L1238.37 325.655C1236.22 324.834 1234.83 324.793 1232.33 325.623L1225.58 327.862C1221.1 329.35 1219.33 332.85 1221 337.878L1230.64 366.93C1232.34 372.054 1235.91 373.806 1241.06 372.097ZM1225.87 336.709C1225.15 334.54 1225.99 332.993 1228.11 332.289L1232.64 330.785C1234.33 330.224 1235.47 330.297 1237.19 330.942L1238.9 331.619C1241.01 332.4 1242.45 332.449 1244.95 331.619L1268 323.968C1270.19 323.24 1271.79 323.981 1272.55 326.269L1273.01 327.675L1227.85 342.667L1225.87 336.709ZM1239.8 367.251C1237.6 367.979 1236.01 367.239 1235.24 364.927L1229.24 346.838L1274.4 331.846L1280.41 349.959C1281.17 352.247 1280.34 353.794 1278.14 354.522L1239.8 367.251Z" fill="#F2F2F2"/>
</g>
<g filter="url(#filter1_d_7_2)">
<path d="M920.83 363.356L946.539 355.986C951.704 354.505 953.602 351.009 952.114 345.819L945.838 323.925C944.876 320.57 943.998 319.149 941.289 317.627L924.921 308.37C922.305 306.899 920.501 306.894 917.483 307.759L905.848 311.095C900.682 312.575 898.785 316.071 900.273 321.261L910.715 357.687C912.21 362.902 915.665 364.837 920.83 363.356ZM919.86 358.514C917.519 359.185 916.007 358.286 915.364 356.041L905.087 320.195C904.45 317.974 905.249 316.386 907.591 315.715L917.874 312.767L921.666 325.995C922.656 329.447 924.847 330.622 928.275 329.639L941.286 325.909L947.3 346.886C947.943 349.131 947.113 350.701 944.772 351.372L919.86 358.514ZM927.519 325.362C926.53 325.646 925.995 325.329 925.711 324.34L922.237 312.222L939.444 321.944L927.519 325.362Z" fill="#F2F2F2"/>
</g>
<g filter="url(#filter2_d_7_2)">
<path d="M920.83 363.356L946.539 355.986C951.704 354.505 953.602 351.009 952.114 345.819L945.838 323.925C944.876 320.57 943.998 319.149 941.289 317.627L924.921 308.37C922.305 306.899 920.501 306.894 917.483 307.759L905.848 311.095C900.682 312.575 898.785 316.071 900.273 321.261L910.715 357.687C912.21 362.902 915.665 364.837 920.83 363.356ZM919.86 358.514C917.519 359.185 916.007 358.286 915.364 356.041L905.087 320.195C904.45 317.974 905.249 316.386 907.591 315.715L917.874 312.767L921.666 325.995C922.656 329.447 924.847 330.622 928.275 329.639L941.286 325.909L947.3 346.886C947.943 349.131 947.113 350.701 944.772 351.372L919.86 358.514ZM927.519 325.362C926.53 325.646 925.995 325.329 925.711 324.34L922.237 312.222L939.444 321.944L927.519 325.362Z" fill="#F2F2F2"/>
</g>
<g filter="url(#filter3_d_7_2)">
<path d="M784.959 386.222L825.55 376.844C830.272 375.753 832.379 372.38 831.169 367.144L825.353 341.967C824.143 336.731 820.745 334.63 815.46 335.851L792.779 341.091C791.017 341.498 789.875 341.35 788.245 340.541L786.615 339.732C784.55 338.714 783.17 338.543 780.601 339.137L773.677 340.736C769.077 341.799 766.983 345.118 768.176 350.281L775.066 380.106C776.282 385.366 779.674 387.443 784.959 386.222ZM773.141 349.572C772.626 347.345 773.603 345.882 775.78 345.379L780.429 344.305C782.166 343.904 783.29 344.082 784.944 344.886L786.58 345.719C788.61 346.694 790.044 346.878 792.613 346.284L816.273 340.818C818.524 340.298 820.043 341.184 820.585 343.533L820.919 344.976L774.554 355.688L773.141 349.572ZM784.152 381.28C781.901 381.8 780.382 380.914 779.834 378.541L775.543 359.97L821.908 349.258L826.204 367.853C826.747 370.202 825.77 371.665 823.52 372.185L784.152 381.28Z" fill="#F2F2F2"/>
</g>
<g clip-path="url(#clip1_7_2)" filter="url(#filter4_d_7_2)">
<path d="M1175.56 503.894L1196.91 519.989C1201.21 523.223 1205.14 522.634 1208.39 518.322L1222.1 500.132C1224.2 497.345 1224.8 495.789 1224.39 492.709L1221.93 474.066C1221.53 471.092 1220.45 469.648 1217.94 467.759L1208.27 460.475C1203.98 457.241 1200.05 457.829 1196.8 462.141L1174 492.404C1170.73 496.736 1171.26 500.66 1175.56 503.894ZM1178.84 500.205C1176.89 498.739 1176.7 496.991 1178.11 495.126L1200.55 465.344C1201.94 463.499 1203.69 463.181 1205.63 464.647L1214.18 471.085L1205.9 482.075C1203.73 484.943 1204.12 487.4 1206.96 489.546L1217.77 497.692L1204.64 515.119C1203.23 516.985 1201.48 517.267 1199.54 515.801L1178.84 500.205ZM1209.92 486.369C1209.1 485.749 1209.03 485.131 1209.65 484.309L1217.24 474.241L1219.83 493.834L1209.92 486.369Z" fill="#F2F2F2"/>
</g>
<g filter="url(#filter5_d_7_2)">
<path d="M1139.29 314.117C1132.34 317.228 1125.57 322.685 1121.15 328.736C1120.32 329.881 1120.52 331.249 1121.6 332.139C1120.46 334.001 1120.66 336.223 1122.27 338.113C1124.35 340.483 1127.29 340.653 1129.65 338.606L1139.05 330.428C1141.39 328.392 1141.58 325.5 1139.53 323.086C1138.67 322.072 1137.62 321.465 1136.52 321.272C1138.09 320.294 1139.7 319.406 1141.33 318.677C1153.86 313.061 1165.63 316.977 1170.78 328.458C1175.92 339.939 1171.02 351.354 1158.49 356.97C1156.86 357.7 1155.14 358.335 1153.35 358.832C1153.92 357.889 1154.16 356.708 1153.99 355.352C1153.56 352.243 1151.28 350.46 1148.2 350.847L1135.84 352.424C1132.71 352.808 1130.91 355.126 1131.29 358.233C1131.63 360.721 1133.16 362.348 1135.28 362.719C1135.25 364.134 1136.14 365.195 1137.55 365.333C1145.01 366.065 1153.6 364.665 1160.54 361.554C1175.83 354.705 1181.74 340.691 1175.34 326.415C1168.95 312.161 1154.57 307.268 1139.29 314.117Z" fill="#333333" fill-opacity="0.01"/>
</g>
<g filter="url(#filter6_d_7_2)">
<path d="M1021.88 49.7976L1032.05 74.5314C1034.09 79.5014 1037.78 81 1042.77 78.9465L1063.84 70.2835C1067.06 68.9559 1068.38 67.9266 1069.59 65.0655L1076.98 47.7724C1078.15 45.0097 1077.96 43.2162 1076.76 40.3132L1072.16 29.1191C1070.12 24.1491 1066.43 22.6505 1061.44 24.704L1026.39 39.1169C1021.38 41.18 1019.83 44.8276 1021.88 49.7976ZM1026.58 48.2971C1025.66 46.0444 1026.38 44.4425 1028.54 43.5542L1063.03 29.3706C1065.17 28.4919 1066.83 29.11 1067.76 31.3627L1071.83 41.2563L1059.1 46.4904C1055.78 47.8562 1054.86 50.1642 1056.21 53.462L1061.36 65.9799L1041.18 74.2799C1039.02 75.1682 1037.37 74.5173 1036.44 72.2646L1026.58 48.2971ZM1060.38 52.2372C1059.99 51.285 1060.24 50.7183 1061.2 50.3267L1072.85 45.532L1065.1 63.71L1060.38 52.2372Z" fill="#F2F2F2"/>
</g>
<defs>
<filter id="filter0_d_7_2" x="1199" y="294" width="109.13" height="109.13" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_7_2"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_7_2" result="shape"/>
</filter>
<filter id="filter1_d_7_2" x="599" y="285" width="376.948" height="240.948" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-274" dy="138"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_7_2"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_7_2" result="shape"/>
</filter>
<filter id="filter2_d_7_2" x="873" y="285" width="106.948" height="106.948" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_7_2"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_7_2" result="shape"/>
</filter>
<filter id="filter3_d_7_2" x="748" y="312" width="103.955" height="103.955" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_7_2"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_7_2" result="shape"/>
</filter>
<filter id="filter4_d_7_2" x="1142" y="435" width="120.036" height="120.036" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_7_2"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_7_2" result="shape"/>
</filter>
<filter id="filter5_d_7_2" x="1033" y="285" width="169.719" height="165.719" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-60" dy="56"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_7_2"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_7_2" result="shape"/>
</filter>
<filter id="filter6_d_7_2" x="999" y="0" width="158.416" height="317.416" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="50" dy="209"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_7_2"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_7_2" result="shape"/>
</filter>
<clipPath id="clip0_7_2">
<rect width="80" height="80" fill="white" transform="translate(1203 319.204) rotate(-18.3641)"/>
</clipPath>
<clipPath id="clip1_7_2">
<rect width="80" height="80" fill="white" transform="translate(1194.15 435) rotate(37)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,6 +1,5 @@
.b-bar {
height: 100%;
padding: $small;
.grid {
background-color: $primary;

View File

@ -6,7 +6,7 @@
"l-sidebar nav search-input"
"l-sidebar content r-sidebar"
"l-sidebar content r-sidebar"
"l-sidebar content tabs";
"l-sidebar content bottombar";
max-width: 2720px;
height: calc(100vh - 1rem);
margin: 0 auto;
@ -19,7 +19,11 @@
@include tablet-landscape {
grid-template-columns: min-content 1fr;
grid-template-areas:
"l-sidebar nav"
"l-sidebar content"
"l-sidebar content"
"l-sidebar bottombar";
.r-sidebar,
#tabs,
#gsearch-input {
@ -32,7 +36,6 @@
grid-area: content;
max-width: 1955px;
overflow: hidden scroll;
margin-top: -$small;
.nav {
margin: $small;
@ -48,7 +51,6 @@
.r-sidebar {
grid-area: r-sidebar;
margin-top: -$small;
}
#gsearch-input {
@ -66,7 +68,6 @@
padding: 1rem;
}
.bottom-bar {
grid-area: bottom-bar;
height: 4rem;
.b-bar {
grid-area: bottombar;
}

View File

@ -24,9 +24,17 @@
}
.rounded {
border-radius: 1rem;
}
.rounded-sm {
border-radius: $small;
}
.rounded-md {
border-radius: $medium;
}
.circular {
border-radius: 20px;
}
@ -36,7 +44,7 @@
}
.bg-black {
background-color: $black;
background-color: $gray4;
box-shadow: 0 0 1rem rgba(0, 0, 0, 0.1);
}
@ -58,8 +66,8 @@ button {
display: flex;
align-items: center;
justify-content: center;
height: 2rem;
background-image: linear-gradient(70deg, $gray3, $gray2);
height: 2.25rem;
background: linear-gradient(70deg, $gray3, $gray2);
&:hover {
background-image: linear-gradient(70deg, #234ece, $darkblue);

View File

@ -3,7 +3,7 @@
padding: $smaller;
}
.pad-small {
.pad-sm {
padding: $small;
}

View File

@ -4,8 +4,8 @@ input[type="range"] {
width: calc(100% - 2px);
height: 0.3rem;
border-radius: 5px;
background-size: 0 100%;
background: $gray linear-gradient($accent, $accent) no-repeat;
background: $gray linear-gradient(90deg, $accent, $accent) no-repeat;
background-size: 100% 100%;
&::-webkit-slider-thumb {
-webkit-appearance: none;
@ -38,15 +38,15 @@ input[type="range"] {
/* Input Thumb */
input[type="range"]::-webkit-slider-thumb:hover {
background: $pink;
background: $accent;
}
input[type="range"]::-moz-range-thumb:hover {
background: $pink;
background: $accent;
}
input[type="range"]::-ms-thumb:hover {
background: $pink;
background: $accent;
}
/* Input Track */

View File

@ -39,7 +39,7 @@ $indigo: #5e5ce6;
$teal: rgb(64, 200, 224);
$primary: $gray4;
$accent: $red;
$accent: $gray1;
$secondary: $gray5;
$cta: $blue;
$danger: $red;
@ -48,7 +48,7 @@ $context: $gray;
// SVG COLORS
$default: $accent;
$track-btn-svg: $red;
$track-btn-svg: $accent;
$side-nav-svg: $red;

View File

@ -4,7 +4,7 @@
ref="albumheaderthing"
:style="{
backgroundImage: `linear-gradient(
37deg, ${props.album.colors[0]}, ${props.album.colors[3]}
37deg, ${album.colors[0]}, ${album.colors[3]}
)`,
}"
>

View File

@ -1,33 +1,72 @@
<template>
<div class="b-bar">
<div class="grid rounded">
<div class="controlsx rounded">
<div class="controls-bottom">
<HotKeys />
<div class="b-bar bg-black pad-medium rounded">
<div class="info">
<img
:src="paths.images.thumb + queue.currenttrack?.image"
alt=""
class="rounded"
/>
<div class="tags">
<div class="np-artist ellip">
<span v-for="artist in putCommas(queue.currenttrack?.artists || ['Artist'])">
{{ artist }}
</span>
</div>
<div class="progress progress-bottom">
<span class="durationx">{{ formatSeconds(q.track.current_time) }}</span>
<Progress />
<span class="durationx">{{ formatSeconds(q.length) }}</span>
</div>
<div class="r-group">
<div id="heart" class="image ctrl-btn"></div>
<div id="add-to" class="image ctrl-btn"></div>
<div id="repeat" class="image ctrl-btn"></div>
<div class="np-title ellip">
{{ queue.currenttrack?.title || "Track title" }}
</div>
</div>
<div class="volume-group"></div>
</div>
<Progress />
</div>
</template>
<script setup lang="ts">
import "@/assets/scss/BottomBar/BottomBar.scss";
import { formatSeconds } from "@/utils";
import HotKeys from "../LeftSidebar/NP/HotKeys.vue";
import { formatSeconds, putCommas } from "@/utils";
import Progress from "../LeftSidebar/NP/Progress.vue";
import useQStore from "@/stores/queue";
import { paths } from "@/config";
const q = useQStore();
const queue = useQStore();
</script>
<style lang="scss">
.b-bar {
display: grid;
grid-template-rows: 1fr max-content;
border-radius: 1rem;
gap: 1rem;
padding: 1rem;
padding-bottom: 2rem;
.info {
display: grid;
grid-template-columns: max-content 1fr;
gap: 1rem;
img {
height: 6rem;
width: auto;
}
.tags {
display: flex;
flex-direction: column;
justify-content: flex-end;
.np-title {
font-size: 1.15rem;
font-weight: bold;
margin-bottom: $small;
}
.np-artist {
opacity: 0.75;
font-size: 0.9rem;
}
}
}
}
</style>

View File

@ -141,8 +141,8 @@ const showContextMenu = (e: Event) => {
font-size: 0.75rem;
width: max-content;
padding: 0.2rem 0.35rem;
top: 14.25rem;
left: 1.5rem;
top: 14rem;
left: 2rem;
background-color: $black;
border-radius: $smaller;
box-shadow: 0rem 0rem 1rem rgba(0, 0, 0, 0.438);

View File

@ -12,14 +12,7 @@
<div class="carddd">
<div class="info">
<div class="btns">
<PlayBtnRect
:source="playSources.playlist"
:store="usePStore"
:background="{
color: '#fff',
isDark: true,
}"
/>
<PlayBtnRect :source="playSources.playlist" :store="usePStore" />
<Option @showDropdown="showDropdown" :src="context.src" />
</div>
<div class="duration">

View File

@ -23,7 +23,7 @@
</TransitionGroup>
</div>
</div>
<PlayingFrom :from="queue.from" />
<!-- <PlayingFrom :from="queue.from" /> -->
</div>
</div>
</template>
@ -87,8 +87,8 @@ onUpdated(() => {
height: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: max-content 1fr max-content;
gap: $small;
grid-template-rows: max-content 1fr;
gap: 1rem;
.scrollable-r {
height: 100%;

View File

@ -1,12 +1,12 @@
<template>
<div
class="next-track bg-black"
class="next-track bg-black rounded"
:class="{ contexton: context_on }"
@click="playNext"
@contextmenu.prevent="showMenu"
>
<div class="nextup abs">next up</div>
<img :src="paths.images.thumb + track?.image" class="rounded" />
<img :src="paths.images.thumb + track?.image" class="rounded-sm" />
<div class="tags">
<div class="title ellip">{{ track?.title || "Don't click here" }}</div>
<div class="artist ellip" v-if="track">
@ -43,13 +43,12 @@ function showMenu(e: Event) {
<style lang="scss">
.next-track {
border-radius: 0.5rem;
position: relative;
display: grid;
grid-template-columns: max-content 1fr;
gap: 1rem;
padding: $small;
padding: 1rem;
width: 100%;
cursor: pointer;

View File

@ -49,7 +49,7 @@ defineProps<{
.search-results-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-columns: repeat(2, 1fr);
gap: 0.75rem;
}
</style>

View File

@ -1,7 +1,7 @@
<template>
<div id="right-tabs" class="bg-black rounded">
<div class="tab-buttons-wrapper">
<div id="tabheaders" class="rounded noscroll">
<div id="tabheaders" class="rounded-sm noscroll">
<div
class="tab"
v-for="slot in $slots.default()"
@ -44,7 +44,7 @@ const s = useSearchStore();
justify-content: space-around;
margin: 1rem;
width: max-content;
background: linear-gradient(37deg, $gray3, $gray4, $gray3);
background: linear-gradient(37deg, $gray1, $gray2, $gray1);
height: 2rem;
& > * {
@ -55,6 +55,7 @@ const s = useSearchStore();
display: flex;
align-items: center;
justify-content: center;
user-select: none;
cursor: pointer;
transition: all 0.3s ease;

View File

@ -1,76 +1,55 @@
<template>
<div id="gsearch-input">
<div
id="gsearch-input"
class="bg-black rounded"
:class="{ 'search-focused': focused }"
>
<div id="ginner" tabindex="0">
<div class="icon image"></div>
<SearchSvg />
<input
id="globalsearch"
class="rounded"
v-model="search.query"
placeholder="Search your library"
type="search"
@focus="focusThis()"
@blur="unfocusThis()"
@focus="focused = true"
@blur="focused = false"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
import { ref } from "vue";
import useSearchStore from "../../stores/search";
import SearchSvg from "../../assets/icons/search.svg";
const search = useSearchStore();
let input: HTMLInputElement;
onMounted(() => {
input = document.getElementById("ginner") as HTMLInputElement;
});
function focusThis() {
input.classList.add("focused");
}
function unfocusThis() {
input.classList.remove("focused");
}
const focused = ref(false);
</script>
<style lang="scss">
#gsearch-input {
display: flex;
height: max-content;
padding: $smaller;
#ginner {
width: 100%;
border-radius: 0.4rem;
position: relative;
display: flex;
background-color: $red;
background-color: $gray4;
.icon {
width: 2.25rem;
aspect-ratio: 1;
background-image: url("../../assets/icons/search.svg");
background-size: 1.5rem;
margin-left: $smaller;
}
align-items: center;
gap: $smaller;
margin-left: $small;
input {
display: flex;
align-items: center;
width: 100%;
border: none;
line-height: 2.25rem;
color: inherit;
font-size: 1rem;
background-color: transparent;
outline: 2px solid transparent;
outline: none;
}
}
.focused {
outline: solid $accent;
}
}
.search-focused {
outline: solid $accent;
}
</style>

View File

@ -8,13 +8,13 @@
v-if="modal.component == modal.options.newPlaylist"
:track="modal.props.track"
@hideModal="hideModal"
@title="title"
@setTitle="setTitle"
/>
<UpdatePlaylist
:playlist="modal.props"
v-if="modal.component == modal.options.updatePlaylist"
@hideModal="hideModal"
@title="title"
@setTitle="setTitle"
/>
<WelcomeModal v-if="modal.component == modal.options.welcome" />
</div>
@ -33,7 +33,7 @@ const modal = useModalStore();
* Sets the modal title
* @param title
*/
function title(title: string) {
function setTitle(title: string) {
console.log(title);
modal.setTitle(title);
}

View File

@ -30,15 +30,15 @@ const route = useRoute();
const playlistStore = usePlaylistStore();
onMounted(() => {
document.getElementById("modal-playlist-name-input").focus();
(document.getElementById("modal-playlist-name-input") as HTMLElement).focus();
});
const emit = defineEmits<{
(e: "title", title: string): void;
(e: "setTitle", title: string): void;
(e: "hideModal"): void;
}>();
emit("title", "New Playlist");
emit("setTitle", "New Playlist");
/**
* Create a new playlist. If this modal is called with a track,

View File

@ -65,15 +65,15 @@ const props = defineProps<{
}>();
onMounted(() => {
document.getElementById("modal-playlist-name-input").focus();
(document.getElementById("modal-playlist-name-input") as HTMLElement).focus();
});
const emit = defineEmits<{
(e: "title", title: string): void;
(e: "setTitle", title: string): void;
(e: "hideModal"): void;
}>();
emit("title", "Update Playlist");
emit("setTitle", "Update Playlist");
function selectFiles() {
const input = document.getElementById(

View File

@ -1,10 +1,7 @@
<template>
<div class="topnav">
<div class="left">
<div class="btn">
<NavButtons />
</div>
<NavButtons />
<div class="info">
<APTitle v-show="showAPTitle" />
<Playlists v-show="$route.name == Routes.playlists" />
@ -15,16 +12,12 @@
<div class="center rounded">
<Loader />
</div>
<!-- <div class="right">
<Search />
</div> -->
</div>
</template>
<script setup lang="ts">
import NavButtons from "./NavButtons.vue";
import Loader from "../shared/Loader.vue";
// import Search from "./Search.vue";
import { useRoute } from "vue-router";
import { ref, watch } from "vue";
import { Routes } from "@/composables/enums";
@ -82,13 +75,11 @@ watch(
display: grid;
grid-template-columns: 1fr min-content;
width: 100%;
gap: 1rem;
overflow: hidden;
.left {
display: grid;
grid-template-columns: max-content 1fr;
overflow: hidden;
gap: 1rem;
.info {
overflow: hidden;
@ -106,11 +97,5 @@ watch(
place-items: center;
margin-right: 1rem;
}
.right {
width: 100%;
display: flex;
gap: $small;
}
}
</style>

View File

@ -1,40 +1,41 @@
<template>
<div id="back-forward">
<div class="back image" @click="$router.back()"></div>
<div class="forward image" @click="$router.forward()"></div>
<div id="back-forward" class="">
<button class="back" @click="$router.back()">
<ArrowSvg />
</button>
<button class="forward" @click="$router.forward()">
<ArrowSvg />
</button>
</div>
</template>
<script setup lang="ts">
import ArrowSvg from "../../assets/icons/right-arrow.svg";
</script>
<style lang="scss">
#back-forward {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
padding-right: 1rem;
margin-right: $small;
padding-right: 1.25rem;
border-right: 1px solid $gray3;
width: 100%;
& > div {
background-color: $gray4;
border-radius: $small;
height: 2.25rem;
width: 2.25rem;
cursor: pointer;
background-size: 2rem;
transition: all .25s ease-in-out;
& > * {
background-color: $gray3;
padding: $small;
height: 100%;
aspect-ratio: 1;
border-radius: $medium;
&:hover {
background-color: $accent;
svg {
margin: auto;
}
}
.back {
background-image: url("../../assets/icons/right-arrow.svg");
transform: rotate(180deg);
}
.forward {
background-image: url("../../assets/icons/right-arrow.svg");
}
}
</style>

View File

@ -47,5 +47,7 @@ const things = computed(() => {
display: flex;
align-items: center;
gap: $small;
outline: solid 1px $gray3;
height: 100%;
}
</style>

View File

@ -1,55 +1,28 @@
<template>
<div
class="p-card rounded"
id="new-playlist-card"
class="p-card new-playlist-card rounded bg-black"
@click="Modal.showNewPlaylistModal()"
>
<div class="gradient rounded"></div>
<div class="plus image p-image"></div>
<div>New Playlist</div>
<div></div>
<PlusSvg />
</div>
</template>
<script setup lang="ts">
import useModalStore from "../../stores/modal";
import PlusSvg from "../../assets/icons/plus.svg";
const Modal = useModalStore();
</script>
<style lang="scss">
#new-playlist-card {
display: grid;
place-items: center;
position: relative;
.new-playlist-card {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
.gradient {
position: absolute;
width: calc(100% - 1.5rem);
top: 0.75rem;
background-image: linear-gradient(37deg, $red, $blue);
background-size: 100%;
transition: all 0.5s ease-in-out;
aspect-ratio: 1;
}
.image {
background-image: url("../../assets/icons/plus.svg");
background-size: 5rem;
z-index: 1;
transition: all 0.5s ease-in-out;
background-color: transparent;
margin-bottom: $small;
}
&:hover {
.gradient {
background-size: 29rem;
}
.image {
transform: rotate(180deg);
}
svg {
transform: scale(3);
}
}
</style>

View File

@ -2,7 +2,7 @@
<router-link
:to="{ name: 'PlaylistView', params: { pid: props.playlist.playlistid } }"
:playlist="props.playlist"
class="p-card rounded"
class="p-card rounded bg-black"
>
<div
class="image p-image rounded shadow-sm"
@ -37,10 +37,9 @@ const props = defineProps<{
<style lang="scss">
.p-card {
width: 100%;
padding: 0.75rem;
padding: 1rem;
transition: all 0.25s ease;
position: relative;
background-color: #1c1c1e80;
.p-image {
min-width: 100%;
@ -72,7 +71,7 @@ const props = defineProps<{
}
&:hover {
background-color: $gray5;
background-color: $gray2;
.drop {
transition-delay: 0.75s;

View File

@ -29,7 +29,6 @@ defineProps<{
display: grid;
gap: $small;
padding: $small;
background-color: $gray4;
transition: all 0.5s ease;
border-radius: .7rem;

View File

@ -32,16 +32,13 @@ defineProps<{
border-radius: 0.75rem;
display: grid;
justify-content: center;
padding: 1rem $small;
cursor: pointer;
.artist-image {
width: 8rem;
height: 8rem;
width: 100%;
border-radius: 60%;
margin-bottom: $small;
transition: all 0.5s ease-in-out;
transition-delay: 0.25s;
object-fit: cover;
}
@ -50,27 +47,5 @@ defineProps<{
border-radius: 20%;
}
}
.artist-name {
margin: 0;
font-size: 0.9rem;
font-weight: 510;
max-width: 7rem;
text-transform: capitalize;
}
}
._is_on_sidebar {
background-color: $gray4 !important;
.artist-image {
width: 7rem;
height: 7rem;
@include for-desktop-down {
width: 6rem;
height: 6rem;
}
}
}
</style>

View File

@ -2,14 +2,18 @@
<div
class="loaderx"
:class="{ loader: loader.loading, not_loader: !loader.loading }"
@click="modal.showSearchModal"
>
<div v-if="!loader.loading">🦋</div>
</div>
</template>
<script setup lang="ts">
import useLoaderStore from "../../stores/loader";
import useLoaderStore from "@/stores/loader";
import useModalStore from "@/stores/modal";
const loader = useLoaderStore();
const modal = useModalStore();
</script>
<style lang="scss">

View File

@ -1,21 +1,12 @@
<template>
<div
class="drop-btn rounded shadow-sm"
id="option-drop"
@click="showDropdown"
>
<div
class="image drop-icon"
:class="{ clicked: clicked && src == ContextSrc.PHeader }"
></div>
</div>
<button id="option-drop" @click.stop.prevent="showDropdown">
<MoreSvg />
</button>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { ContextSrc } from "../../composables/enums";
import { onMounted } from "vue";
import MoreSvg from "../../assets/icons/more.svg";
let elem: DOMRect;
const clicked = ref(false);
defineProps<{
src?: string;
@ -26,47 +17,24 @@ const emit = defineEmits<{
}>();
onMounted(() => {
elem = document.getElementById("option-drop").getBoundingClientRect();
const el = document.getElementById("option-drop") as HTMLElement;
elem = el.getBoundingClientRect();
});
function showDropdown(e: Event) {
e.preventDefault();
e.stopImmediatePropagation();
emit("showDropdown", {
clientX: elem.left + 45,
clientX: elem.left + 35,
clientY: elem.top,
});
clicked.value = true;
}
</script>
<style lang="scss">
.drop-btn {
width: 2.5rem;
background-color: $accent;
transition: all 0.5s ease-in-out;
cursor: pointer;
#option-drop {
display: flex;
align-items: center;
.drop-icon {
transition: all 0.25s;
padding: $small;
height: 2.5rem;
width: 2.5rem;
background-image: url("../../assets/icons/right-arrow.svg");
background-size: 1.75rem;
transform: rotate(90deg);
}
.clicked {
transform: rotate(0deg);
}
&:hover {
background-color: $green;
.image {
transform: rotate(0deg);
}
svg {
transform: scale(1.25);
}
}
</style>

View File

@ -1,8 +1,10 @@
<template>
<div
class="play-btn rounded shadow-sm"
<button
class="play-btn rounded-md"
@click="usePlayFrom(source, useQStore, store)"
></div>
>
<PlaySvg />
</button>
</template>
<script setup lang="ts">
@ -12,24 +14,19 @@ import usePlaylistStore from "@/stores/pages/playlist";
import usePlayFrom from "@/composables/usePlayFrom";
import useQStore from "@/stores/queue";
import PlaySvg from "../../assets/icons/play.svg";
defineProps<{
source: playSources;
store: typeof useAlbumStore | typeof usePlaylistStore;
}>();
</script>
<style lang="scss">
.play-btn {
height: 2.25rem;
background-color: $gray3;
background-image: url("../../assets/icons/play.svg");
background-size: 1.75rem;
background-repeat: no-repeat;
background-position: 50% 50%;
transition: all 0.25s ease-in-out;
height: 100%;
aspect-ratio: 1;
&:hover {
background-color: $accent;
}
display: grid;
place-items: center;
}
</style>

View File

@ -1,15 +1,15 @@
<template>
<div
class="playbtnrect rounded"
<button
class="playbtnrect"
@click="usePlayFrom(source, useQStore, store)"
:style="{
backgroundColor: background.color,
background: background?.color,
}"
:class="{ playbtnrectdark: background.isDark }"
:class="{ playbtnrectdark: background?.isDark }"
>
<playBtnSvg />
<div class="text">Play</div>
</div>
</button>
</template>
<script setup lang="ts">
@ -40,24 +40,9 @@ defineProps<{
width: 6rem;
display: flex;
align-items: center;
height: 2.5rem;
padding-left: 0.75rem;
cursor: pointer;
user-select: none;
color: $white;
justify-content: center;
transition: all 0.5s ease-in-out;
.icon {
height: 2rem;
width: 2rem;
background-image: url("../../assets/icons/play.svg");
}
&:hover {
.icon {
transform: rotate(120deg);
}
}
color: $white;
}
.playbtnrectdark {

View File

@ -19,7 +19,7 @@
loading="lazy"
:src="imguri + track.image"
alt=""
class="album-art image rounded"
class="album-art image rounded-sm"
/>
<div
class="now-playing-track-indicator image"

View File

@ -11,7 +11,7 @@
@contextmenu.prevent="showMenu"
>
<div class="album-art">
<img :src="paths.images.thumb + track.image" alt="" class="rounded" />
<img :src="paths.images.thumb + track.image" alt="" class="rounded-sm" />
<div
class="now-playing-track-indicator image"
v-if="isCurrent"

View File

@ -2,41 +2,36 @@ import { defineStore } from "pinia";
import { Playlist, Track } from "../interfaces";
enum ModalOptions {
newPlaylist = "newPlaylist",
updatePlaylist = "editPlaylist",
welcome = "welcome",
newPlaylist,
updatePlaylist,
welcome,
}
export default defineStore("newModal", {
state: () => ({
title: "",
options: ModalOptions,
component: "",
component: <any>null,
props: <any>{},
visible: false,
}),
actions: {
showModal(modalOption: string) {
showModal(modalOption: ModalOptions) {
this.component = modalOption;
this.visible = true;
},
showNewPlaylistModal(track?: Track) {
this.component = ModalOptions.newPlaylist;
if (track) {
this.props.track = track;
}
this.visible = true;
this.showModal(ModalOptions.newPlaylist);
},
showEditPlaylistModal(playlist: Playlist) {
this.component = ModalOptions.updatePlaylist;
this.props = playlist;
this.visible = true;
this.showModal(ModalOptions.updatePlaylist);
},
showWelcomeModal() {
this.component = ModalOptions.welcome;
this.visible = true;
this.showModal(ModalOptions.welcome);
},
hideModal() {
this.visible = false;

View File

@ -240,19 +240,25 @@ export default defineStore("Queue", {
},
playTrackNext(track: Track) {
const Toast = useNotifStore();
const nextindex = this.current + 1;
const next: Track = this.tracklist[nextindex];
// if track is already next, skip
if (next?.trackid === track.trackid) {
Toast.showNotification("Track is already queued", NotifType.Info);
return;
}
// if tracklist is empty or current track is last, push track
// else insert track after current track
if (this.current == this.tracklist.length - 1) {
this.tracklist.push(track);
} else {
const nextindex = this.current + 1;
const next: Track = this.tracklist[nextindex];
if (next.trackid === track.trackid) {
Toast.showNotification("Track is already queued", NotifType.Info);
return;
}
this.tracklist.splice(this.current + 1, 0, track);
}
this.tracklist.splice(this.current + 1, 0, track);
// save queue
this.updateNext(this.current);
Toast.showNotification(
`Added ${track.title} to queue`,

View File

@ -1,12 +1,12 @@
<template>
<div id="f-view-parent">
<div id="scrollable" ref="scrollable">
<div class="banner shadow-lg">
<div class="banner shadow-lg rounded">
<div class="text abs rounded pad-medium">
<h3><FolderSvg /> {{ getFolderName($route) }}</h3>
</div>
<img
src="../assets/images/folder.webp"
src="@/assets/images/folderbg.webp"
alt=""
class="rounded"
loading="lazy"
@ -79,20 +79,16 @@ onBeforeRouteUpdate((to, from) => {
pointer-events: none;
user-select: none;
width: 100%;
// display: table-cell;
// vertical-align: bottom;
background-color: $accent;
.text {
bottom: 1rem;
// height: 100%;
left: 1rem;
// right: 1rem;
// width: min-content;
width: max-content;
max-width: calc(100% - 2rem);
background-color: $black;
@include for-desktop-down {
max-width: 31rem;
right: 1rem;
}
@ -110,6 +106,7 @@ onBeforeRouteUpdate((to, from) => {
height: 100%;
width: 100%;
object-fit: cover;
object-position: bottom;
}
}

View File

@ -25,11 +25,11 @@ const pStore = usePStore();
scrollbar-color: $gray2 transparent;
.grid {
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
gap: 1rem;
@include for-desktop-down {
grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
.name {
font-size: 0.9rem;

View File

@ -1732,6 +1732,11 @@ picomatch@^2.0.4, picomatch@^2.2.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pinia-plugin-persistedstate@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-2.1.1.tgz#584c416cdc278689ae9d49483621ec96dcb7d6ef"
integrity sha512-HUgsU5IRtM75eAQiIqzT3p1oPEuYH1/B2ipTMU++yE+FV0LkHaBswdKXs0RMWYCmugO8s62oxLTh/N1dLNp+5A==
pinia@^2.0.17:
version "2.0.17"
resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.0.17.tgz#f925e5e4f73c15e16dfb4838176a9ca50752f26b"