Compare commits
	
		
			10 Commits
		
	
	
		
			8d3586f4d4
			...
			7a1cdf2178
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 7a1cdf2178 | ||
|  | d013e62fcf | ||
|  | 9c1204b46b | ||
|  | 8541050011 | ||
|  | 480e8f008c | ||
|  | 7f8eb7bbb9 | ||
|  | 7e9c0d3caf | ||
|  | f972137389 | ||
|  | 7f8ed0e8a0 | ||
|  | 0ca4cc3bfe | 
							
								
								
									
										16
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						| @@ -1,16 +0,0 @@ | |||||||
| kind: pipeline |  | ||||||
| type: docker |  | ||||||
| name: default |  | ||||||
|  |  | ||||||
| steps: |  | ||||||
|   - name: deploy |  | ||||||
|     image: docker:dind |  | ||||||
|     commands: |  | ||||||
|     - apk add --upgrade npm bash findutils rsync sed |  | ||||||
|     - WORKDIR="/var/docker-web/apps/$DRONE_REPO_NAME" |  | ||||||
|     - rm -rf $WORKDIR |  | ||||||
|     - mkdir $WORKDIR |  | ||||||
|     - rsync -av --exclude  ./node_modules /drone/src/ $WORKDIR |  | ||||||
|     - cd $WORKDIR |  | ||||||
|     - npm ci |  | ||||||
|     - bash /var/docker-web/src/cli.sh up $DRONE_REPO_NAME |  | ||||||
							
								
								
									
										21
									
								
								.github/workflows/deploy.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,21 @@ | |||||||
