chore: replace Sass with PostCSS

This commit is contained in:
Phan An 2024-04-04 22:13:35 +02:00
parent b81571ab29
commit 0b66f365b2
169 changed files with 1005 additions and 1245 deletions

View file

@ -11,6 +11,6 @@
export default (on: () => void, config: Record<string, unknown>): Record<string, unknown> => {
return Object.assign({}, config, {
supportFile: 'cypress/support/index.ts'
supportFile: 'cypress/support/main.ts'
})
}

View file

@ -13,7 +13,7 @@ defineOptions({
</figure>
</template>
<style scoped lang="scss">
<style scoped lang="postcss">
figure {
margin: 1.5rem 0;
overflow: hidden;

View file

@ -15,7 +15,7 @@ import downloadedScreenshot from '../../assets/img/mobile/downloaded.webp'
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
div {
display: grid;
grid-template-columns: repeat(4, 1fr);

View file

@ -5,7 +5,7 @@
<script lang="ts" setup>
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
span {
display: inline-block;

View file

@ -19,7 +19,7 @@ defineOptions({
})
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
img {
opacity: 0.8;

View file

@ -52,7 +52,7 @@ import doLogo from '../../assets/img/sponsors/do.svg'
import whatTheDiffLogo from '../../assets/img/sponsors/what-the-diff.svg'
</script>
<style lang="scss">
<style lang="postcss">
div.sponsors {
border-left: 1px solid var(--vp-c-divider);
padding-left: 16px;

View file

@ -30,7 +30,7 @@ const themes: Theme[] = [
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
div .theme + .theme {
margin-left: -100%;
}

View file

@ -15,7 +15,7 @@ import Sponsors from '../components/Sponsors.vue'
const { Layout: BaseLayout } = DefaultTheme
</script>
<style lang="scss">
<style lang="postcss">
.aside-outline-after {
margin-top: 1.5rem;
}

View file

@ -69,7 +69,7 @@ onMounted(() => {
})
</script>
<style lang="scss" module>
<style lang="postcss" module>
ol img {
margin: 1.2rem 0;
}

View file

@ -54,6 +54,7 @@
"@vueuse/core": "^10.9.0",
"@vueuse/integrations": "^10.9.0",
"add": "^2.0.6",
"autoprefixer": "^10.4.19",
"cross-env": "^7.0.3",
"cypress": "^9.5.4",
"eslint": "^8.14.0",
@ -72,8 +73,9 @@
"laravel-vite-plugin": "^1.0.2",
"lint-staged": "^10.3.0",
"lucide-vue-next": "^0.363.0",
"postcss": "^8.4.38",
"postcss-nested": "^6.0.1",
"qrcode": "^1",
"sass": "^1.72.0",
"start-server-and-test": "^2.0.3",
"typescript": "^4.8.4",
"vite": "^5.1.6",

6
postcss.config.cjs Normal file
View file

@ -0,0 +1,6 @@
module.exports = {
plugins: [
require('postcss-nested'),
require('autoprefixer')
]
}

View file

@ -1,10 +1,22 @@
@mixin vertical-center() {
@import './vendor/reset.pcss';
@import './partials/vars.pcss';
@import './partials/hack.pcss';
@import '@modules/nouislider/distribute/nouislider.min.css';
@import './vendor/plyr.pcss';
@import './vendor/nprogress.pcss';
@import './partials/skeleton.pcss';
@import './partials/tooltip.pcss';
@import './partials/shared.pcss';
.vertical-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin artist-album-wrapper() {
.artist-album-wrapper {
display: grid !important;
gap: 16px;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
@ -24,9 +36,11 @@
}
}
@mixin artist-album-info-wrapper() {
.artist-album-info-wrapper {
.loading {
@include vertical-center();
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
@ -62,12 +76,13 @@
}
}
@mixin artist-album-info() {
.artist-album-info {
color: var(--color-text-secondary);
h1 {
@include vertical-center();
display: flex;
align-items: center;
justify-content: center;
font-weight: var(--font-weight-thin);
line-height: 2.8rem;
margin-bottom: 16px;
@ -154,13 +169,13 @@
}
}
@mixin inset-when-pressed() {
.inset-when-pressed {
&:not([disabled]):active {
box-shadow: inset 0 10px 10px -10px rgba(0, 0, 0, .6);
}
}
@mixin context-menu() {
.context-menu {
padding: .4rem 0;
width: max-content;
min-width: 144px;
@ -179,7 +194,7 @@
}
}
@mixin themed-background() {
.themed-background, body, html {
background-color: var(--color-bg-primary);
background-image: var(--bg-image);
background-attachment: var(--bg-attachment);

View file

@ -23,8 +23,6 @@ h1, h2, h3, h4, h5, h6, blockquote {
body,
html {
@include themed-background();
color: var(--color-text-primary);
font-family: var(--font-family);
font-size: 13px;
@ -130,11 +128,6 @@ a {
}
}
.ir {
color: transparent;
font: 0/0 serif;
}
.control {
cursor: pointer;
color: var(--color-text-secondary);
@ -174,6 +167,8 @@ label {
.tabs {
min-height: 100%;
display: flex;
flex-direction: column;
position: relative;
[role=tablist] {
@ -182,6 +177,7 @@ label {
padding: 0 1.25rem;
display: flex;
gap: 0.3rem;
min-height: 36px;
[role=tab] {
position: relative;
@ -344,7 +340,6 @@ label {
.context-menu,
.submenu,
menu {
@include context-menu();
position: fixed;
@keyframes subMenuHoverHelp {

View file

@ -1,18 +1,13 @@
.skeleton {
.pulse,
&.pulse {
.pulse, &.pulse {
animation: skeleton-pulse 2s infinite;
background-color: rgba(255, 255, 255, .05);
}
@keyframes skeleton-pulse {
0%,
100% {
0%, 100% {
opacity: 0;
}
50% {
opacity: 1;
}

View file

@ -0,0 +1,4 @@
@import './vendor/reset.pcss';
@import '@modules/nouislider/distribute/nouislider.min.css';
@import './partials/vars.pcss';
@import './partials/shared.pcss';

583
resources/assets/css/vendor/plyr.pcss vendored Normal file
View file

@ -0,0 +1,583 @@
.plyr__captions, .plyr__controls {
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-align: center
}
.plyr__tooltip, .plyr__video-embed.plyr iframe {
pointer-events: none
}
@-webkit-keyframes plyr-progress {
to {
background-position: 40px 0
}
}
@keyframes plyr-progress {
to {
background-position: 40px 0
}
}
.plyr {
position: relative;
max-width: 100%;
min-width: 290px;
}
.plyr, .plyr *, .plyr ::after, .plyr ::before {
box-sizing: border-box
}
.plyr a, .plyr button, .plyr input, .plyr label {
-ms-touch-action: manipulation;
touch-action: manipulation
}
.plyr__sr-only {
position: absolute !important;
clip: rect(1px, 1px, 1px, 1px);
padding: 0 !important;
border: 0 !important;
height: 1px !important;
width: 1px !important;
overflow: hidden
}
.plyr__video-wrapper {
position: relative
}
.plyr audio, .plyr video {
width: 100%;
height: auto;
vertical-align: middle
}
.plyr__video-embed {
padding-bottom: 56.25%;
height: 0;
overflow: hidden;
background: #000
}
.plyr__video-embed iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
user-select: none
}
.plyr__video-embed > div {
position: relative;
padding-bottom: 200%;
transform: translateY(-35.95%)
}
.plyr__captions {
display: none;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 20px 20px 30px;
color: #fff;
font-size: 20px
}
.plyr__captions span {
border-radius: 2px;
padding: 3px 10px;
background: rgba(0, 0, 0, .9)
}
.plyr__captions span:empty {
display: none
}
@media (min-width: 768px) {
.plyr__captions {
font-size: 24px
}
}
.plyr--captions-active .plyr__captions {
display: block
}
.plyr--fullscreen-active .plyr__captions {
font-size: 32px
}
.plyr__controls {
position: relative;
padding: 10px;
background: #fff;
line-height: 1;
box-shadow: 0 1px 1px rgba(52, 63, 74, .2)
}
.plyr__controls::after {
content: '';
display: table;
clear: both
}
.plyr__controls--right {
display: block;
margin: 10px auto 0
}
@media (min-width: 560px) {
.plyr__controls--left {
float: left
}
.plyr__controls--right {
float: right;
margin-top: 0
}
}
.plyr__controls button {
display: inline-block;
vertical-align: middle;
margin: 0 2px;
padding: 5px 10px;
overflow: hidden;
border: 0;
background: 0 0;
border-radius: 3px;
cursor: pointer;
color: var(--color-highlight);
transition: background .3s ease, color .3s ease, opacity .3s ease
}
.plyr__controls button svg {
width: 18px;
height: 18px;
display: block;
fill: currentColor;
transition: fill .3s ease
}
.plyr__controls button.tab-focus:focus, .plyr__controls button:hover {
background: #3498DB;
color: #fff
}
.plyr__controls .plyr__time, .plyr__tooltip {
color: var(--color-highlight);
font-size: 14px;
font-weight: 600
}
.plyr__controls button:focus {
outline: 0
}
.plyr__controls .icon--captions-on, .plyr__controls .icon--exit-fullscreen, .plyr__controls .icon--muted {
display: none
}
.plyr__controls .plyr__time {
display: inline-block;
vertical-align: middle;
margin-left: 10px
}
.plyr__controls .plyr__time + .plyr__time {
display: none
}
@media (min-width: 560px) {
.plyr__controls .plyr__time + .plyr__time {
display: inline-block
}
}
.plyr__controls .plyr__time + .plyr__time::before {
content: '\2044';
margin-right: 10px
}
.plyr__tooltip {
visibility: hidden;
position: absolute;
z-index: 2;
bottom: 100%;
margin-bottom: 10px;
padding: 10px 15px;
opacity: 0;
background: #fff;
box-shadow: 0 0 5px rgba(64, 64, 64, .1), 0 0 0 1px rgba(64, 64, 64, .1);
border-radius: 3px;
line-height: 1.5;
transform: translate(-50%, 10px) scale(.8);
-webkit-transform-origin: 50% 100%;
transform-origin: 50% 100%;
transition: transform .2s .1s ease, opacity .2s .1s ease, visibility .3s ease;
}
.plyr__tooltip::after, .plyr__tooltip::before {
content: '';
position: absolute;
width: 0;
height: 0;
top: 100%;
left: 50%;
transform: translateX(-50%)
}
.plyr__tooltip::after {
bottom: -8px;
border-right: 7px solid transparent;
border-top: 7px solid rgba(64, 64, 64, .2);
border-left: 7px solid transparent;
z-index: 1
}
.plyr__tooltip::before {
bottom: -6px;
border-right: 6px solid transparent;
border-top: 6px solid #fff;
border-left: 6px solid transparent;
z-index: 2
}
.plyr button.tab-focus:focus .plyr__tooltip, .plyr button:hover .plyr__tooltip, .plyr__tooltip--visible {
visibility: visible;
opacity: 1;
transform: translate(-50%, 0) scale(1)
}
.plyr button:hover .plyr__tooltip {
z-index: 3
}
.plyr input[type=range]::-ms-tooltip {
display: none
}
.plyr input[type=range].tab-focus:focus {
outline: rgba(52, 63, 74, .8) dotted 1px;
outline-offset: 3px
}
.plyr__progress--seek[type=range]:focus, .plyr__volume[type=range]:focus {
outline: 0
}
.plyr__progress {
position: absolute;
bottom: 100%;
left: 0;
right: 0;
width: 100%;
height: 10px;
background: transparent;
}
.plyr__progress--buffer[value], .plyr__progress--played[value], .plyr__progress--seek[type=range] {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 4px;
margin: 0;
padding: 0;
vertical-align: top;
-webkit-appearance: none;
-moz-appearance: none;
border: none;
background: 0 0
}
.plyr__progress--buffer[value]::-webkit-progress-bar, .plyr__progress--played[value]::-webkit-progress-bar {
background: 0 0;
transition: width .2s ease
}
.plyr__progress--buffer[value]::-webkit-progress-value, .plyr__progress--played[value]::-webkit-progress-value {
background: currentColor;
transition: width .2s ease
}
.plyr__progress--buffer[value]::-moz-progress-bar, .plyr__progress--played[value]::-moz-progress-bar {
background: currentColor;
transition: width .2s ease
}
.plyr__progress--played[value] {
z-index: 2;
color: #3498DB
}
.plyr__progress--buffer[value] {
color: rgba(86, 93, 100, .25)
}
.plyr__progress--seek[type=range] {
z-index: 4;
cursor: pointer;
outline: 0;
height: 10px; /* increase height for touch */
}
.plyr__progress--seek[type=range]::-webkit-slider-runnable-track {
background: 0 0;
border: 0
}
.plyr__progress--seek[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
background: 0 0;
border: 0;
width: 1px;
height: 10px
}
.plyr__progress--seek[type=range]::-moz-range-track {
background: 0 0;
border: 0
}
.plyr__progress--seek[type=range]::-moz-range-thumb {
-moz-appearance: none;
background: 0 0;
border: 0;
width: 1px;
height: 10px
}
.plyr__progress--seek[type=range]::-ms-track {
color: transparent;
background: 0 0;
border: 0
}
.plyr__progress--seek[type=range]::-ms-fill-lower, .plyr__progress--seek[type=range]::-ms-fill-upper {
background: 0 0;
border: 0
}
.plyr__progress--seek[type=range]::-ms-thumb {
background: 0 0;
border: 0;
width: 1px;
height: 10px
}
.plyr__progress--seek[type=range]::-moz-focus-outer {
border: 0
}
.plyr__progress .plyr__tooltip {
left: 0
}
.plyr--is-touch .plyr--seek[type=range]::-webkit-slider-thumb {
width: 40px;
transform: translateX(-50%)
}
.plyr--is-touch .plyr--seek[type=range]::-moz-range-thumb {
width: 40px;
transform: translateX(-50%)
}
.plyr--is-touch .plyr--seek[type=range]::-ms-thumb {
width: 40px;
transform: translateX(-50%)
}
.plyr--loading .plyr__progress--buffer {
-webkit-animation: plyr-progress 1s linear infinite;
animation: plyr-progress 1s linear infinite;
background-size: 40px 40px;
background-repeat: repeat-x;
background-color: rgba(86, 93, 100, .25);
background-image: linear-gradient(-45deg, rgba(0, 0, 0, .15) 25%, transparent 25%, transparent 50%, rgba(0, 0, 0, .15) 50%, rgba(0, 0, 0, .15) 75%, transparent 75%, transparent);
color: transparent
}
.plyr--playing .plyr__controls [data-plyr=play], .plyr__controls [data-plyr=pause] {
display: none
}
.plyr--playing .plyr__controls [data-plyr=pause] {
display: inline-block
}
.plyr__volume[type=range] {
display: inline-block;
vertical-align: middle;
-webkit-appearance: none;
-moz-appearance: none;
width: 100px;
margin: 0 10px 0 0;
padding: 0;
cursor: pointer;
background: transparent;
border: none
}
.plyr__volume[type=range]::-webkit-slider-runnable-track {
height: 6px;
background: rgba(255, 255, 255, .2);
border: 0;
border-radius: 3px
}
.plyr__volume[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
margin-top: -3px;
height: 12px;
width: 12px;
background: var(--color-highlight);
border: 0;
border-radius: 100%;
transition: background .3s ease;
cursor: ew-resize
}
.plyr__volume[type=range]::-moz-range-track {
height: 6px;
background: rgba(255, 255, 255, .2);
border: 0;
border-radius: 3px
}
.plyr__volume[type=range]::-moz-range-thumb {
height: 12px;
width: 12px;
background: var(--color-highlight);
border: 0;
border-radius: 100%;
transition: background .3s ease;
cursor: ew-resize
}
.plyr__volume[type=range]::-ms-track {
height: 6px;
background: rgba(255, 255, 255, .2);
border-color: transparent;
border-width: 3px 0;
color: transparent
}
.plyr__volume[type=range]::-ms-fill-lower, .plyr__volume[type=range]::-ms-fill-upper {
height: 6px;
background: rgba(255, 255, 255, .2);
border: 0;
border-radius: 3px
}
.plyr__volume[type=range]::-ms-thumb {
height: 12px;
width: 12px;
background: var(--color-highlight);
border: 0;
border-radius: 100%;
transition: background .3s ease;
cursor: ew-resize
}
.plyr__volume[type=range]:focus::-webkit-slider-thumb {
background: transparent;
}
.plyr__volume[type=range]:focus::-moz-range-thumb {
background: #3498DB
}
.plyr__volume[type=range]:focus::-ms-thumb {
background: #3498DB
}
.plyr--is-ios .plyr__volume, .plyr--is-ios [data-plyr=mute], .plyr--is-ios.plyr--audio .plyr__controls--right {
display: none
}
.plyr--is-ios.plyr--audio .plyr__controls--left {
float: none
}
.plyr--audio .plyr__controls {
padding-top: 20px
}
.plyr--audio .plyr__progress {
bottom: auto;
top: 0;
background: transparent;
}
.plyr--fullscreen-active, .plyr.plyr--fullscreen {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
height: 100%;
width: 100%;
z-index: 10000000;
background: #000
}
.plyr--fullscreen-active video, .plyr.plyr--fullscreen video {
height: 100%
}
.plyr--fullscreen-active .plyr__video-wrapper, .plyr.plyr--fullscreen .plyr__video-wrapper {
height: 100%;
width: 100%
}
.plyr--fullscreen-active .plyr__controls, .plyr.plyr--fullscreen .plyr__controls {
position: absolute;
bottom: 0;
left: 0;
right: 0
}
.plyr--fullscreen-active.plyr--fullscreen--hide-controls.plyr--playing .plyr__controls, .plyr.plyr--fullscreen.plyr--fullscreen--hide-controls.plyr--playing .plyr__controls {
transform: translateY(100%) translateY(5px);
transition: transform .3s .2s ease;
}
.plyr--fullscreen-active.plyr--fullscreen--hide-controls.plyr--playing .plyr__captions, .plyr.plyr--fullscreen.plyr--fullscreen--hide-controls.plyr--playing .plyr__captions {
bottom: 5px;
transition: bottom .3s .2s ease
}
.plyr--fullscreen-active.plyr--fullscreen--hide-controls.plyr--playing.plyr--hover .plyr__controls, .plyr.plyr--fullscreen.plyr--fullscreen--hide-controls.plyr--playing.plyr--hover .plyr__controls {
transform: translateY(0)
}
.plyr--fullscreen--hide-controls.plyr--fullscreen-active.plyr--playing.plyr--hover .plyr__captions, .plyr--fullscreen-active .plyr__captions, .plyr.plyr--fullscreen .plyr__captions {
top: auto;
bottom: 90px
}
@media (min-width: 560px) {
.plyr--fullscreen--hide-controls.plyr--fullscreen-active.plyr--playing.plyr--hover .plyr__captions, .plyr--fullscreen-active .plyr__captions, .plyr.plyr--fullscreen .plyr__captions {
bottom: 60px
}
}
.plyr--captions-active .plyr__controls .icon--captions-on, .plyr--fullscreen-active .icon--exit-fullscreen, .plyr--muted .plyr__controls .icon--muted {
display: block
}
.plyr [data-plyr=fullscreen], .plyr [data-plyr=captions], .plyr--captions-active .plyr__controls .icon--captions-on + svg, .plyr--fullscreen-active .icon--exit-fullscreen + svg, .plyr--muted .plyr__controls .icon--muted + svg {
display: none
}
.plyr--captions-enabled [data-plyr=captions], .plyr--fullscreen-enabled [data-plyr=fullscreen] {
display: inline-block
}

34
resources/assets/css/vendor/reset.pcss vendored Normal file
View file

@ -0,0 +1,34 @@
html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline
}
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {
display: block
}
body {
line-height: 1
}
ol, ul {
list-style: none
}
blockquote, q {
quotes: none
}
blockquote:before, blockquote:after, q:before, q:after {
content: '';
content: none
}
table {
border-collapse: collapse;
border-spacing: 0
}

View file

@ -26,7 +26,7 @@
</template>
<script lang="ts" setup>
import { defineAsyncComponent, nextTick, onMounted, provide, ref, watch } from 'vue'
import { defineAsyncComponent, onMounted, provide, ref, watch } from 'vue'
import { useOnline } from '@vueuse/core'
import { commonStore, preferenceStore as preferences, queueStore } from '@/stores'
import { authService, socketListener, socketService, uploadService } from '@/services'
@ -160,9 +160,7 @@ provide(MessageToasterKey, toaster)
provide(CurrentSongKey, currentSong)
</script>
<style lang="scss">
@import "#/app.scss";
<style lang="postcss">
#dragGhost {
display: inline-block;
background: var(--color-green);

View file

@ -4,6 +4,7 @@ import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome
import { RouterKey } from '@/symbols'
import { routes } from '@/config'
import Router from '@/router'
import '@/../css/app.pcss'
import App from './App.vue'
createApp(App)

View file

@ -1,5 +1,5 @@
<template>
<article :class="mode" class="album-info" data-testid="album-info">
<article :class="mode" class="album-info artist-album-info" data-testid="album-info">
<h1 v-if="mode === 'aside'" class="name">
<span>{{ album.name }}</span>
<button :title="`Play all songs in ${album.name}`" class="control" type="button" @click.prevent="play">
@ -68,17 +68,3 @@ const play = async () => {
go('queue')
}
</script>
<style lang="scss" scoped>
.album-info {
@include artist-album-info();
.track-listing {
margin-top: 2rem;
:deep(h1) {
margin-bottom: 1.2rem;
}
}
}
</style>

View file

@ -1,13 +1,13 @@
<template>
<section class="track-listing">
<h1>Track Listing</h1>
<article class="track-listing">
<h3>Track Listing</h3>
<ul class="tracks">
<li v-for="(track, index) in tracks" :key="index" data-testid="album-track-item">
<TrackListItem :album="album" :track="track" />
</li>
</ul>
</section>
</article>
</template>
<script lang="ts" setup>
@ -28,12 +28,11 @@ provide(SongsKey, songs)
onMounted(async () => songs.value = await songStore.fetchForAlbum(album.value))
</script>
<style lang="scss" scoped>
section {
h1 {
<style lang="postcss" scoped>
article {
h3 {
font-size: 1.4rem;
margin-bottom: 0;
display: block;
margin-bottom: 1rem;
}
ul {

View file

@ -47,7 +47,7 @@ const play = () => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.track-list-item {
display: flex;
flex: 1;

View file

@ -1,5 +1,5 @@
<template>
<article :class="mode" class="artist-info" data-testid="artist-info">
<article :class="mode" class="artist-info artist-album-info" data-testid="artist-info">
<h1 v-if="mode === 'aside'" class="name">
<span>{{ artist.name }}</span>
<button :title="`Play all songs by ${artist.name}`" class="control" type="button" @click.prevent="play">
@ -65,10 +65,8 @@ const play = async () => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.artist-info {
@include artist-album-info();
.none {
margin-top: 1rem;
}

View file

@ -45,7 +45,7 @@ const requestResetPasswordLink = async () => {
}
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
form {
min-width: 480px;

View file

@ -86,7 +86,7 @@ const onSSOSuccess = (token: CompositeToken) => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
/**
* I like to move it move it
* I like to move it move it

View file

@ -1,5 +1,5 @@
<template>
<div class="reset-password-wrapper">
<div class="reset-password-wrapper vertical-center">
<form v-if="validPayload" @submit.prevent="submit">
<h1 class="font-size-1.5">Set New Password</h1>
<div>
@ -55,10 +55,8 @@ const submit = async () => {
}
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
.reset-password-wrapper {
@include vertical-center;
height: 100vh;
}

View file

@ -4,7 +4,7 @@ exports[`renders 1`] = `
<div data-v-0b0f87ea="" class="login-wrapper">
<form data-v-0b0f87ea="" class="" data-testid="login-form">
<div data-v-0b0f87ea="" class="logo"><img data-v-0b0f87ea="" alt="Koel's logo" src="undefined/resources/assets/img/logo.svg" width="156"></div><input data-v-0b0f87ea="" autofocus="" placeholder="Email Address" required="" type="email">
<div data-v-a2893005="" data-v-0b0f87ea=""><input data-v-a2893005="" type="password" placeholder="Password" required=""><button data-v-a2893005="" type="button"><br data-v-a2893005="" data-testid="Icon" icon="[object Object]"></button></div><button data-v-e368fe26="" data-v-0b0f87ea="" type="submit">Log In</button><a data-v-0b0f87ea="" class="reset-password" role="button"> Forgot password? </a>
<div data-v-a2893005="" data-v-0b0f87ea=""><input data-v-a2893005="" type="password" placeholder="Password" required=""><button data-v-a2893005="" type="button"><br data-v-a2893005="" data-testid="Icon" icon="[object Object]"></button></div><button data-v-e368fe26="" data-v-0b0f87ea="" class="inset-when-pressed" type="submit">Log In</button><a data-v-0b0f87ea="" class="reset-password" role="button"> Forgot password? </a>
</form>
<!--v-if-->
<!--v-if-->
@ -15,7 +15,7 @@ exports[`shows Google login button 1`] = `
<div data-v-0b0f87ea="" class="login-wrapper">
<form data-v-0b0f87ea="" class="" data-testid="login-form">
<div data-v-0b0f87ea="" class="logo"><img data-v-0b0f87ea="" alt="Koel's logo" src="undefined/resources/assets/img/logo.svg" width="156"></div><input data-v-0b0f87ea="" autofocus="" placeholder="Email Address" required="" type="email">
<div data-v-a2893005="" data-v-0b0f87ea=""><input data-v-a2893005="" type="password" placeholder="Password" required=""><button data-v-a2893005="" type="button"><br data-v-a2893005="" data-testid="Icon" icon="[object Object]"></button></div><button data-v-e368fe26="" data-v-0b0f87ea="" type="submit">Log In</button><a data-v-0b0f87ea="" class="reset-password" role="button"> Forgot password? </a>
<div data-v-a2893005="" data-v-0b0f87ea=""><input data-v-a2893005="" type="password" placeholder="Password" required=""><button data-v-a2893005="" type="button"><br data-v-a2893005="" data-testid="Icon" icon="[object Object]"></button></div><button data-v-e368fe26="" data-v-0b0f87ea="" class="inset-when-pressed" type="submit">Log In</button><a data-v-0b0f87ea="" class="reset-password" role="button"> Forgot password? </a>
</form>
<div data-v-0b0f87ea="" class="sso"><br data-v-0b0f87ea="" data-testid="google-login-button"></div>
<!--v-if-->

View file

@ -23,7 +23,7 @@ const loginWithGoogle = async () => {
}
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
button {
opacity: .5;

View file

@ -1,5 +1,5 @@
<template>
<div class="invitation-wrapper">
<div class="invitation-wrapper vertical-center">
<form v-if="userProspect" autocomplete="off" @submit.prevent="submit">
<header>
Welcome to Koel! To accept the invitation, fill in the form below and click that button.
@ -92,10 +92,8 @@ onMounted(async () => {
})
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
.invitation-wrapper {
@include vertical-center();
display: flex;
height: 100vh;
flex-direction: column;

View file

@ -40,7 +40,7 @@ const validateLicenseKey = async () => {
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
form {
display: flex;
align-items: stretch;

View file

@ -1,5 +1,5 @@
<template>
<a href class="upgrade-to-plus-btn" @click.prevent="openModal">
<a href class="upgrade-to-plus-btn inset-when-pressed" @click.prevent="openModal">
<Icon :icon="faPlus" fixed-width />
Upgrade to Plus
</a>
@ -12,10 +12,8 @@ import { eventBus } from '@/utils'
const openModal = () => eventBus.emit('MODAL_SHOW_KOEL_PLUS')
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
a.upgrade-to-plus-btn {
@include inset-when-pressed();
background: linear-gradient(97.78deg, #671ce4 17.5%, #c62be8 113.39%);
border-radius: 5px;
border-style: solid;
@ -26,7 +24,7 @@ a.upgrade-to-plus-btn {
}
&:active {
padding: .65rem 1rem; // prevent layout jump in sidebar
padding: .65rem 1rem; /* prevent layout jump in sidebar */
}
}
</style>

View file

@ -55,7 +55,7 @@ const hideActivateLicenseForm = () => (showingActivateLicenseForm.value = false)
onMounted(() => window.createLemonSqueezy?.())
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
.plus {
max-width: 480px;
display: flex;

View file

@ -85,7 +85,7 @@ eventBus.on('MODAL_SHOW_ABOUT_KOEL', () => (activeModalName.value = 'about-koel'
.on('MODAL_SHOW_EQUALIZER', () => (activeModalName.value = 'equalizer'))
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
dialog {
border: 0;
padding: 0;

View file

@ -10,8 +10,8 @@
<script lang="ts" setup>
</script>
<style lang="scss">
// can't be scoped as it would be overridden by the plyr css
<style lang="postcss">
/* can't be scoped as it would be overridden by the plyr css */
.plyr {
width: 100%;
height: 4px;

View file

@ -62,7 +62,7 @@ onMounted(() => {
})
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.extra-controls {
display: flex;
justify-content: flex-end;

View file

@ -36,7 +36,7 @@ const playPrev = async () => await playbackService.playPrev()
const playNext = async () => await playbackService.playNext()
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.playback-controls {
flex: 1;
display: flex;

View file

@ -33,7 +33,7 @@ const onDragStart = (event: DragEvent) => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.song-info {
padding: 0 1.5rem;
display: flex;

View file

@ -3,7 +3,7 @@
exports[`renders 1`] = `
<div data-v-8bf5fe81="" class="extra-controls" data-testid="other-controls">
<div data-v-8bf5fe81="" class="wrapper"><button data-v-8bf5fe81="" class="visualizer-btn" data-testid="toggle-visualizer-btn" title="Toggle visualizer"><br data-v-8bf5fe81="" data-testid="Icon" icon="[object Object]"></button>
<!--v-if--><span data-v-8bf5fe81="" id="volume" class="volume muted"><span role="button" tabindex="0" title="Unmute"><br data-testid="Icon" icon="[object Object]" fixed-width=""></span><span role="button" tabindex="0" title="Mute" style="display: none;"><br data-testid="Icon" icon="[object Object]" fixed-width=""></span><input class="plyr__volume" max="10" role="slider" step="0.1" title="Volume" type="range"></span>
<!--v-if--><span data-v-c7afcfc4="" data-v-8bf5fe81="" id="volume" class="volume muted"><span data-v-c7afcfc4="" role="button" tabindex="0" title="Unmute"><br data-v-c7afcfc4="" data-testid="Icon" icon="[object Object]" fixed-width=""></span><span data-v-c7afcfc4="" role="button" tabindex="0" title="Mute" style="display: none;"><br data-v-c7afcfc4="" data-testid="Icon" icon="[object Object]" fixed-width=""></span><input data-v-c7afcfc4="" class="plyr__volume" max="10" role="slider" step="0.1" title="Volume" type="range"></span>
<!--v-if-->
</div>
</div>

View file

@ -99,7 +99,7 @@ watch(isFullscreen, fullscreen => {
eventBus.on('FULLSCREEN_TOGGLE', () => toggleFullscreen())
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
footer {
background-color: var(--color-bg-secondary);
background-size: 0;

View file

@ -123,7 +123,7 @@ const logout = () => eventBus.emit('LOG_OUT')
onMounted(() => isMobile.any || (activeTab.value = preferenceStore.active_extra_panel_tab))
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
aside {
display: flex;
flex-direction: row-reverse;
@ -132,7 +132,12 @@ aside {
z-index: 2;
@media screen and (max-width: 768px) {
@include themed-background();
background-color: var(--color-bg-primary);
background-image: var(--bg-image);
background-attachment: var(--bg-attachment);
background-size: var(--bg-size);
background-position: var(--bg-position);
flex-direction: column;
position: fixed;
top: 0;
@ -152,7 +157,7 @@ aside {
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.1);
@media (hover: none) {
// Enable scroll with momentum on touch devices
/* Enable scroll with momentum on touch devices */
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
@ -219,6 +224,7 @@ aside {
&:hover, &.active {
opacity: 1;
color: var(--color-text-primary);
background: rgba(255, 255, 255, .1);
}
&:active {

View file

@ -78,7 +78,7 @@ onMounted(async () => {
})
</script>
<style lang="scss">
<style lang="postcss">
#mainContent {
flex: 1;
position: relative;
@ -113,7 +113,7 @@ onMounted(async () => {
place-content: start;
@media (hover: none) {
// Enable scroll with momentum on touch devices
/* Enable scroll with momentum on touch devices */
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
@ -122,7 +122,7 @@ onMounted(async () => {
@media screen and (max-width: 768px) {
> section {
// Leave some space for the "Back to top" button
/* Leave some space for the "Back to top" button */
.main-scroll-wrap {
padding-bottom: 64px;
}

View file

@ -17,12 +17,12 @@ import ExtraDrawer from '@/components/layout/main-wrapper/ExtraDrawer.vue'
const ModalWrapper = defineAsyncComponent(() => import('@/components/layout/ModalWrapper.vue'))
</script>
<style lang="scss">
<style lang="postcss">
#mainWrapper {
position: relative;
display: flex;
flex: 1;
height: 0; // fix a flex-box bug https://github.com/philipwalton/flexbugs/issues/197#issuecomment-378908438
height: 0; /* fix a flex-box bug https://github.com/philipwalton/flexbugs/issues/197#issuecomment-378908438 */
overflow: hidden;
}
</style>

View file

@ -107,7 +107,7 @@ const onContextMenu = (event: MouseEvent) => eventBus.emit(
)
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
li.playlist-folder {
position: relative;

View file

@ -127,7 +127,7 @@ onRouteChanged(route => {
})
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.playlist {
user-select: none;

View file

@ -53,7 +53,7 @@ const requestContextMenu = () => {
}
</script>
<style lang="scss">
<style lang="postcss">
#playlists {
h1 {
display: flex;
@ -67,7 +67,7 @@ const requestContextMenu = () => {
position: relative;
&::before {
// increase clickable area
/* increase clickable area */
content: '';
position: absolute;
width: 28px;

View file

@ -130,7 +130,7 @@ eventBus.on('TOGGLE_SIDEBAR', () => (mobileShowing.value = !mobileShowing.value)
.on('PLAY_YOUTUBE_VIDEO', _ => (youTubePlaying.value = true))
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
nav {
position: relative;
width: var(--sidebar-width);
@ -176,7 +176,7 @@ nav {
overflow-y: auto;
@media (hover: none) {
// Enable scroll with momentum on touch devices
/* Enable scroll with momentum on touch devices */
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
@ -256,7 +256,7 @@ nav {
}
}
:deep(li li a) { // submenu items
:deep(li li a) { /* submenu items */
padding-left: 11px;
&:active {
@ -287,7 +287,12 @@ nav {
}
@media screen and (max-width: 768px) {
@include themed-background();
background-color: var(--color-bg-primary);
background-image: var(--bg-image);
background-attachment: var(--bg-attachment);
background-size: var(--bg-size);
background-position: var(--bg-position);
transform: translateX(-100vw);
transition: transform .2s ease-in-out;

View file

@ -105,7 +105,7 @@ onMounted(async () => {
})
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.about {
text-align: center;
max-width: 480px;

View file

@ -15,7 +15,7 @@
<script lang="ts" setup>
import sponsors from '@/sponsors'</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.sponsors {
display: flex;
align-items: center;

View file

@ -42,7 +42,7 @@ watch(preferenceStore.initialized, initialized => {
}, { immediate: true })
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.support-bar {
background: var(--color-bg-primary);
font-size: .9rem;

View file

@ -12,6 +12,6 @@ exports[`renders 1`] = `
<!--v-if--><br data-v-6b5b01a9="" data-testid="sponsor-list">
<p data-v-6b5b01a9=""> Loving Koel? Please consider supporting its development via <a data-v-6b5b01a9="" href="https://github.com/users/phanan/sponsorship" rel="noopener" target="_blank">GitHub Sponsors</a> and/or <a data-v-6b5b01a9="" href="https://opencollective.com/koel" rel="noopener" target="_blank">OpenCollective</a>. </p>
</main>
<footer data-v-6b5b01a9=""><button data-v-e368fe26="" data-v-6b5b01a9="" data-testid="close-modal-btn" red="" rounded="">Close</button></footer>
<footer data-v-6b5b01a9=""><button data-v-e368fe26="" data-v-6b5b01a9="" class="inset-when-pressed" data-testid="close-modal-btn" red="" rounded="">Close</button></footer>
</div>
`;

View file

@ -98,7 +98,7 @@ const maybeClose = async () => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
form {
min-width: 100%;
}

View file

@ -86,7 +86,7 @@ const maybeClose = async () => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
form {
min-width: 100%;
}

View file

@ -37,7 +37,7 @@ const inviteCollaborators = async () => {
}
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
.copied {
font-size: .95rem;
}

View file

@ -48,7 +48,7 @@ const emit = defineEmits<{ (e: 'close'): void }>()
const close = () => emit('close')
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.collaboration-modal {
max-width: 640px;
}

View file

@ -70,7 +70,7 @@ const removeCollaborator = async (collaborator: PlaylistCollaborator) => {
onMounted(async () => await fetchCollaborators())
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
ul {
display: flex;
width: 100%;

View file

@ -43,7 +43,7 @@ const { currentUser } = useAuthorization()
const emit = defineEmits<{ (e: 'remove'): void }>()
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
li {
display: flex;
align-items: center;

View file

@ -23,7 +23,7 @@ const displayedCollaborators = computed(() => collaborators.value.slice(0, 3))
const remainderCount = computed(() => collaborators.value.length - displayedCollaborators.value.length)
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
div {
display: inline-block;
vertical-align: middle;

View file

@ -14,6 +14,6 @@ exports[`renders the modal 1`] = `
<div data-v-886145d2="" class="collaborators-wrapper"><br data-v-886145d2="" data-testid="CollaboratorList" playlist="[object Object]"></div>
</section>
</main>
<footer data-v-886145d2=""><button data-v-e368fe26="" data-v-886145d2="">Close</button></footer>
<footer data-v-886145d2=""><button data-v-e368fe26="" data-v-886145d2="" class="inset-when-pressed">Close</button></footer>
</div>
`;

View file

@ -7,7 +7,7 @@
<script lang="ts" setup>
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.smart-playlist-form {
width: 560px;
max-height: calc(100vh - 4rem);

View file

@ -113,7 +113,7 @@ const onInput = () => {
const removeRule = () => emit('remove')
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.row {
display: flex;
gap: .5rem;

View file

@ -54,7 +54,7 @@ const removeRule = (rule: SmartPlaylistRule) => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.rule-group {
margin-bottom: 1rem;
padding-bottom: .5rem;

View file

@ -17,7 +17,7 @@ const value = computed({
})
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
input {
width: 140px !important;
}

View file

@ -77,7 +77,7 @@ const onCancel = () => (cropperSource.value = null)
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
.avatar {
--w: 105px;
outline: rgba(255, 255, 255, .1) solid 3px;

View file

@ -15,7 +15,7 @@ import LastfmIntegration from '@/components/profile-preferences/LastfmIntegratio
import SpotifyIntegration from '@/components/profile-preferences/SpotifyIntegration.vue'
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
.integrations {
> article + article {
margin-top: 2rem;

View file

@ -77,9 +77,9 @@ const disconnect = async () => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.lastfm-icon {
color: #d31f27; // Last.fm red
color: #d31f27; /* Last.fm red */
margin-right: .4rem;
}

View file

@ -50,7 +50,7 @@ const isPhone = isMobile.phone
const { isPlus } = useKoelPlus()
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
label {
font-size: 1rem;
}

View file

@ -129,7 +129,7 @@ const update = async () => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
form {
input {
width: 100%;

View file

@ -37,7 +37,7 @@ onMounted(() => {
})
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
img {
margin-top: 1.5rem;
display: block;

View file

@ -36,9 +36,9 @@ const { currentUser, isAdmin } = useAuthorization();
const { useSpotify } = useThirdPartyServices();
</script>
<style scoped lang="scss">
<style scoped lang="postcss">
.spotify-icon {
margin-right: .4rem;
color: #1db954; // Spotify green
color: #1db954; /* Spotify green */
}
</style>

View file

@ -31,7 +31,7 @@ if (theme.value.thumbnailUrl) {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.theme {
height: 100%;
background-position: center;

View file

@ -19,7 +19,7 @@ const themes = toRef(themeStore.state, 'themes')
const setTheme = (theme: Theme) => themeStore.setTheme(theme)
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.themes {
display: grid;
grid-auto-rows: 8rem;

View file

@ -22,7 +22,7 @@
ref="listEl"
v-koel-overflow-fade
:class="`as-${viewMode}`"
class="albums main-scroll-wrap"
class="albums main-scroll-wrap artist-album-wrapper"
data-testid="album-list"
>
<template v-if="showSkeletons">
@ -96,12 +96,3 @@ useRouter().onScreenActivated('Albums', async () => {
}
})
</script>
<style lang="scss">
#albumsWrapper {
.albums {
@include artist-album-wrapper();
}
}
</style>
`

View file

@ -1,5 +1,5 @@
<template>
<section v-if="album" id="albumWrapper">
<section v-if="album" id="albumWrapper" class="artist-album-info-wrapper">
<ScreenHeaderSkeleton v-if="loading" />
<ScreenHeader v-if="!loading && album" :layout="songs.length === 0 ? 'collapsed' : headerLayout">
@ -67,14 +67,14 @@
<div v-show="activeTab === 'OtherAlbums'" class="albums-pane" data-testid="albums-pane">
<template v-if="otherAlbums">
<ul v-if="otherAlbums.length" v-koel-overflow-fade class="as-list">
<ul v-if="otherAlbums.length" v-koel-overflow-fade class="as-list artist-album-wrapper">
<li v-for="a in otherAlbums" :key="a.id">
<AlbumCard :album="a" layout="compact" />
</li>
</ul>
<p v-else class="none text-secondary">No other albums by {{ album.artist_name }} found in the library.</p>
</template>
<ul v-else class="as-list">
<ul v-else class="as-list artist-album-wrapper">
<li v-for="i in 12" :key="i">
<AlbumCardSkeleton layout="compact" />
</li>
@ -186,9 +186,3 @@ onScreenActivated('Album', () => (albumId.value = parseInt(getRouteParam('id')!)
// if the current album has been deleted, go back to the list
eventBus.on('SONGS_UPDATED', () => albumStore.byId(albumId.value!) || go('albums'))
</script>
<style lang="scss" scoped>
#albumWrapper {
@include artist-album-info-wrapper();
}
</style>

View file

@ -168,10 +168,10 @@ onScreenActivated('Songs', async () => {
})
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.controls {
width: 100%;
min-height: 32px; // prevent shrinking causing the jumping effect
min-height: 32px; /* prevent shrinking causing the jumping effect */
display: flex;
justify-content: space-between;
align-items: center;

View file

@ -22,7 +22,7 @@
ref="listEl"
v-koel-overflow-fade
:class="`as-${viewMode}`"
class="artists main-scroll-wrap"
class="artists main-scroll-wrap artist-album-wrapper"
data-testid="artist-list"
>
<template v-if="showSkeletons">
@ -95,11 +95,3 @@ useRouter().onScreenActivated('Artists', async () => {
}
})
</script>
<style lang="scss">
#artistsWrapper {
.artists {
@include artist-album-wrapper();
}
}
</style>

View file

@ -1,5 +1,5 @@
<template>
<section v-if="artist" id="artistWrapper">
<section v-if="artist" id="artistWrapper" class="artist-album-info-wrapper">
<ScreenHeaderSkeleton v-if="loading" />
<ScreenHeader v-if="!loading && artist" :layout="songs.length === 0 ? 'collapsed' : headerLayout">
@ -65,12 +65,12 @@
</div>
<div v-show="activeTab === 'Albums'" class="albums-pane">
<ul v-if="albums" v-koel-overflow-fade class="as-list">
<ul v-if="albums" v-koel-overflow-fade class="as-list artist-album-wrapper">
<li v-for="album in albums" :key="album.id">
<AlbumCard :album="album" layout="compact" />
</li>
</ul>
<ul v-else class="as-list">
<ul v-else class="as-list artist-album-wrapper">
<li v-for="i in 12" :key="i">
<AlbumCardSkeleton layout="compact" />
</li>
@ -175,11 +175,3 @@ onScreenActivated('Artist', () => (artistId.value = parseInt(getRouteParam('id')
// if the current artist has been deleted, go back to the list
eventBus.on('SONGS_UPDATED', () => artistStore.byId(artist.value!.id) || go('artists'))
</script>
<style lang="scss" scoped>
@import "#/partials/_mixins.scss";
#artistWrapper {
@include artist-album-info-wrapper();
}
</style>

View file

@ -73,7 +73,7 @@ onMounted(async () => {
})
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.genres {
text-align: center;
@ -120,12 +120,34 @@ onMounted(async () => {
}
}
@for $i from 0 through 5 {
.level-#{$i} {
$zoom: 1 + $i * .4;
--unit: #{$zoom}rem;
opacity: .8 + $i * .04;
}
.level-0 {
--unit: 1rem;
opacity: .8;
}
.level-1 {
--unit: 1.4rem;
opacity: .84;
}
.level-2 {
--unit: 1.8rem;
opacity: .88;
}
.level-3 {
--unit: 2.2rem;
opacity: .92;
}
.level-4 {
--unit: 2.6rem;
opacity: .96;
}
.level-5 {
--unit: 3rem;
opacity: 1;
}
}
</style>

View file

@ -91,7 +91,7 @@ useRouter().onScreenActivated('Home', async () => {
})
</script>
<style lang="scss">
<style lang="postcss">
#homeWrapper {
.two-cols {
display: grid;
@ -127,7 +127,7 @@ useRouter().onScreenActivated('Home', async () => {
li {
overflow: hidden;
padding: 1px; // make space for focus outline
padding: 1px; /* make space for focus outline */
}
@media only screen and (max-width: 768px) {

View file

@ -91,7 +91,7 @@ const confirmThenSave = async () => {
}
</script>
<style lang="scss">
<style lang="postcss">
#settingsWrapper {
input[type="text"] {
width: 50%;

View file

@ -102,7 +102,7 @@ const retryAll = () => uploadService.retryAll()
const removeFailedEntries = () => uploadService.removeFailed()
</script>
<style lang="scss">
<style lang="postcss">
#uploadWrapper {
.upload-panel {
position: relative;

View file

@ -76,7 +76,7 @@ const showInviteUserForm = () => eventBus.emit('MODAL_SHOW_INVITE_USER_FORM')
onMounted(async () => await userStore.fetch())
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.users {
display: flex;
flex-direction: column;

View file

@ -76,7 +76,7 @@ const freeUp = () => {
onBeforeUnmount(() => freeUp())
</script>
<style lang="scss">
<style lang="postcss">
#vizContainer {
.viz {
height: 100%;

View file

@ -60,7 +60,7 @@ eventBus.on('PLAY_YOUTUBE_VIDEO', payload => {
})
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
:deep(#player) {
height: 100%;
flex: 1;

View file

@ -14,11 +14,11 @@ exports[`renders 1`] = `
</div>
<div data-v-8ea4eaa5="" data-v-5691beb5-s="" class="controls">
<div data-v-d396e0d2="" data-v-8ea4eaa5="" data-v-5691beb5-s="" class="song-list-controls" data-testid="song-list-controls">
<div data-v-d396e0d2="" class="wrapper"><span data-v-e884c19a="" data-v-d396e0d2="" class="btn-group" uppercased=""><button data-v-e368fe26="" data-v-d396e0d2="" class="btn-shuffle-all" data-testid="btn-shuffle-all" orange="" title="Shuffle all. Press Alt/⌥ to change mode."><br data-v-d396e0d2="" data-testid="Icon" icon="[object Object]" fixed-width=""> All </button><!--v-if--><!--v-if--><!--v-if--></span>
<div data-v-d396e0d2="" class="wrapper"><span data-v-e884c19a="" data-v-d396e0d2="" class="btn-group" uppercased=""><button data-v-e368fe26="" data-v-d396e0d2="" class="inset-when-pressed btn-shuffle-all" data-testid="btn-shuffle-all" orange="" title="Shuffle all. Press Alt/⌥ to change mode."><br data-v-d396e0d2="" data-testid="Icon" icon="[object Object]" fixed-width=""> All </button><!--v-if--><!--v-if--><!--v-if--></span>
<!--v-if-->
<!--v-if-->
</div>
<div data-v-d396e0d2="" class="menu-wrapper">
<div data-v-d396e0d2="" class="menu-wrapper context-menu">
<div data-v-42061e3e="" data-v-d396e0d2="" class="add-to" data-testid="add-to-menu" tabindex="0">
<section data-v-42061e3e="" class="existing-playlists">
<p data-v-42061e3e="">Add 0 songs to</p>
@ -26,7 +26,7 @@ exports[`renders 1`] = `
<li data-v-42061e3e="" data-testid="queue" tabindex="0">Queue</li>
<li data-v-42061e3e="" class="favorites" data-testid="add-to-favorites" tabindex="0"> Favorites </li>
</ul>
</section><button data-v-e368fe26="" data-v-42061e3e="" transparent="">New Playlist…</button>
</section><button data-v-e368fe26="" data-v-42061e3e="" class="inset-when-pressed" transparent="">New Playlist…</button>
</div>
</div>
</div>
@ -51,11 +51,11 @@ exports[`renders in Plus edition 1`] = `
</div>
<div data-v-8ea4eaa5="" data-v-5691beb5-s="" class="controls">
<div data-v-d396e0d2="" data-v-8ea4eaa5="" data-v-5691beb5-s="" class="song-list-controls" data-testid="song-list-controls">
<div data-v-d396e0d2="" class="wrapper"><span data-v-e884c19a="" data-v-d396e0d2="" class="btn-group" uppercased=""><button data-v-e368fe26="" data-v-d396e0d2="" class="btn-shuffle-all" data-testid="btn-shuffle-all" orange="" title="Shuffle all. Press Alt/⌥ to change mode."><br data-v-d396e0d2="" data-testid="Icon" icon="[object Object]" fixed-width=""> All </button><!--v-if--><!--v-if--><!--v-if--></span>
<div data-v-d396e0d2="" class="wrapper"><span data-v-e884c19a="" data-v-d396e0d2="" class="btn-group" uppercased=""><button data-v-e368fe26="" data-v-d396e0d2="" class="inset-when-pressed btn-shuffle-all" data-testid="btn-shuffle-all" orange="" title="Shuffle all. Press Alt/⌥ to change mode."><br data-v-d396e0d2="" data-testid="Icon" icon="[object Object]" fixed-width=""> All </button><!--v-if--><!--v-if--><!--v-if--></span>
<!--v-if-->
<!--v-if-->
</div>
<div data-v-d396e0d2="" class="menu-wrapper">
<div data-v-d396e0d2="" class="menu-wrapper context-menu">
<div data-v-42061e3e="" data-v-d396e0d2="" class="add-to" data-testid="add-to-menu" tabindex="0">
<section data-v-42061e3e="" class="existing-playlists">
<p data-v-42061e3e="">Add 0 songs to</p>
@ -63,7 +63,7 @@ exports[`renders in Plus edition 1`] = `
<li data-v-42061e3e="" data-testid="queue" tabindex="0">Queue</li>
<li data-v-42061e3e="" class="favorites" data-testid="add-to-favorites" tabindex="0"> Favorites </li>
</ul>
</section><button data-v-e368fe26="" data-v-42061e3e="" transparent="">New Playlist…</button>
</section><button data-v-e368fe26="" data-v-42061e3e="" class="inset-when-pressed" transparent="">New Playlist…</button>
</div>
</div>
</div><label data-v-8ea4eaa5="" data-v-5691beb5-s="" class="own-songs-toggle text-secondary"><span data-v-b5259680="" data-v-8ea4eaa5="" data-v-5691beb5-s="" class=""><input data-v-b5259680="" type="checkbox"></span><span data-v-8ea4eaa5="" data-v-5691beb5-s="">Own songs only</span></label>

View file

@ -14,7 +14,7 @@ exports[`renders 1`] = `
<div class="form-row"><label for="inputSettingsPath">Media Path</label>
<p id="mediaPathHelp" class="help"> The <em>absolute</em> path to the server directory containing your media. Koel will scan this directory for songs and extract any available information.<br> Scanning may take a while, especially if you have a lot of songs, so be patient. </p><input id="inputSettingsPath" aria-describedby="mediaPathHelp" name="media_path" type="text">
</div>
<div class="form-row"><button data-v-e368fe26="" type="submit">Scan</button></div>
<div class="form-row"><button data-v-e368fe26="" class="inset-when-pressed" type="submit">Scan</button></div>
</form>
</section>
`;

View file

@ -123,7 +123,7 @@ eventBus.on('SEARCH_KEYWORDS_CHANGED', async _q => {
})
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.results > section {
margin-bottom: 3em;
}

View file

@ -82,7 +82,7 @@ const {
watch(songs, () => songs.value.length || close())
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.add-to {
width: 100%;
max-width: 256px;

View file

@ -282,7 +282,7 @@ const submit = async () => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
form {
max-width: 540px;

View file

@ -55,7 +55,7 @@ const play = () => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
article {
display: flex;
gap: 12px;
@ -103,7 +103,7 @@ article {
}
}
// show the thumbnail's playback control on the whole card focus and hover
/* show the thumbnail's playback control on the whole card focus and hover */
&:hover :deep(.cover), &:focus :deep(.cover) {
.control {
display: flex;

View file

@ -10,7 +10,7 @@
</template>
<li class="has-sub">
Add To
<ul class="menu submenu menu-add-to">
<ul class="menu submenu menu-add-to context-menu">
<template v-if="queue.length">
<li v-if="currentSong" @click="queueSongsAfterCurrent">After Current Song</li>
<li @click="queueSongsToBottom">Bottom of Queue</li>
@ -224,7 +224,7 @@ eventBus.on('SONG_CONTEXT_MENU_REQUESTED', async ({ pageX, pageY }, _songs) => {
})
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
ul.playlists {
position: relative;
max-height: 192px;

View file

@ -380,7 +380,7 @@ defineExpose({
onMounted(() => render())
</script>
<style lang="scss">
<style lang="postcss">
.song-list-wrap {
position: relative;
display: flex;
@ -395,7 +395,7 @@ onMounted(() => render())
.song-list-header {
background: var(--color-bg-secondary);
display: flex;
z-index: 2; // fix stack-context related issue when e.g., footer would cover the sort context menu
z-index: 2; /* fix stack-context related issue when e.g., footer would cover the sort context menu */
}
&.dragging .song-item * {

View file

@ -89,7 +89,7 @@
</BtnGroup>
</div>
<div ref="addToMenu" v-koel-clickaway="closeAddToMenu" class="menu-wrapper">
<div ref="addToMenu" v-koel-clickaway="closeAddToMenu" class="menu-wrapper context-menu">
<AddToMenu :config="config.addTo" :songs="selectedSongs" @closing="closeAddToMenu" />
</div>
</div>
@ -175,7 +175,7 @@ onBeforeUnmount(() => {
})
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
.song-list-controls {
position: relative;
@ -186,8 +186,6 @@ onBeforeUnmount(() => {
}
.menu-wrapper {
@include context-menu();
padding: 0;
display: none;
}

View file

@ -51,7 +51,7 @@ const maybeClose = () => {
}
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
form {
display: flex;
border: 1px solid rgba(255, 255, 255, .1);

View file

@ -70,11 +70,11 @@ const collaborator = computed<Pick<User, 'name' | 'avatar'>>(() => (song.value a
const play = () => emit('play', song.value)
</script>
<style lang="scss">
<style lang="postcss">
.song-item {
color: var(--color-text-secondary);
border-bottom: 1px solid var(--color-bg-secondary);
max-width: 100% !important; // overriding .item
max-width: 100% !important; /* overriding .item */
height: 64px;
display: flex;
align-items: center;

View file

@ -3,7 +3,7 @@
<button ref="button" title="Sort" @click.stop="trigger">
<Icon :icon="faSort" />
</button>
<menu ref="menu" v-koel-clickaway="hide">
<menu ref="menu" v-koel-clickaway="hide" class="context-menu">
<li
v-for="item in menuItems"
:key="item.label"
@ -91,7 +91,7 @@ onMounted(() => menu.value && setup())
onBeforeUnmount(() => teardown())
</script>
<style lang="scss" scoped>
<style lang="postcss" scoped>
button {
width: 100%;

Some files were not shown because too many files have changed in this diff Show more