|  | name: Deploy App | ||||||
|  | on: [push] | ||||||
|  |  | ||||||
|  | jobs: | ||||||
|  |   deploy: | ||||||
|  |     runs-on: ubuntu-22.04 | ||||||
|  |     container: | ||||||
|  |       volumes: | ||||||
|  |         - /var/docker-web:/var/docker-web | ||||||
|  |  | ||||||
|  |     steps: | ||||||
|  |       - uses: actions/checkout@v4 | ||||||
|  |       - name: install | ||||||
|  |         run: | | ||||||
|  |           APP_DIR=/var/docker-web/apps/${GITHUB_REPOSITORY##*/} | ||||||
|  |           mkdir -p $APP_DIR | ||||||
|  |           cp -a $(find . -mindepth 1 -maxdepth 1 ! -name '.git' ! -name 'node_modules') "$APP_DIR/" | ||||||
|  |       - name: up | ||||||
|  |         run: | | ||||||
|  |           export COMPOSE_BAKE=false | ||||||
|  |           bash /var/docker-web/src/cli.sh up ${GITHUB_REPOSITORY##*/} | ||||||
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -17,3 +17,8 @@ logs | |||||||
| .DS_Store | .DS_Store | ||||||
| .fleet | .fleet | ||||||
| .idea | .idea | ||||||
|  |  | ||||||
|  | # Local env files | ||||||
|  | .env | ||||||
|  | .env.* | ||||||
|  | !.env.example | ||||||
|   | |||||||
							
								
								
									
										37
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						| @@ -1,19 +1,30 @@ | |||||||
| # INSTALL | # Stage de build | ||||||
| FROM node:18-alpine as builder | FROM node:20-alpine AS build | ||||||
|  |  | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
|  |  | ||||||
|  | # Installer pnpm | ||||||
|  | RUN npm install -g pnpm | ||||||
|  |  | ||||||
|  | # Copier package.json et lockfile pour cache pnpm | ||||||
|  | COPY package.json pnpm-lock.yaml* ./ | ||||||
|  |  | ||||||
|  | RUN pnpm install --frozen-lockfile | ||||||
|  |  | ||||||
|  | # Copier tout le projet | ||||||
| COPY . . | COPY . . | ||||||
| RUN npm ci && npm cache clean --force |  | ||||||
| ADD . . |  | ||||||
|  |  | ||||||
| # BUILD | # Build Nuxt | ||||||
| RUN npm run build | RUN pnpm build | ||||||
|  |  | ||||||
|  | # Stage production | ||||||
|  | FROM node:20-alpine | ||||||
|  |  | ||||||
| # PROD |  | ||||||
| FROM node:18-alpine |  | ||||||
| WORKDIR /app | WORKDIR /app | ||||||
| COPY --from=builder /app/.output /app/.output |  | ||||||
| COPY --from=builder /app/.nuxt /app/.nuxt | COPY --from=build /app/.output .output | ||||||
| COPY --from=builder /app/.env /app/.env | COPY --from=build /app/package.json ./ | ||||||
| ENV HOST 0.0.0.0 | COPY --from=build /app/node_modules ./node_modules | ||||||
|  |  | ||||||
| EXPOSE 3000 | EXPOSE 3000 | ||||||
| CMD source .env && node .output/server/index.mjs | CMD ["node", ".output/server/index.mjs"] | ||||||
|   | |||||||
							
								
								
									
										76
									
								
								README.md
									
									
									
									
									
								
							
							
						
						| @@ -1 +1,75 @@ | |||||||
| # evilSpins | # Nuxt Minimal Starter | ||||||
|  |  | ||||||
|  | Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more. | ||||||
|  |  | ||||||
|  | ## Setup | ||||||
|  |  | ||||||
|  | Make sure to install dependencies: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | # npm | ||||||
|  | npm install | ||||||
|  |  | ||||||
|  | # pnpm | ||||||
|  | pnpm install | ||||||
|  |  | ||||||
|  | # yarn | ||||||
|  | yarn install | ||||||
|  |  | ||||||
|  | # bun | ||||||
|  | bun install | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Development Server | ||||||
|  |  | ||||||
|  | Start the development server on `http://localhost:3000`: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | # npm | ||||||
|  | npm run dev | ||||||
|  |  | ||||||
|  | # pnpm | ||||||
|  | pnpm dev | ||||||
|  |  | ||||||
|  | # yarn | ||||||
|  | yarn dev | ||||||
|  |  | ||||||
|  | # bun | ||||||
|  | bun run dev | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Production | ||||||
|  |  | ||||||
|  | Build the application for production: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | # npm | ||||||
|  | npm run build | ||||||
|  |  | ||||||
|  | # pnpm | ||||||
|  | pnpm build | ||||||
|  |  | ||||||
|  | # yarn | ||||||
|  | yarn build | ||||||
|  |  | ||||||
|  | # bun | ||||||
|  | bun run build | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Locally preview production build: | ||||||
|  |  | ||||||
|  | ```bash | ||||||
|  | # npm | ||||||
|  | npm run preview | ||||||
|  |  | ||||||
|  | # pnpm | ||||||
|  | pnpm preview | ||||||
|  |  | ||||||
|  | # yarn | ||||||
|  | yarn preview | ||||||
|  |  | ||||||
|  | # bun | ||||||
|  | bun run preview | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information. | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								app.vue
									
									
									
									
									
								
							
							
						
						| @@ -1,11 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <NuxtPage /> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup> |  | ||||||
| // @todo : laod datas as plugin/middleware (cant load pinia in plugin/middleware) ? |  | ||||||
| onMounted(async ()=>{ |  | ||||||
|   const dataStore = await useDataStore() |  | ||||||
|   await dataStore.loadData() |  | ||||||
| }) |  | ||||||
| </script> |  | ||||||
							
								
								
									
										6
									
								
								app/app.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | |||||||
|  | <template> | ||||||
|  |   <NuxtLayout> | ||||||
|  |     <NuxtPage /> | ||||||
|  |     <NuxtRouteAnnouncer /> | ||||||
|  |   </NuxtLayout> | ||||||
|  | </template> | ||||||
							
								
								
									
										8
									
								
								app/components/atropos.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,8 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="flex items-center justify-center min-h-screen"> | ||||||
|  |     <atropos-component class="h-72 w-60" active-offset="80" shadow-scale="1.05"> | ||||||
|  |       <img src="/logo.svg"> | ||||||
|  |       <img src="/ES01A/object.png"> | ||||||
|  |     </atropos-component> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
							
								
								
									
										96
									
								
								app/pages/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,96 @@ | |||||||
|  | <template> | ||||||
|  |   <div> | ||||||
|  |     <div class="background fixed w-full h-full"> | ||||||
|  |       <video class="animation screen" loop autoplay muted ref="animation"> | ||||||
|  |         <source src="https://files.erudi.fr/evilspins/sloughi-run-loop-big.webm" type="video/webm"> | ||||||
|  |         <source src="https://files.erudi.fr/evilspins/sloughi-run-loop-small.webm" type="video/webm" | ||||||
|  |           media="all and (max-width: 640px)"> | ||||||
|  |       </video> | ||||||
|  |     </div> | ||||||
|  |     <section class="splash-screen flex items-center flex-col"> | ||||||
|  |       <figure class="ui"> | ||||||
|  |         <img class="logo" src="/logo.svg"> | ||||||
|  |       </figure> | ||||||
|  |     </section> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <style scoped> | ||||||
|  | body { | ||||||
|  |   margin: 0; | ||||||
|  |   overflow-x: hidden; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .logo, | ||||||
|  | .button, | ||||||
|  | .shadow, | ||||||
|  | .animation, | ||||||
|  | .mix { | ||||||
|  |   transition: .7s opacity; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .screen { | ||||||
|  |   position: absolute; | ||||||
|  |   height: 100vh; | ||||||
|  |   min-width: 100%; | ||||||
|  |   max-width: 100%; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .splash-screen { | ||||||
|  |   position: relative; | ||||||
|  |   height: 100vh; | ||||||
|  |   box-shadow: inset black 0px 1px 800px 200px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .animation { | ||||||
|  |   z-index: 1; | ||||||
|  |   object-fit: cover; | ||||||
|  |   opacity: .8; | ||||||
|  |   /* opacity: 0; */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .mix { | ||||||
|  |   z-index: 4; | ||||||
|  |   position: fixed; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .shadow { | ||||||
|  |   z-index: 3; | ||||||
|  |   box-shadow: rgb(0, 0, 0) 0px 0px 170px 70px inset; | ||||||
|  |   opacity: .9; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .ui { | ||||||
|  |   z-index: 4; | ||||||
|  |   position: absolute; | ||||||
|  |   top: 50%; | ||||||
|  |   left: 50%; | ||||||
|  |   max-width: 80%; | ||||||
|  |   transform: translate(-50%, -50%); | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   align-items: center; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .logo { | ||||||
|  |   filter: drop-shadow(8px 8px 0 rgb(0 0 0 / 0.8)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .mixPlayer { | ||||||
|  |   background: black; | ||||||
|  |   max-height: 70vh; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .hide { | ||||||
|  |   opacity: 0; | ||||||
|  |   z-index: 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .show { | ||||||
|  |   opacity: 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .text-shadow { | ||||||
|  |   text-shadow: 3px 2px 8px black; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										3
									
								
								app/pages/wait.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,3 @@ | |||||||
|  | <template> | ||||||
|  |   <atropos /> | ||||||
|  | </template> | ||||||
| @@ -1,45 +0,0 @@ | |||||||
| @tailwind base; |  | ||||||
| @tailwind components; |  | ||||||
| @tailwind utilities; |  | ||||||
|  |  | ||||||
| body { |  | ||||||
|   @apply bg-black; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .button { |  | ||||||
|   text-decoration: none; |  | ||||||
|   box-shadow: 0 8px 0 0 black; |  | ||||||
|   transition: all .3s; |  | ||||||
|   border: 8px black solid; |  | ||||||
|   line-height: 100%; |  | ||||||
|   border-width: 2px; |  | ||||||
|   border-radius: 100px; |  | ||||||
|   cursor: pointer; |  | ||||||
|   color: black; |  | ||||||
|   font-size: 26px; |  | ||||||
|   background-color: #ffffff59; |  | ||||||
|   height: 40px; |  | ||||||
|   width: 40px; |  | ||||||
|  |  | ||||||
|   @media (min-width: 780px) { |  | ||||||
|     height: 70px; |  | ||||||
|     width: 70px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .button:hover { |  | ||||||
|   background-color: #fdec50ff; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .button:active { |  | ||||||
|   box-shadow: 0 0 0 0 black; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .button--screened { |  | ||||||
|   top: 74px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .compilation { |  | ||||||
|   cursor: pointer; |  | ||||||
|   max-width: 420px; |  | ||||||
| } |  | ||||||
| @@ -1,22 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <NuxtLink :to="'/compilations/' + props.data.id" class="compilation mx-auto p-4 inline-flex"> |  | ||||||
|     <atropos-component class="my-atropos" active-offset="80" shadow-scale="1.05"> |  | ||||||
|       <img :src="props.data.id + '/bkg.jpg'" data-atropos-offset="-8" /> |  | ||||||
|       <img :src="props.data.id + '/object.png'" data-atropos-offset="-3" class="absolute inset-0 object-cover" /> |  | ||||||
|       <img :src="props.data.id + '/name.png'" data-atropos-offset="0" class="absolute inset-0 object-cover" /> |  | ||||||
|       <img src="/logo.svg" data-atropos-offset="0" width="70%" class="logo absolute inset-0" /> |  | ||||||
|     </atropos-component> |  | ||||||
|   </NuxtLink> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup> |  | ||||||
| const props = defineProps(['data', 'template']) |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped> |  | ||||||
| .logo { |  | ||||||
|   filter: drop-shadow(4px 4px 0 rgb(0 0 0 / 0.5)); |  | ||||||
|   left: 14%; |  | ||||||
|   top: 10%; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section> |  | ||||||
|     <div v-for="compilation in store.getAllCompilations" class="text-white"> |  | ||||||
|       <compilationObject :data="compilation" template="full" /> |  | ||||||
|     </div> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup lang="ts"> |  | ||||||
| const store = useDataStore() |  | ||||||
| </script> |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| <script setup lang="ts"> |  | ||||||
| const isLoaded = ref(false) |  | ||||||
| const isPlaying = ref(false) |  | ||||||
| const video = ref() |  | ||||||
| async function play() { |  | ||||||
|   await video.value.player.playVideo() |  | ||||||
| } |  | ||||||
| function stateChange(event) { |  | ||||||
|   isPlaying.value = event.data === 1 |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <template> |  | ||||||
|   <div> |  | ||||||
|     <div class="flex items-center justify-center p-5"> |  | ||||||
|       <ScriptYouTubePlayer ref="video" video-id="iyPiiZly864" class="group" @ready="isLoaded = true" @state-change="stateChange"> |  | ||||||
|         <template #awaitingLoad> |  | ||||||
|           <div class="absolute left-1/2 top-1/2 transform -translate-x-1/2 -translate-y-1/2 h-[48px] w-[68px]"> |  | ||||||
|             <svg height="100%" version="1.1" viewBox="0 0 68 48" width="100%"><path d="M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z" fill="#f00" /><path d="M 45,24 27,14 27,34" fill="#fff" /></svg> |  | ||||||
|           </div> |  | ||||||
|         </template> |  | ||||||
|       </ScriptYouTubePlayer> |  | ||||||
|     </div> |  | ||||||
|     <div class="text-center"> |  | ||||||
|       <div v-if="!isLoaded" class="mb-5" size="sm" color="blue" variant="soft" title="Click to load" description="Clicking the video will load the Vimeo iframe and start the video." /> |  | ||||||
|       <button v-if="isLoaded && !isPlaying" @click="play"> |  | ||||||
|         Play Video |  | ||||||
|       </button> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
| @@ -1,28 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div class="compilation mx-auto p-4 inline-flex"> |  | ||||||
|     <atropos-component ref="atropos" class="my-atropos" active-offset="80" shadow-scale="1.05"> |  | ||||||
|       <img src="/zero/sky-b.jpg" data-atropos-offset="-8" /> |  | ||||||
|       <img src="/zero/propeller-b.png" data-atropos-offset="-3" class="absolute inset-0 object-cover" /> |  | ||||||
|       <img src="/zero/zero-b.png" data-atropos-offset="0" class="absolute inset-0 object-cover" /> |  | ||||||
|       <img src="/logo.svg" data-atropos-offset="0" width="70%" class="logo absolute inset-0" /> |  | ||||||
|     </atropos-component> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup> |  | ||||||
| import { onMounted, ref } from 'vue' |  | ||||||
|  |  | ||||||
| const atropos = ref(null) |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped> |  | ||||||
| /* .my-atropos { |  | ||||||
|   width: 320px; |  | ||||||
|   height: 160px; |  | ||||||
| } */ |  | ||||||
| .logo { |  | ||||||
|     filter: drop-shadow(4px 4px 0 rgb(0 0 0 / 0.5)); |  | ||||||
|     left: 14%; |  | ||||||
|     top: 10%; |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
							
								
								
									
										5
									
								
								config.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						| @@ -0,0 +1,5 @@ | |||||||
|  | export REPO_NAME="evilspins" | ||||||
|  | export DOMAIN="evilspins.$MAIN_DOMAIN" | ||||||
|  | export PORT="7901" | ||||||
|  | export PORT_EXPOSED="3000" | ||||||
|  | export REDIRECTIONS="" # example.$MAIN_DOMAIN->/route $MAIN_DOMAIN->url /route->/another-route /route->url | ||||||
| @@ -1,18 +1,21 @@ | |||||||
| services: | services: | ||||||
|  |  | ||||||
|   evilspins: |   evilspins: | ||||||
|     build: . |     image: local/evilspins | ||||||
|  |     build: | ||||||
|  |       context: . | ||||||
|  |       dockerfile: Dockerfile | ||||||
|     container_name: evilspins |     container_name: evilspins | ||||||
|     restart: unless-stopped |     restart: unless-stopped | ||||||
|  |     working_dir: /app | ||||||
|     ports: |     ports: | ||||||
|       - $PORT:3000 |       - "${PORT}:${PORT_EXPOSED}" | ||||||
|  |     volumes: | ||||||
|  |       - "${MEDIA_DIR}:/mnt/media" | ||||||
|     environment: |     environment: | ||||||
|       VIRTUAL_HOST: "${DOMAIN}" |       VIRTUAL_HOST: "${DOMAIN}" | ||||||
|       LETSENCRYPT_HOST: "${DOMAIN}" |       LETSENCRYPT_HOST: "${DOMAIN}" | ||||||
|       PUID: "${PUID}" |       PUID: "${PUID}" | ||||||
|       PGID: "${PGID}" |       PGID: "${PGID}" | ||||||
|     volumes: |  | ||||||
|       - "${MEDIA_DIR}:/app/media" |  | ||||||
|  |  | ||||||
| networks: | networks: | ||||||
|   default: |   default: | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								eslint.config.mjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,6 @@ | |||||||
|  | // @ts-check | ||||||
|  | import withNuxt from './.nuxt/eslint.config.mjs' | ||||||
|  |  | ||||||
|  | export default withNuxt( | ||||||
|  |   // Your custom configs here | ||||||
|  | ) | ||||||
							
								
								
									
										125
									
								
								logo.svg
									
									
									
									
									
								
							
							
						
						| Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 2.4 KiB | 
| @@ -1,24 +1,11 @@ | |||||||
| // https://nuxt.com/docs/api/configuration/nuxt-config | // https://nuxt.com/docs/api/configuration/nuxt-config | ||||||
| export default defineNuxtConfig({ | export default defineNuxtConfig({ | ||||||
|   ssr: true, |   compatibilityDate: '2025-07-15', | ||||||
|   devtools: { enabled: true }, |   devtools: { enabled: true }, | ||||||
|   css: ['~/assets/css/main.css'], |   modules: ['@nuxt/eslint', '@nuxtjs/tailwindcss', '@pinia/nuxt'], | ||||||
|  |   vue: { | ||||||
|   postcss: { |     compilerOptions: { | ||||||
|     plugins: { |       isCustomElement: (tag) => ['atropos-component'].includes(tag) | ||||||
|       tailwindcss: {}, |  | ||||||
|       autoprefixer: {}, |  | ||||||
|  |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   app: { |  | ||||||
|     head: { |  | ||||||
|       charset: 'utf-8', |  | ||||||
|       viewport: 'width=device-width, initial-scale=1', |  | ||||||
|     } |     } | ||||||
|   }, |   } | ||||||
|  |  | ||||||
|   compatibilityDate: '2024-07-10', |  | ||||||
|   modules: ['@pinia/nuxt'] |  | ||||||
| }) | }) | ||||||
							
								
								
									
										8186
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
							
								
								
									
										25
									
								
								package.json
									
									
									
									
									
								
							
							
						
						| @@ -1,27 +1,28 @@ | |||||||
| { | { | ||||||
|   "name": "nuxt-app", |   "name": "nuxt-app", | ||||||
|   "private": true, |  | ||||||
|   "type": "module", |   "type": "module", | ||||||
|  |   "private": true, | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "build": "nuxt build", |     "build": "nuxt build", | ||||||
|     "dev": "nuxt dev --host", |     "dev": "nuxt dev", | ||||||
|     "generate": "nuxt generate", |     "generate": "nuxt generate", | ||||||
|     "preview": "nuxt preview", |     "preview": "nuxt preview", | ||||||
|     "postinstall": "nuxt prepare" |     "postinstall": "nuxt prepare" | ||||||
|   }, |   }, | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@pinia/nuxt": "^0.5.5", |     "@nuxt/eslint": "1.9.0", | ||||||
|  |     "@nuxtjs/tailwindcss": "6.14.0", | ||||||
|     "atropos": "^2.0.2", |     "atropos": "^2.0.2", | ||||||
|     "nuxt": "^3.12.3", |     "eslint": "^9.33.0", | ||||||
|     "pinia": "^2.2.4", |     "nuxt": "^4.0.3", | ||||||
|     "unhead": "^1.9.15", |     "vue": "^3.5.18", | ||||||
|     "vue": "^3.4.31", |     "vue-router": "^4.5.1" | ||||||
|     "vue-router": "^4.4.0" |  | ||||||
|   }, |   }, | ||||||
|  |   "engines": { | ||||||
|  |     "pnpm": ">=10 <11" | ||||||
|  |   }, | ||||||
|  |   "packageManager": "pnpm@10.14.0+sha512.ad27a79641b49c3e481a16a805baa71817a04bbe06a38d17e60e2eaee83f6a146c6a688125f5792e48dd5ba30e7da52a5cda4c3992b9ccf333f9ce223af84748", | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "autoprefixer": "^10.4.19", |     "@pinia/nuxt": "^0.11.2" | ||||||
|     "postcss": "^8.4.39", |  | ||||||
|     "sass": "^1.77.6", |  | ||||||
|     "tailwindcss": "^3.4.4" |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										137
									
								
								pages/about.vue
									
									
									
									
									
								
							
							
						
						| @@ -1,137 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div class="text-white p-12 text-lg flex flex-col items-center"> |  | ||||||
|     <a href="/" class="mb-12"> |  | ||||||
|       <img class="logo" src="/logo.svg"> |  | ||||||
|     </a> |  | ||||||
|     <div class="max-w-4xl"> |  | ||||||
|       <h1 class="text-esyellow text-6xl mb-8">About evilSpins ...</h1> |  | ||||||
|       <pre> |  | ||||||
|         Rather than explaining the "artistic" approach of evilspins in too formal a manner, I prefer to freely share the notes and sketches as a testament to the project's long genesis (2019 -> 2024) : |  | ||||||
|       </pre> |  | ||||||
|       <pre> |  | ||||||
|       "The idea of the name comes from Anton Newcombe, who defines music as something that must remain independent, |  | ||||||
|       hence his quote "keep music evil", from which 'evil' and 'spins' refer to music as an object that turns (cassette, |  | ||||||
|       vinyl, CD...), music is a living object in perpetual motion and it's 'evil' / independent / unmanageable because |  | ||||||
|       it makes you dance, it takes the listener without even realizing it. |  | ||||||
|     </pre> |  | ||||||
|       <img src="https://files.erudi.fr/evilspins/ABOUT-1.jpg"> |  | ||||||
|       <pre> |  | ||||||
|       Each compilation is the original soundtrack of a non-existent film. It must leave room for imagination and |  | ||||||
|       reflection. |  | ||||||
|       A compilation tries to produce the effect of a film, to provoke imagination. |  | ||||||
|       It's an opportunity to decontextualize forgotten, outdated, or unconsciously caricatured musical genres |  | ||||||
|       (bluegrass, |  | ||||||
|       punk, folk, hip-hop...) or simply to discover new genres. |  | ||||||
|       Approach music without thinking about the stylistic references of the piece, like in a film. |  | ||||||
|     </pre> |  | ||||||
|       <img src="https://files.erudi.fr/evilspins/ABOUT-2.jpg"> |  | ||||||
|       <pre> |  | ||||||
|       A compilation can therefore offer several readings, |  | ||||||
|       - a panel of characters, |  | ||||||
|       - several versions (short, long like a director's cut, side A/B (side B could be a parallel version with the same |  | ||||||
|       artists in the same order but with different titles very close)) |  | ||||||
|       - several possible reading modes (mode 1: only the mixed sound and artworks (only play/pause is available), |  | ||||||
|       mode 2: portraits and names of the protagonists, anecdotes, quotes, and web links (possibility to go to the |  | ||||||
|       next/previous track and to 'seek')) |  | ||||||
|       - an artwork (square format (vinyl) or 16/9 + black band (cinema)) - vocal samples to make characters speak? |  | ||||||
|       (samples of artists in interviews, for example) |  | ||||||
|       - a mix must follow this order: |  | ||||||
|       List of quintessence sound : |  | ||||||
|       1. accessible but instrumental |  | ||||||
|       2. more researched and instrumental |  | ||||||
|       3. more rhythmic instrumental |  | ||||||
|       4->7. rhythmic sung |  | ||||||
|       8. rhythmic instrumental |  | ||||||
|       9. Instrumental |  | ||||||
|       10. bluegrass final Evils spins from the idea that music needs the imagination of its listener. |  | ||||||
|       11. hidden track |  | ||||||
|     </pre> |  | ||||||
|       <img src="https://files.erudi.fr/evilspins/ABOUT-3.jpg"> |  | ||||||
|       <pre> |  | ||||||
|       Design: timeline of the player like the itinerary of a journey on a map OR like a display board at a train |  | ||||||
|       station/airport "A problem created cannot be solved by thinking in the same way it was created." "God only depends |  | ||||||
|       on the imagination of men" Drawing situations where you meet someone you think you know well but who doesn't have |  | ||||||
|       the same vision of things as you. Example: discussion about music and completely divergent points of view, (Nick |  | ||||||
|       Waterhouse = completely inaccessible jazz) Going to see local labels inventing a religion and therefore a god, is |  | ||||||
|       only a way to personify one's conscience. The projects converge on the concept of a "cyber residence of artists" |  | ||||||
|       drawing a face to one's morality. Dreams are nightmares, nightmares are dreams. Starting from reflections on the |  | ||||||
|       use |  | ||||||
|       of new technologies; questioning one's use of the internet on one's computer, phone, etc., allows one to wonder |  | ||||||
|       what? when? why do I need the internet, to watch a movie, to listen to music... In my case, the answers to these |  | ||||||
|       questions propose a use that mixes tools and methods from different eras. TOOLS & METHODS FROM DIFFERENT |  | ||||||
|       ERAS/CONTEXTS Just like in the film 'La fille du 14 juillet', it can be very interesting to play on the contrasts |  | ||||||
|       between different eras by mixing them in the same visual and sound realization. Idea of realization graphic novel |  | ||||||
|       or |  | ||||||
|       comic book: Observation: with the revolution of the internet and new technologies, cinema has become a major art |  | ||||||
|       that everyone masters more or less. The public's gaze is sharpened and everyone knows how to apprehend |  | ||||||
|       cinematographic realization. The plans, camera movements, sound effects are a language that everyone knows how to |  | ||||||
|       read (cinema is carried by all through downloading & streaming) ... and even write (I can make a film with my |  | ||||||
|       phone, |  | ||||||
|       reflex cameras have become affordable). How to draw cinema? Try to take key scenes from cinema, draw/paint them |  | ||||||
|       and |  | ||||||
|       animate them. fixed plan? traveling? zoom? panoramic? plunge? counter-plunge? wide-angle? long focal? work on the |  | ||||||
|       Wikipedia of 'film noir' re-watch film noir link with the polar noir? film noir has a pretentious approach at |  | ||||||
|       first |  | ||||||
|       glance. so we need to find a technique (visual? sound?) to disarm this bad image. to do this we need to start by |  | ||||||
|       isolating and understanding the possible pretentious aspect of film noir. |  | ||||||
|     </pre> |  | ||||||
|       <img src="https://files.erudi.fr/evilspins/ABOUT-4.jpg"> |  | ||||||
|       <pre> |  | ||||||
|       The solitude of the character? The |  | ||||||
|       voice-overs that narrate the thoughts? The appearance of the protagonist? The cliché (visual & script) of the |  | ||||||
|       polar |  | ||||||
|       noir too worn out? (the detective alone in his thoughts, in his apartment smoking a cigarette on the balcony) the |  | ||||||
|       cigarette can still be a more powerful visual element than a cliché transition with animation of the cigarette? |  | ||||||
|       cigarette = huge filmographic symbol == we find it in most films especially in the era of film noir == commercial |  | ||||||
|       influence tool == influence of American culture (cowboy), == symbol of the ephemeral, like life, like the |  | ||||||
|       characters |  | ||||||
|       of a film, like a film. the 2 mega clichés: Nicholson/Polansky in Chinatown & Ridley Scott in Blade Runner How to |  | ||||||
|       integrate the cigarette? = 3D animation? (often ugly, technically very difficult, aesthetically difficult) = |  | ||||||
|       hand-drawn animation? (long... very long to do but good pretext to train) = vector-drawn animation? (technically |  | ||||||
|       moderately difficult but aesthetically difficult) = film excerpts? (technically easy & aesthetically very easy BUT |  | ||||||
|       not really creation (montage), and illegal... to check) = animation of the spin (film zoom in Cassette, CD, Vinyl, |  | ||||||
|       the plates of a hard drive (joke -> why not make a montage effect), find an equivalent for digital (server bays, |  | ||||||
|       server fan? (joke))) why not call the box to meet at Slift to turn it properly and start a collaboration? |  | ||||||
|       otherwise, |  | ||||||
|       a lot of material to Bellecours photo + ... Fnac? no, much more interesting to go through a collaboration. Take |  | ||||||
|       out |  | ||||||
|       the rushes of films. |  | ||||||
|     </pre> |  | ||||||
|       <img src="https://files.erudi.fr/evilspins/ABOUT-5.jpg"> |  | ||||||
|       <pre> |  | ||||||
|  |  | ||||||
|       The thinking of Jack Nicholson in Chinatown No visual drawing during the reading of the piece, |  | ||||||
|       only why not the log / cover / artwork of the album the reading should not look like a PowerPoint, the |  | ||||||
|       counter-example is everywhere on YouTube. On the other hand, a drawn and animated artwork in parallax why not. See |  | ||||||
|       3D js cover -> at the mouse movement: preview with animation -> At the click fade of the box zoom on the cover the |  | ||||||
|       animation is no longer manual but automatic (linear movement? random?) after the cigarette... the smoke... too |  | ||||||
|       cliché? possible but the smoke can make a transition between 2 listens / animations. the listening ends the smoke |  | ||||||
|       arrives brings us to the cigarette which brings us to a protagonist who brings us to a film excerpt. why |  | ||||||
|       evilspins? |  | ||||||
|       The spin obviously refers to the movement of music both by its format (cassette, vinyl, CD) and by its effect |  | ||||||
|       (membrane, air movement, dance) possible sound effect: end of the piece Purple Mercy - Purple -> the end of the |  | ||||||
|       piece ends with an abrupt snare with a subtle reverb -> effect felt: conclusion on an impression of grand space -> |  | ||||||
|       effect analyzed / symbolic: grandeur of the proposal but above all empty room -> no public -> therefore call to |  | ||||||
|       the |  | ||||||
|       public -> idea expressible: maybe too pretentious again. film noir has a pretentious image at first glance. we |  | ||||||
|       need |  | ||||||
|       to find a technique (visual? sound?) to disarm this bad image. to do this we need to start by isolating and |  | ||||||
|       understanding the possible pretentious aspect of film noir. The solitude of the character? The voice-overs that |  | ||||||
|       narrate the thoughts? The appearance of the protagonist? The cliché (visual & script) of the polar noir too worn |  | ||||||
|       out? (the detective alone in his thoughts, in his apartment smoking a cigarette on the balcony)" |  | ||||||
|     </pre> |  | ||||||
|       <img src="https://files.erudi.fr/evilspins/ABOUT-6.jpg"> |  | ||||||
|     </div> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <style scoped> |  | ||||||
| img { |  | ||||||
|   margin: 32px 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| pre { |  | ||||||
|   white-space: pre-line; |  | ||||||
|   font-family: sans-serif; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,154 +0,0 @@ | |||||||
| <template @keydown.esc="closePlayer()"> |  | ||||||
|   <div class="text-white w-full flex items-center flex-col"> |  | ||||||
|     <button class="text-sm md:text-5xl leading-none button button--close m-3 flex justify-center items-center z-50" |  | ||||||
|       @click="closePlayer()"> |  | ||||||
|     </button> |  | ||||||
|     <video class="mixPlayer w-full" controls ref="mixPlayer"> |  | ||||||
|       <source :src="videoSD" type="video/mp4"> |  | ||||||
|     </video> |  | ||||||
|     <nav class="text-esyellow w-full flex" v-if="currentTrack"> |  | ||||||
|       <button v-for="(track, index) in tracks" @click="listenTo(track.start)" :index="track.id" |  | ||||||
|         class="border-l-wihte-400 border-l-2 p-2 flex-grow hover:bg-esyellow hover:text-black" |  | ||||||
|         :class="{ 'border-l-0': index === 0, 'bg-esyellow text-black': track.id === currentTrack.id }"> |  | ||||||
|         <span class="block"> |  | ||||||
|           {{ index + 1 }} |  | ||||||
|         </span> |  | ||||||
|         <span class="hidden 2xl:block"> |  | ||||||
|           {{ track.title }} |  | ||||||
|         </span> |  | ||||||
|         <span class="hidden lg:block"> |  | ||||||
|           {{ getArtistName(track.artist) }} |  | ||||||
|         </span> |  | ||||||
|       </button> |  | ||||||
|     </nav> |  | ||||||
|  |  | ||||||
|     <article class="text-white p-8 max-w-5xl" v-if="currentTrack"> |  | ||||||
|       <div class="flex flex-col sm:flex-row items-center "> |  | ||||||
|         <a :href="currentTrack.url" target="_blank" class="mr-4"> |  | ||||||
|           <atropos-component> |  | ||||||
|             <img class="flex-grow-0" :src="'https://f4.bcbits.com/img/' + currentTrack.cover + '_8.jpg'" /> |  | ||||||
|           </atropos-component> |  | ||||||
|         </a> |  | ||||||
|         <div> |  | ||||||
|           <a :href="currentTrack.url" target="_blank" rel="noopener noreferrer"> |  | ||||||
|             <h3 class="text-5xl"> |  | ||||||
|               {{ currentTrack.title }} |  | ||||||
|             </h3> |  | ||||||
|           </a> |  | ||||||
|           <a v-if="currentArtist" :href="currentArtist.url" target="_blank" rel="noopener noreferrer"> |  | ||||||
|             <h2 class="font-bold text-6xl text-esyellow"> |  | ||||||
|               {{ currentArtist.name }} |  | ||||||
|             </h2> |  | ||||||
|           </a> |  | ||||||
|           <h4 class="text-xl text-slate-200"> |  | ||||||
|             {{ compilation.name }} |  | ||||||
|           </h4> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|  |  | ||||||
|       <p class="block mt-10"> |  | ||||||
|         see artist page:<br> |  | ||||||
|         <a v-if="currentArtist" target="_blank" class="underline text-orange-500 hover:text-orange-400" |  | ||||||
|           :href="currentArtist.url"> |  | ||||||
|           {{ currentArtist.name }} |  | ||||||
|         </a><br> |  | ||||||
|         purchase the track:<br> |  | ||||||
|         <a target="_blank" class="underline text-orange-500 hover:text-orange-400" :href="currentTrack.url"> |  | ||||||
|           {{ currentTrack.title }} |  | ||||||
|         </a><br> |  | ||||||
|         <br> |  | ||||||
|       </p> |  | ||||||
|     </article> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script setup lang="ts"> |  | ||||||
| const route = useRoute() |  | ||||||
| const store = useDataStore() |  | ||||||
|  |  | ||||||
| const compilation = ref() |  | ||||||
| const tracks = ref() |  | ||||||
| const mixPlayer = ref() |  | ||||||
| const videoSD = ref() |  | ||||||
| const currentTrack = ref() |  | ||||||
| const { isLoaded } = storeToRefs(store) |  | ||||||
| const currentArtist = computed(() => { |  | ||||||
|   return store.getArtistById(currentTrack.value.artist) |  | ||||||
| }) |  | ||||||
| const getArtistName = (id: number) => { |  | ||||||
|   return store.getArtistById(id)?.name |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // LOAD DATAs |  | ||||||
|  |  | ||||||
| onMounted(() => { |  | ||||||
|   loadCompilation() // if user arrive directly on compilation page |  | ||||||
| }) |  | ||||||
| watch(isLoaded, () => { |  | ||||||
|   loadCompilation() // if the user came from another page |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| const watchPlayingTrack = () => { |  | ||||||
|   setInterval(() => { |  | ||||||
|     if (mixPlayer.value && compilation.value.id) { |  | ||||||
|       currentTrack.value = tracks.value.find((track: { start: number; }, index: number) => { |  | ||||||
|         const nextTrackStart = tracks.value[index + 1]?.start ?? Infinity |  | ||||||
|         return track.start <= mixPlayer.value.currentTime && mixPlayer.value.currentTime < nextTrackStart |  | ||||||
|       }) |  | ||||||
|     } |  | ||||||
|   }, 1000) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const loadCompilation = () => { |  | ||||||
|   if (isLoaded.value) { |  | ||||||
|     compilation.value = store.getCompilationById(route.params.id as string) |  | ||||||
|     tracks.value = store.getTracksByCompilationId(route.params.id as string) |  | ||||||
|     videoSD.value = 'https://files.erudi.fr/evilspins/' + compilation.value.id + '-SD.mp4' |  | ||||||
|     mixPlayer.value.load() |  | ||||||
|     mixPlayer.value.play() |  | ||||||
|     mixPlayer.value.focus() |  | ||||||
|     watchPlayingTrack() |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const listenTo = (start: number) => { |  | ||||||
|   mixPlayer.value.currentTime = start |  | ||||||
|   mixPlayer.value.play() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const closePlayer = async () => { |  | ||||||
|   await navigateTo('/') |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| body { |  | ||||||
|   margin: 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .logo { |  | ||||||
|   filter: drop-shadow(8px 8px 0 rgb(0 0 0 / 0.8)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| a:hover { |  | ||||||
|   text-decoration: underline; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .mixPlayer { |  | ||||||
|   background: black; |  | ||||||
|   max-height: 70vh; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| nav>button:first-child { |  | ||||||
|   border-left: none; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .button--close { |  | ||||||
|   position: fixed; |  | ||||||
|   right: 2vw; |  | ||||||
|  |  | ||||||
|   &:after { |  | ||||||
|     content: "\00d7"; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
							
								
								
									
										127
									
								
								pages/index.vue
									
									
									
									
									
								
							
							
						
						| @@ -1,127 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div> |  | ||||||
|     <div class="w-full flex justify-center"> |  | ||||||
|       <nav class="[&>*]:p-2 text-white bottom-0 right-0 fixed flex justify-center z-50"> |  | ||||||
|         <a href="https://www.youtube.com/channel/UCATtFHnOLDCv8qroi2KW3ZA" target="about:blank" class="mt-1"> |  | ||||||
|           <img src="/youtube.svg" alt="youtube channel" /> |  | ||||||
|         </a> |  | ||||||
|         <a href="mailto:contact@evilspins.com">📬</a> |  | ||||||
|         <a href="/about">❓</a> |  | ||||||
|       </nav> |  | ||||||
|     </div> |  | ||||||
|     <section class="splash-screen flex items-center flex-col"> |  | ||||||
|       <figure class="ui"> |  | ||||||
|         <img class="logo" src="/logo.svg"> |  | ||||||
|         <h1 class="text-white pt-6 text-sm md:text-md lg:text-lg text-center font-bold tracking-widest">Compilations |  | ||||||
|           Indépendantes |  | ||||||
|         </h1> |  | ||||||
|         <button class="button button--screened relative top-16 flex justify-center items-center" @click="scrollDown()"> |  | ||||||
|           ↓ |  | ||||||
|         </button> |  | ||||||
|       </figure> |  | ||||||
|       <div class="shadow screen" /> |  | ||||||
|       <video class="animation screen" loop autoplay muted ref="animation"> |  | ||||||
|         <source src="https://files.erudi.fr/evilspins/sloughi-run-loop-big.webm" type="video/webm"> |  | ||||||
|         <source src="https://files.erudi.fr/evilspins/sloughi-run-loop-small.webm" type="video/webm" |  | ||||||
|           media="all and (max-width: 640px)"> |  | ||||||
|       </video> |  | ||||||
|     </section> |  | ||||||
|     <section class="flex justify-center"> |  | ||||||
|       <div class="flex max-w-2xl"> |  | ||||||
|         <compilationsList /> |  | ||||||
|       </div> |  | ||||||
|     </section> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
| <script setup lang="ts"> |  | ||||||
| // SEO |  | ||||||
| useSeoMeta({ |  | ||||||
|   title: 'evilSpins - compilations indépendantes', |  | ||||||
|   ogTitle: 'evilSpins - compilations indépendantes', |  | ||||||
|   description: 'evilSpins - compilations indépendantes, la bande originale d\'un film qui n\'existe pas', |  | ||||||
|   ogDescription: 'evilSpins - compilations indépendantes, la bande originale d\'un film qui n\'existe pas', |  | ||||||
|   ogImage: 'https://evilspins.com/logo.svg' |  | ||||||
| }) |  | ||||||
|  |  | ||||||
| const dataStore = useDataStore() |  | ||||||
|  |  | ||||||
| const scrollDown = function () { |  | ||||||
|   window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }) |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| body { |  | ||||||
|   margin: 0; |  | ||||||
|   overflow-x: hidden; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .logo, |  | ||||||
| .button, |  | ||||||
| .shadow, |  | ||||||
| .animation, |  | ||||||
| .mix { |  | ||||||
|   transition: .7s opacity; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .screen { |  | ||||||
|   position: absolute; |  | ||||||
|   height: 100vh; |  | ||||||
|   min-width: 100%; |  | ||||||
|   max-width: 100%; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .splash-screen { |  | ||||||
|   position: relative; |  | ||||||
|   height: 100vh; |  | ||||||
|   background-color: black; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .animation { |  | ||||||
|   z-index: 1; |  | ||||||
|   object-fit: cover; |  | ||||||
|   opacity: .8; |  | ||||||
|   /* opacity: 0; */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .mix { |  | ||||||
|   z-index: 4; |  | ||||||
|   position: fixed; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .shadow { |  | ||||||
|   z-index: 3; |  | ||||||
|   box-shadow: rgb(0, 0, 0) 0px 0px 170px 70px inset; |  | ||||||
|   opacity: .9; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .ui { |  | ||||||
|   z-index: 4; |  | ||||||
|   position: absolute; |  | ||||||
|   top: 50%; |  | ||||||
|   left: 50%; |  | ||||||
|   max-width: 80%; |  | ||||||
|   transform: translate(-50%, -50%); |  | ||||||
|   display: flex; |  | ||||||
|   flex-direction: column; |  | ||||||
|   align-items: center; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .logo { |  | ||||||
|   filter: drop-shadow(8px 8px 0 rgb(0 0 0 / 0.8)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .mixPlayer { |  | ||||||
|   background: black; |  | ||||||
|   max-height: 70vh; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .hide { |  | ||||||
|   opacity: 0; |  | ||||||
|   z-index: 0; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .show { |  | ||||||
|   opacity: 1; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| <template> |  | ||||||
|     <div class="h-screen w-full flex justify-center p-16"> |  | ||||||
|         <img src="/logo.svg"> |  | ||||||
|     </div> |  | ||||||
| </template> |  | ||||||
							
								
								
									
										10234
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								public/ES01A/bkg.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 149 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/ES01A/name.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.7 KiB | 
							
								
								
									
										50
									
								
								public/ES01A/number1.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 9.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/ES01A/object.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.4 MiB | 
							
								
								
									
										
											BIN
										
									
								
								public/ES01B/B.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.8 MiB | 
							
								
								
									
										
											BIN
										
									
								
								public/ES01B/bkg.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 149 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/ES01B/name.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										22
									
								
								public/ES01B/name.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 8.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/ES01B/object.png
									
									
									
									
									
										Executable file
									
								
							
							
						
						| After Width: | Height: | Size: 4.5 MiB | 
							
								
								
									
										
											BIN
										
									
								
								public/ESPLAYLISTS/bkg.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 19 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/ESPLAYLISTS/name.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 4.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								public/ESPLAYLISTS/object.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 84 KiB | 
							
								
								
									
										163
									
								
								public/logo.svg
									
									
									
									
									
								
							
							
						
						| Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB | 
| @@ -1,38 +1,50 @@ | |||||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools --> | ||||||
|  |  | ||||||
| <svg | <svg | ||||||
|  |    fill="#000000" | ||||||
|  |    height="800px" | ||||||
|  |    width="800px" | ||||||
|    version="1.1" |    version="1.1" | ||||||
|    id="svg1" |    id="Capa_1" | ||||||
|  |    viewBox="0 0 60 60" | ||||||
|  |    xml:space="preserve" | ||||||
|    sodipodi:docname="play.svg" |    sodipodi:docname="play.svg" | ||||||
|    width="25.177818" |    inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" | ||||||
|    height="31.875" |  | ||||||
|    inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)" |  | ||||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|    xmlns="http://www.w3.org/2000/svg" |    xmlns="http://www.w3.org/2000/svg" | ||||||
|    xmlns:svg="http://www.w3.org/2000/svg"> |    xmlns:svg="http://www.w3.org/2000/svg"><defs | ||||||
|   <defs |    id="defs2"> | ||||||
|      id="defs1" /> | 	 | ||||||
|   <sodipodi:namedview | 	 | ||||||
|      id="namedview1" | </defs><sodipodi:namedview | ||||||
|      pagecolor="#505050" |    id="namedview2" | ||||||
|      bordercolor="#eeeeee" |    pagecolor="#505050" | ||||||
|      borderopacity="1" |    bordercolor="#eeeeee" | ||||||
|      inkscape:showpageshadow="0" |    borderopacity="1" | ||||||
|      inkscape:pageopacity="0" |    inkscape:showpageshadow="0" | ||||||
|      inkscape:pagecheckerboard="0" |    inkscape:pageopacity="0" | ||||||
|      inkscape:deskcolor="#505050" |    inkscape:pagecheckerboard="0" | ||||||
|      inkscape:zoom="1.9448516" |    inkscape:deskcolor="#505050" | ||||||
|      inkscape:cx="202.07197" |    inkscape:zoom="0.94997202" | ||||||
|      inkscape:cy="136.00009" |    inkscape:cx="340.01001" | ||||||
|      inkscape:window-width="1920" |    inkscape:cy="397.38012" | ||||||
|      inkscape:window-height="1011" |    inkscape:window-width="1920" | ||||||
|      inkscape:window-x="0" |    inkscape:window-height="1132" | ||||||
|      inkscape:window-y="0" |    inkscape:window-x="0" | ||||||
|      inkscape:window-maximized="1" |    inkscape:window-y="0" | ||||||
|      inkscape:current-layer="svg1" /> |    inkscape:window-maximized="1" | ||||||
|   <path |    inkscape:current-layer="path4" /> | ||||||
|      style="font-size:64px;line-height:0.6;font-family:'Noto Sans Rejang';-inkscape-font-specification:'Noto Sans Rejang';letter-spacing:0.03px;word-spacing:0.16px;stroke-width:5.38174;stroke-miterlimit:2.3;stroke-dasharray:1.07635, 5.91989" |  | ||||||
|      d="M 0,31.875 V 0 l 25.177818,15.9375 z" | <g | ||||||
|      id="text1" |    id="g4" | ||||||
|      aria-label="▸" /> |    transform="translate(9.7969913,-22.06049)"><g | ||||||
| </svg> |      id="path4" | ||||||
|  |      inkscape:transform-center-x="-3.1076416" | ||||||
|  |      inkscape:transform-center-y="0.031482236" | ||||||
|  |      style="opacity:1" | ||||||
|  |      transform="matrix(0.16696126,-0.60372499,0.52316491,0.19267096,25.039308,35.922386)"><path | ||||||
|  |        id="path1" | ||||||
|  |        style="baseline-shift:baseline;display:inline;overflow:visible;vector-effect:none;fill:#ffffff;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:2.3;paint-order:fill markers stroke;enable-background:accumulate;stop-color:#000000;stop-opacity:1" | ||||||
|  |        d="m -9.5847112,-19.414681 a 2.4868138,2.4868138 0 0 0 -3.1047968,-1.516874 l -18.788944,6.087811 -18.791084,6.0858648 a 2.4868138,2.4868138 0 0 0 -0.900333,4.2129952 L -36.501957,8.6836742 -21.835903,21.91414 a 2.4868138,2.4868138 0 0 0 4.097569,-1.326305 l 4.124976,-19.3182854 4.1231169,-19.3163776 a 2.4868138,2.4868138 0 0 0 -0.09447,-1.367853 z m -0.7440438,70.809953 a 54.628808,47.339229 72.300195 0 1 -61.707096,-37.65028 54.628808,47.339229 72.300195 0 1 28.489522,-66.435356 54.628808,47.339229 72.300195 0 1 61.707096,37.650281 54.628808,47.339229 72.300195 0 1 -28.489522,66.435355 z" /></g></g></svg> | ||||||
|   | |||||||
| Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.2 KiB | 
							
								
								
									
										2
									
								
								public/robots.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,2 @@ | |||||||
|  | User-Agent: * | ||||||
|  | Disallow: | ||||||
| @@ -1,81 +0,0 @@ | |||||||
| export default eventHandler(() => { |  | ||||||
|   return [ |  | ||||||
|     { |  | ||||||
|       id: 0, |  | ||||||
|       name: "L'efondras", |  | ||||||
|       url: "https://leffondras.bandcamp.com/music", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "0024705317" |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 1, |  | ||||||
|       name: "The kundalini genie", |  | ||||||
|       url: "https://the-kundalini-genie.bandcamp.com", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "0012045550" |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 2, |  | ||||||
|       name: "Fontaines D.C.", |  | ||||||
|       url: "https://fontainesdc.bandcamp.com", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "0027327090" |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 3, |  | ||||||
|       name: "Fontanarosa", |  | ||||||
|       url: "https://fontanarosa.bandcamp.com", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "0035380235", |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 4, |  | ||||||
|       name: "Johnny mafia", |  | ||||||
|       url: "https://johnnymafia.bandcamp.com", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "0035009392", |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 5, |  | ||||||
|       name: "New candys", |  | ||||||
|       url: "https://newcandys.bandcamp.com", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "0033518637", |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 6, |  | ||||||
|       name: "Magic shoppe", |  | ||||||
|       url: "https://magicshoppe.bandcamp.com", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "0030748374" |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 7, |  | ||||||
|       name: "Les jaguars", |  | ||||||
|       url: "https://radiomartiko.bandcamp.com/album/surf-qu-b-cois", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "0016551336", |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 8, |  | ||||||
|       name: "TRAAMS", |  | ||||||
|       url: "https://traams.bandcamp.com", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "0028348410", |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 9, |  | ||||||
|       name: "Blue orchid", |  | ||||||
|       url: "https://blue-orchid.bandcamp.com", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "0034796193", |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 10, |  | ||||||
|       name: "I love UFO", |  | ||||||
|       url: "https://bruitblanc.bandcamp.com", |  | ||||||
|       style: [0, 1, 2], |  | ||||||
|       cover: "a2203158939", |  | ||||||
|     } |  | ||||||
|   ] |  | ||||||
| }) |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| export default eventHandler(() => { |  | ||||||
|   return [ |  | ||||||
|     { |  | ||||||
|       id: 'ES00A', |  | ||||||
|       name: 'zero', |  | ||||||
|       duration: 2794, |  | ||||||
|       description: '...', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 'ES00B', |  | ||||||
|       name: 'zero b-sides', |  | ||||||
|       duration: 2470, |  | ||||||
|       description: '...', |  | ||||||
|     } |  | ||||||
|   ] |  | ||||||
| }) |  | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| import fs from 'fs' |  | ||||||
| import path from 'path' |  | ||||||
|  |  | ||||||
| export default eventHandler(async (event) => { |  | ||||||
|   const directoryPath = path.join(process.cwd(), 'media/files/music') // replace 'your-folder' with the folder you want to list |  | ||||||
|  |  | ||||||
|   try { |  | ||||||
|     // Read the directory contents |  | ||||||
|     const files = await fs.promises.readdir(directoryPath) |  | ||||||
|  |  | ||||||
|     return { |  | ||||||
|       success: true, |  | ||||||
|       files: files.filter(file => !file.startsWith('.')) // optional: exclude unwanted files |  | ||||||
|     } |  | ||||||
|   } catch (error) { |  | ||||||
|     return { |  | ||||||
|       success: false, |  | ||||||
|       error: error.message |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| }) |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| export default eventHandler(() => { |  | ||||||
|   return [ |  | ||||||
|     { |  | ||||||
|       "id": 0, |  | ||||||
|       "name": "post-rock" |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       "id": 1, |  | ||||||
|       "name": "math-rock" |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       "id": 2, |  | ||||||
|       "name": "indie-pop" |  | ||||||
|     } |  | ||||||
|   ] |  | ||||||
| }) |  | ||||||
| @@ -1,224 +0,0 @@ | |||||||
| export default eventHandler(() => { |  | ||||||
|   return [ |  | ||||||
|     { |  | ||||||
|       id: 1, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'The grinding wheel', |  | ||||||
|       artist: 0, |  | ||||||
|       start: 0, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://arakirecords.bandcamp.com/track/the-grinding-wheel', |  | ||||||
|       cover: 'a3236746052', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 2, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'Bleach', |  | ||||||
|       artist: 1, |  | ||||||
|       start: 393, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://the-kundalini-genie.bandcamp.com/track/bleach-2', |  | ||||||
|       cover: 'a1714786533', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 3, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'Televised mind', |  | ||||||
|       artist: 2, |  | ||||||
|       start: 892, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://fontainesdc.bandcamp.com/track/televised-mind', |  | ||||||
|       cover: 'a3772806156' |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 4, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'In it', |  | ||||||
|       artist: 3, |  | ||||||
|       start: 1138, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://howlinbananarecords.bandcamp.com/track/in-it', |  | ||||||
|       cover: 'a1720372066', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 5, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'Bad michel', |  | ||||||
|       artist: 4, |  | ||||||
|       start: 1245, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://johnnymafia.bandcamp.com/track/bad-michel-3', |  | ||||||
|       cover: 'a0984622869', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 6, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'Overall', |  | ||||||
|       artist: 5, |  | ||||||
|       start: 1394, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://newcandys.bandcamp.com/track/overall', |  | ||||||
|       cover: 'a0559661270', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 7, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'Blowup', |  | ||||||
|       artist: 6, |  | ||||||
|       start: 1674, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://magicshoppe.bandcamp.com/track/blowup', |  | ||||||
|       cover: 'a1444895293', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 8, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'Guitar jet', |  | ||||||
|       artist: 7, |  | ||||||
|       start: 1880, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://radiomartiko.bandcamp.com/track/guitare-jet', |  | ||||||
|       cover: 'a1494681687', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 9, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'Intercontinental radio waves', |  | ||||||
|       artist: 8, |  | ||||||
|       start: 2024, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://traams.bandcamp.com/track/intercontinental-radio-waves', |  | ||||||
|       cover: 'a0046738552', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 10, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'Here comes the sun', |  | ||||||
|       artist: 9, |  | ||||||
|       start: 2211, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://blue-orchid.bandcamp.com/track/here-come-the-sun', |  | ||||||
|       cover: 'a4102567047', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 11, |  | ||||||
|       compilation: 'ES00A', |  | ||||||
|       title: 'Like in the movies', |  | ||||||
|       artist: 10, |  | ||||||
|       start: 2559, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://bruitblanc.bandcamp.com/track/like-in-the-movies-2', |  | ||||||
|       cover: 'a2203158939', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 21, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'Ce que révèle l\'éclipse', |  | ||||||
|       artist: 0, |  | ||||||
|       start: 0, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://arakirecords.bandcamp.com/track/ce-que-r-v-le-l-clipse', |  | ||||||
|       cover: 'a3236746052', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 22, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'Bleedin\' Gums Mushrool', |  | ||||||
|       artist: 1, |  | ||||||
|       start: 263, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://the-kundalini-genie.bandcamp.com/track/bleedin-gums-mushroom', |  | ||||||
|       cover: 'a1714786533', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 23, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'A lucid dream', |  | ||||||
|       artist: 2, |  | ||||||
|       start: 554, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://fontainesdc.bandcamp.com/track/a-lucid-dream', |  | ||||||
|       cover: 'a3772806156', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 24, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'Lights off', |  | ||||||
|       artist: 3, |  | ||||||
|       start: 781, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://howlinbananarecords.bandcamp.com/track/lights-off', |  | ||||||
|       cover: 'a1720372066', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 25, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'I\'m sentimental', |  | ||||||
|       artist: 4, |  | ||||||
|       start: 969, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://johnnymafia.bandcamp.com/track/im-sentimental-2', |  | ||||||
|       cover: 'a2333676849', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 26, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'Thrill or trip', |  | ||||||
|       artist: 5, |  | ||||||
|       start: 1128, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://newcandys.bandcamp.com/track/thrill-or-trip', |  | ||||||
|       cover: 'a0559661270', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 27, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'Redhead', |  | ||||||
|       artist: 6, |  | ||||||
|       start: 1303, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://magicshoppe.bandcamp.com/track/redhead', |  | ||||||
|       cover: 'a0594426943', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 28, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'Supersonic twist', |  | ||||||
|       artist: 7, |  | ||||||
|       start: 1584, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://open.spotify.com/track/66voQIZAJ3zD3Eju2qtNjF', |  | ||||||
|       cover: 'a1494681687', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 29, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'Flowers', |  | ||||||
|       artist: 8, |  | ||||||
|       start: 1749, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://traams.bandcamp.com/track/flowers', |  | ||||||
|       cover: 'a3644668199', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 30, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'The shade', |  | ||||||
|       artist: 9, |  | ||||||
|       start: 1924, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://blue-orchid.bandcamp.com/track/the-shade', |  | ||||||
|       cover: 'a0804204790', |  | ||||||
|     }, |  | ||||||
|     { |  | ||||||
|       id: 31, |  | ||||||
|       compilation: 'ES00B', |  | ||||||
|       title: 'Like in the movies', |  | ||||||
|       artist: 10, |  | ||||||
|       start: 2185, |  | ||||||
|       bpm: 0, |  | ||||||
|       url: 'https://bruitblanc.bandcamp.com/track/like-in-the-movies', |  | ||||||
|       cover: 'a3647322740', |  | ||||||
|     }, |  | ||||||
|   ] |  | ||||||
| }) |  | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| { |  | ||||||
|   "extends": "../.nuxt/tsconfig.server.json" |  | ||||||
| } |  | ||||||
| @@ -1,51 +0,0 @@ | |||||||
| import type { Compilation, Artist, Track } from '~/types/types' |  | ||||||
|  |  | ||||||
| // stores/data.ts |  | ||||||
| import { defineStore } from 'pinia' |  | ||||||
|  |  | ||||||
| export const useDataStore = defineStore('data', { |  | ||||||
|   state: () => ({ |  | ||||||
|     compilations: [] as Compilation[],  // Store your compilation data here |  | ||||||
|     artists: [] as Artist[],       // Store artist data here |  | ||||||
|     tracks: [] as Track[],        // Store track data here |  | ||||||
|     isLoaded: false,                   // To track if data is already loaded |  | ||||||
|   }), |  | ||||||
|  |  | ||||||
|   actions: { |  | ||||||
|     async loadData() { |  | ||||||
|       if (this.isLoaded) return  // Avoid re-fetching if already loaded |  | ||||||
|  |  | ||||||
|       // Fetch your data once (e.g., from an API or local JSON) |  | ||||||
|       const { data: compilations } = await useFetch('/api/compilations') |  | ||||||
|       const { data: artists } = await useFetch('/api/artists') |  | ||||||
|       const { data: tracks } = await useFetch('/api/tracks') |  | ||||||
|  |  | ||||||
|       // Set the data in the store |  | ||||||
|       this.compilations = compilations.value |  | ||||||
|       this.artists = artists.value |  | ||||||
|       this.tracks = tracks.value |  | ||||||
|       this.isLoaded = true |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   getters: { |  | ||||||
|     // Obtenir tous les compilations |  | ||||||
|     getAllCompilations: (state) => state.compilations, |  | ||||||
|     getCompilationById: (state) => { |  | ||||||
|       return (id: string) => { |  | ||||||
|         return state.compilations.find(compilation => compilation.id === id) |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     // Obtenir toutes les pistes d'une compilation donnée |  | ||||||
|     getTracksByCompilationId: (state) => (compilationId: string) => { |  | ||||||
|       return state.tracks.filter(track => track.compilation === compilationId) |  | ||||||
|     }, |  | ||||||
|     // Filtrer les artistes selon certains critères |  | ||||||
|     getArtistById: (state) => (id: number) => state.artists.find(artist => artist.id === id), |  | ||||||
|  |  | ||||||
|     // Obtenir toutes les pistes d'un artiste donné |  | ||||||
|     getTracksByArtistId: (state) => (artistId: string) => { |  | ||||||
|       return state.tracks.filter(track => track.artistId === artistId) |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
| }) |  | ||||||
| @@ -11,12 +11,12 @@ module.exports = { | |||||||
|   theme: { |   theme: { | ||||||
|     extend: { |     extend: { | ||||||
|       colors: { |       colors: { | ||||||
|         esyellow: '#fdec50ff', |         esyellow: "#fdec50ff", | ||||||
|       }, |       }, | ||||||
|       screens: { |       screens: { | ||||||
|         '2sm': '320px', |         "2sm": "320px", | ||||||
|       }, |       }, | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   plugins: [], |   plugins: [], | ||||||
| } | }; | ||||||
|   | |||||||
| @@ -1,4 +1,18 @@ | |||||||
| { | { | ||||||
|   // https://nuxt.com/docs/guide/concepts/typescript |   // https://nuxt.com/docs/guide/concepts/typescript | ||||||
|   "extends": "./.nuxt/tsconfig.json" |   "files": [], | ||||||
|  |   "references": [ | ||||||
|  |     { | ||||||
|  |       "path": "./.nuxt/tsconfig.app.json" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "./.nuxt/tsconfig.server.json" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "./.nuxt/tsconfig.shared.json" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "./.nuxt/tsconfig.node.json" | ||||||
|  |     } | ||||||
|  |   ] | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,27 +0,0 @@ | |||||||
| // types.ts |  | ||||||
| export interface Compilation { |  | ||||||
|   id: string |  | ||||||
|   name: string |  | ||||||
|   duration: number |  | ||||||
|   tracks?: Track[] |  | ||||||
|   description: string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export interface Artist { |  | ||||||
|   id: number |  | ||||||
|   name: string |  | ||||||
|   url: string |  | ||||||
|   style: Array<number> |  | ||||||
|   cover: string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export interface Track { |  | ||||||
|   id: string |  | ||||||
|   compilationId: string |  | ||||||
|   title: string |  | ||||||
|   artistId: number |  | ||||||
|   artist?: Artist |  | ||||||
|   start: number |  | ||||||
|   link: string |  | ||||||
|   cover: string |  | ||||||
| } |  | ||||||