This commit is contained in:
		
							
								
								
									
										14
									
								
								.github/workflows/deploy.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/deploy.yml
									
									
									
									
										vendored
									
									
								
							| @@ -4,19 +4,19 @@ on: [push] | ||||
| jobs: | ||||
|   deploy: | ||||
|     runs-on: ubuntu-22.04 | ||||
|     needs: test | ||||
|     container: | ||||
|       volumes: | ||||
|         - /var/docker-web:/var/docker-web | ||||
|     steps: | ||||
|       - uses: actions/checkout@v4 | ||||
|  | ||||
|       - name: Deploy with docker-web | ||||
|         run: | | ||||
|           APP_DIR=/var/docker-web/apps/${GITHUB_REPOSITORY##*/} | ||||
|           mkdir -p $APP_DIR | ||||
|           REPO_NAME="${GITHUB_REPOSITORY##*/}" | ||||
|           APP_DIR="/var/docker-web/apps/${REPO_NAME}" | ||||
|           bash /var/docker-web/src/cli.sh down "${REPO_NAME}" | ||||
|           rm -rf "$APP_DIR" | ||||
|           mkdir "$APP_DIR" | ||||
|           cp -a $(find . -mindepth 1 -maxdepth 1 ! -name '.git' ! -name 'node_modules') "$APP_DIR/" | ||||
|           export COMPOSE_BAKE=false | ||||
|           bash /var/docker-web/src/cli.sh down ${GITHUB_REPOSITORY##*/} | ||||
|           docker rmi local/${GITHUB_REPOSITORY##*/} | ||||
|           bash /var/docker-web/src/cli.sh up ${GITHUB_REPOSITORY##*/} | ||||
|           docker rmi "local/${REPO_NAME}" | ||||
|           bash /var/docker-web/src/cli.sh up "${REPO_NAME}" | ||||
|   | ||||
| @@ -10,44 +10,33 @@ | ||||
|       <div class="face left" ref="leftFace" /> | ||||
|       <div class="face top" ref="topFace"> | ||||
|         <img class="logo h-full p-1" src="/logo.svg" alt=""> | ||||
|         <img class="absolute left-0 w-16 pr-4" :src="`/${compilation.id}/title.svg`" alt=""> | ||||
|         <img class="absolute block h-1/2" style="left:5%;" :src="`/${compilation.id}/title.svg`" alt=""> | ||||
|       </div> | ||||
|       <div class="face bottom" ref="bottomFace" /> | ||||
|     </div> | ||||
|   </div> | ||||
| 
 | ||||
|   <div class="devtool  absolute right-4 text-white bg-black rounded-2xl px-4 py-2"> | ||||
|     <button @click="poser">poser</button> | ||||
|     <button @click="face">face</button> | ||||
|     <button @click="dos">dos</button> | ||||
|     <div> | ||||
|       <label class="block"> | ||||
|         X: {{ angleX }} | ||||
|         <input v-model.number="angleX" type="range" step="1" min="-180" max="180" @input="applyTransform"> | ||||
|       </label> | ||||
|       <label class="block"> | ||||
|         Y: {{ angleY }} | ||||
|         <input v-model.number="angleY" type="range" step="1" min="-180" max="180" @input="applyTransform"> | ||||
|       </label> | ||||
|       <label class="block"> | ||||
|         Z: {{ angleZ }} | ||||
|         <input v-model.number="angleZ" type="range" step="1" min="-180" max="180" @input="applyTransform"> | ||||
|       </label> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import compilations from '~~/server/api/compilations'; | ||||
| import type { Compilation } from '~~/types/types'; | ||||
| import type { Compilation, BoxPosition } from '~~/types/types'; | ||||
| 
 | ||||
| const props = defineProps<{ compilation: Compilation }>() | ||||
| const props = withDefaults( | ||||
|   defineProps<{ | ||||
|     compilation: Compilation | ||||
|     position?: BoxPosition | ||||
|     size?: number | ||||
|   }>(), | ||||
|   { | ||||
|     position: () => ({ x: 0, y: 0, z: 0 }), | ||||
|     size: 6, | ||||
|   } | ||||
| ) | ||||
| 
 | ||||
| // States | ||||
| const position = ref('') | ||||
| const angleX = ref(76) | ||||
| const angleY = ref(0) | ||||
| const angleZ = ref(150) | ||||
| 
 | ||||
| const angleX = ref(props.position.x) | ||||
| const angleY = ref(props.position.y) | ||||
| const angleZ = ref(props.position.z) | ||||
| 
 | ||||
| const frontFace = ref() | ||||
| const backFace = ref() | ||||
| @@ -56,18 +45,6 @@ const leftFace = ref() | ||||
| const topFace = ref() | ||||
| const bottomFace = ref() | ||||
| 
 | ||||
| function poser() { | ||||
|   rotateBox(76, 0, 150) | ||||
| } | ||||
| 
 | ||||
| function face() { | ||||
|   rotateBox(-20, 20, 0) | ||||
| } | ||||
| 
 | ||||
| function dos() { | ||||
|   rotateBox(-20, 200, 0) | ||||
| } | ||||
| 
 | ||||
| const box = ref() | ||||
| const scene = ref() | ||||
| 
 | ||||
| @@ -98,23 +75,33 @@ function applyTransform() { | ||||
|   box.value.style.transform = `rotateX(${angleX.value}deg) rotateY(${angleY.value}deg) rotateZ(${angleZ.value}deg)` | ||||
| } | ||||
| 
 | ||||
| function applySize() { | ||||
|   updateCssVar('--height', `${props.size * (100 / 3)}px`, scene.value) | ||||
|   updateCssVar('--width', `${props.size * 50}px`, scene.value) | ||||
|   updateCssVar('--depth', `${props.size * 10}px`, scene.value) | ||||
| } | ||||
| function applyColor() { | ||||
|   frontFace.value.style.setProperty('background', `${props.compilation.color2}`) | ||||
|   backFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.color1}, ${props.compilation.color2})`) | ||||
|   rightFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.color1}, ${props.compilation.color2})`) | ||||
|   leftFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.color1}, ${props.compilation.color2})`) | ||||
|   topFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.color2}, ${props.compilation.color2})`) | ||||
|   bottomFace.value.style.setProperty('background', `${props.compilation.color1}`) | ||||
| } | ||||
| 
 | ||||
| /* | ||||
|   Fonction utilitaire : place la box directement à une rotation donnée | ||||
|   (utilisée par le bouton reset ou autre logique externe) | ||||
| */ | ||||
| function rotateBox(x, y, z) { | ||||
|   angleX.value = x | ||||
|   angleY.value = y | ||||
|   angleZ.value = z | ||||
| function applyRotation() { | ||||
|   angleX.value = props.position.x | ||||
|   angleY.value = props.position.y | ||||
|   angleZ.value = props.position.z | ||||
|   applyTransform() | ||||
| 
 | ||||
|   box.value.style.setProperty('transition', 'transform 800ms ease-in-out') | ||||
|   setTimeout(() => { | ||||
|     box.value.style.setProperty('transition', 'transform 120ms linear') | ||||
|     console.log('dopne timeout') | ||||
|   }, 120) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /* | ||||
| @@ -151,19 +138,8 @@ function tickInertia() { | ||||
|   Mise en place des listeners une fois le composant monté | ||||
| */ | ||||
| onMounted(() => { | ||||
|   // setup CSS vars pour la scène | ||||
|   updateCssVar('--height', '200px', scene.value) | ||||
|   updateCssVar('--width', '300px', scene.value) | ||||
|   updateCssVar('--depth', '60px', scene.value) | ||||
| 
 | ||||
|   frontFace.value.style.setProperty('background', `${props.compilation.colorTo}`) | ||||
|   backFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.colorFrom}, ${props.compilation.colorTo})`) | ||||
|   rightFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.colorFrom}, ${props.compilation.colorTo})`) | ||||
|   leftFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.colorFrom}, ${props.compilation.colorTo})`) | ||||
|   topFace.value.style.setProperty('background', `linear-gradient(to top, ${props.compilation.colorTo}, ${props.compilation.colorTo})`) | ||||
|   bottomFace.value.style.setProperty('background', `${props.compilation.colorFrom}`) | ||||
| 
 | ||||
| 
 | ||||
|   applySize() | ||||
|   applyColor() | ||||
|   applyTransform() | ||||
| 
 | ||||
|   // pointerdown = début du drag | ||||
| @@ -221,6 +197,18 @@ onMounted(() => { | ||||
|     cancelAnimationFrame(raf) | ||||
|   }) | ||||
| }) | ||||
| 
 | ||||
| watch(() => props.position, () => { | ||||
|   applyRotation() | ||||
| }, { deep: true }) | ||||
| 
 | ||||
| watch(() => props.compilation, () => { | ||||
|   applyColor() | ||||
| }, { deep: true }) | ||||
| 
 | ||||
| watch(() => props.size, () => { | ||||
|   applySize() | ||||
| }) | ||||
| </script> | ||||
| 
 | ||||
| 
 | ||||
| @@ -254,6 +242,7 @@ body { | ||||
|   position: relative; | ||||
|   transform-style: preserve-3d; | ||||
|   transition: transform 120ms linear; | ||||
|   transition: height 120ms linear; | ||||
|   /* légère smoothing quand on lâche */ | ||||
|   margin: auto; | ||||
|   user-select: none; | ||||
| @@ -1,263 +0,0 @@ | ||||
| <template> | ||||
|  | ||||
|   <div class="scene" id="scene"> | ||||
|     <div class="box" id="box"> | ||||
|       <div class="face front"> | ||||
|         <img class="cover" src="https://evilspins.com/ES01A/object.png" alt=""> | ||||
|       </div> | ||||
|       <div class="face back"></div> | ||||
|       <div class="face right"></div> | ||||
|       <div class="face left"></div> | ||||
|       <div class="face top"></div> | ||||
|       <div class="face bottom"></div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup> | ||||
| /* | ||||
|   Rotation 3D au touch / clic maintenu | ||||
|   - Utilise Pointer Events (fonctionne pour souris, stylet, touch) | ||||
|   - rotateX et rotateY mis à jour pendant le drag | ||||
|   - inertie légère à la release (configurable) | ||||
| */ | ||||
|  | ||||
| (function () { | ||||
|   const box = document.getElementById('box'); | ||||
|   const scene = document.getElementById('scene'); | ||||
|  | ||||
|   // état | ||||
|   let angleX = -20; // angle initial (pour montrer la 3D) | ||||
|   let angleY = 20; | ||||
|   let dragging = false; | ||||
|   let lastPointer = { x: 0, y: 0, time: 0 }; | ||||
|   let velocity = { x: 0, y: 0 }; | ||||
|   let raf = null; | ||||
|  | ||||
|   // paramètres | ||||
|   const sensitivity = 0.3;    // combien de degrés par px | ||||
|   const friction = 0.95;      // inertie (0..1) ; 1 = pas de friction | ||||
|   const minVelocity = 0.02;   // seuil pour arrêter l'inertie | ||||
|   const enableInertia = true; // tu peux mettre false pour pas d'inertie | ||||
|  | ||||
|   // applique la transformation (raf-friendly) | ||||
|   function applyTransform() { | ||||
|     box.style.transform = `rotateX(${angleX}deg) rotateY(${angleY}deg)`; | ||||
|   } | ||||
|  | ||||
|   applyTransform(); | ||||
|  | ||||
|   // boucle d'inertie | ||||
|   function tickInertia() { | ||||
|     if (!enableInertia) return; | ||||
|     // appliquer friction | ||||
|     velocity.x *= friction; | ||||
|     velocity.y *= friction; | ||||
|  | ||||
|     angleX += velocity.y; | ||||
|     angleY += velocity.x; | ||||
|  | ||||
|     // clamp angleX pour éviter flip complet (optionnel) | ||||
|     angleX = Math.max(-80, Math.min(80, angleX)); | ||||
|  | ||||
|     applyTransform(); | ||||
|  | ||||
|     if (Math.abs(velocity.x) > minVelocity || Math.abs(velocity.y) > minVelocity) { | ||||
|       raf = requestAnimationFrame(tickInertia); | ||||
|     } else { | ||||
|       raf = null; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // pointerdown | ||||
|   scene.addEventListener('pointerdown', (ev) => { | ||||
|     ev.preventDefault(); | ||||
|     dragging = true; | ||||
|     scene.setPointerCapture(ev.pointerId); | ||||
|     lastPointer.x = ev.clientX; | ||||
|     lastPointer.y = ev.clientY; | ||||
|     lastPointer.time = performance.now(); | ||||
|     velocity.x = 0; | ||||
|     velocity.y = 0; | ||||
|     if (raf) { cancelAnimationFrame(raf); raf = null; } // stop inertie en commençant un nouveau drag | ||||
|   }); | ||||
|  | ||||
|   // pointermove | ||||
|   scene.addEventListener('pointermove', (ev) => { | ||||
|     if (!dragging) return; | ||||
|     ev.preventDefault(); | ||||
|     const now = performance.now(); | ||||
|     const dx = ev.clientX - lastPointer.x; | ||||
|     const dy = ev.clientY - lastPointer.y; | ||||
|  | ||||
|     // mise à jour angles (inverser si tu veux sens différent) | ||||
|     angleY += dx * sensitivity; | ||||
|     angleX -= dy * sensitivity; | ||||
|  | ||||
|     // clamp angleX | ||||
|     angleX = Math.max(-80, Math.min(80, angleX)); | ||||
|  | ||||
|     // calculer vitesse (px per frame approximative) | ||||
|     const dt = Math.max(1, now - lastPointer.time); // ms | ||||
|     velocity.x = (dx / dt) * 16 * sensitivity; // normalisé approximativement à 60fps | ||||
|     velocity.y = (-dy / dt) * 16 * sensitivity; | ||||
|  | ||||
|     lastPointer.x = ev.clientX; | ||||
|     lastPointer.y = ev.clientY; | ||||
|     lastPointer.time = now; | ||||
|  | ||||
|     applyTransform(); | ||||
|   }); | ||||
|  | ||||
|   // pointerup / cancel | ||||
|   const endDrag = (ev) => { | ||||
|     if (!dragging) return; | ||||
|     dragging = false; | ||||
|     try { scene.releasePointerCapture(ev.pointerId); } catch (e) { } | ||||
|     // si inertie activée, lancer la boucle | ||||
|     if (enableInertia && (Math.abs(velocity.x) > minVelocity || Math.abs(velocity.y) > minVelocity)) { | ||||
|       if (!raf) raf = requestAnimationFrame(tickInertia); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|   scene.addEventListener('pointerup', endDrag); | ||||
|   scene.addEventListener('pointercancel', endDrag); | ||||
|   scene.addEventListener('pointerleave', endDrag); // utile sur desktop si tu sors du container | ||||
|  | ||||
|   // accessibility : permettre rotation via clavier (optionnel) | ||||
|   scene.tabIndex = 0; | ||||
|   scene.addEventListener('keydown', (e) => { | ||||
|     const step = 8; | ||||
|     if (e.key === 'ArrowLeft') { angleY -= step; applyTransform(); } | ||||
|     if (e.key === 'ArrowRight') { angleY += step; applyTransform(); } | ||||
|     if (e.key === 'ArrowUp') { angleX -= step; applyTransform(); } | ||||
|     if (e.key === 'ArrowDown') { angleX += step; applyTransform(); } | ||||
|   }); | ||||
|  | ||||
| })(); | ||||
| </script> | ||||
|  | ||||
| <style> | ||||
| /*  H      W   D | ||||
|     k7  5   :  8 : 1 | ||||
|     CD  12  : 14 : 1 | ||||
|     VHS 4.5 :  8 : 1 | ||||
|     DVD 14  : 10 : 1 | ||||
|     */ | ||||
|  | ||||
| :root { | ||||
|   --size: 100px; | ||||
|   --height: 150px; | ||||
|   --width: 150px; | ||||
|   --depth: 10px; | ||||
|   --bg: #0f172a; | ||||
| } | ||||
|  | ||||
| html, | ||||
| body { | ||||
|   height: 100%; | ||||
|   margin: 0; | ||||
|   background: var(--bg); | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|   font-family: system-ui, Segoe UI, Roboto, Helvetica, Arial; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
| } | ||||
|  | ||||
| /* scène avec perspective */ | ||||
| .scene { | ||||
|   width: calc(var(--height) * 1.2); | ||||
|   height: calc(var(--width) * 1.2); | ||||
|   perspective: 1000px; | ||||
|   touch-action: none; | ||||
|   /* essentiel pour empêcher le scroll pendant le drag */ | ||||
| } | ||||
|  | ||||
| /* l'objet 3D (box simple) */ | ||||
| .box { | ||||
|   width: var(--width); | ||||
|   height: var(--height); | ||||
|   position: relative; | ||||
|   transform-style: preserve-3d; | ||||
|   transition: transform 120ms linear; | ||||
|   /* légère smoothing quand on lâche */ | ||||
|   margin: auto; | ||||
|   user-select: none; | ||||
|   cursor: grab; | ||||
| } | ||||
|  | ||||
| .box:active { | ||||
|   cursor: grabbing; | ||||
| } | ||||
|  | ||||
| /* faces du box */ | ||||
| .face { | ||||
|   position: absolute; | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|   justify-content: center; | ||||
|   font-size: 20px; | ||||
|   color: white; | ||||
|   font-weight: 600; | ||||
|   backface-visibility: hidden; | ||||
|   border: 2px solid rgba(255, 255, 255, 0.06); | ||||
|   box-sizing: border-box; | ||||
|   transform-origin: top right; | ||||
| } | ||||
|  | ||||
| .front, | ||||
| .back { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
| } | ||||
|  | ||||
| .face.top, | ||||
| .face.bottom { | ||||
|   width: var(--width); | ||||
|   height: var(--depth); | ||||
| } | ||||
|  | ||||
| .face.left, | ||||
| .face.right { | ||||
|   width: var(--depth); | ||||
|   height: var(--height); | ||||
| } | ||||
|  | ||||
| .face.front { | ||||
|   background: linear-gradient(180deg, #2563eb, #7dd3fc); | ||||
|   transform: translateX(0px) translateY(0px) translateZ(0px); | ||||
| } | ||||
|  | ||||
| .face.back { | ||||
|   background: linear-gradient(180deg, #7c3aed, #a78bfa); | ||||
|   transform: rotateY(180deg) translateX(var(--width)) translateY(0px) translateZ(var(--depth)); | ||||
| } | ||||
|  | ||||
| .face.right { | ||||
|   background: linear-gradient(180deg, #10b981, #6ee7b7); | ||||
|   transform: rotateY(90deg) translateX(0px) translateY(0px) translateZ(var(--width)); | ||||
|   transform-origin: top left; | ||||
| } | ||||
|  | ||||
| .face.left { | ||||
|   background: linear-gradient(180deg, #ef4444, #fca5a5); | ||||
|   transform: rotateY(-90deg) translateX(0) translateY(0px) translateZ(var(--depth)); | ||||
| } | ||||
|  | ||||
| .face.top { | ||||
|   background: linear-gradient(180deg, #f59e0b, #fcd34d); | ||||
|   transform: rotateX(90deg) translateX(0px) translateY(calc(var(--depth) * -1)) translateZ(0px); | ||||
| } | ||||
|  | ||||
| .face.bottom { | ||||
|   background: linear-gradient(180deg, #06b6d4, #67e8f9); | ||||
|   transform: rotateX(-90deg) translateX(0) translateY(0px) translateZ(calc(var(--height))); | ||||
| } | ||||
|  | ||||
| .cover { | ||||
|   height: 100%; | ||||
|   width: 100%; | ||||
|   object-fit: cover; | ||||
| } | ||||
| </style> | ||||
| @@ -4,7 +4,7 @@ | ||||
|       <div class="flex flex-col-reverse bg-gradient-to-r from-primary to-primary-dark"> | ||||
|         <div class="mt-8 flex flex-wrap justify-center" | ||||
|           v-for="compilation in store.getAllCompilations.slice().reverse()"> | ||||
|           <compilationBox :compilation="compilation" template="full" /> | ||||
|           <box :compilation="compilation" template="full" /> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   | ||||
| @@ -1,100 +0,0 @@ | ||||
| <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"> | ||||
|         <h1 class="text-white pt-6 text-lg md:text-xl lg:text-2xl text-center font-bold tracking-widest text-shadow"> | ||||
|           Compilations | ||||
|           indépendantes ... | ||||
|         </h1> | ||||
|       </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> | ||||
							
								
								
									
										65
									
								
								app/pages/studio.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								app/pages/studio.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| <template> | ||||
|   <div class="flex flex-wrap justify-center"> | ||||
|     <div class="bg-page-dark-bg text-white"> | ||||
|       <div class="flex flex-col-reverse bg-gradient-to-r from-primary to-primary-dark"> | ||||
|         <div class="mt-8 flex flex-wrap justify-center"> | ||||
|           <box :compilation="compilation" :position="currentPosition" :size="size" /> | ||||
|           <div class="devtool  absolute right-4 text-white bg-black rounded-2xl px-4 py-2"> | ||||
|             <button @click="currentPosition = poser">poser</button> | ||||
|             <button @click="currentPosition = face">face</button> | ||||
|             <button @click="currentPosition = dos">dos</button> | ||||
|             <div class="w-full block"> | ||||
|               <input class="w-1/2" type="color" name="color1" id="color1" v-model="compilation.color1"> | ||||
|               <input class="w-1/2" type="color" name="color1" id="color1" v-model="compilation.color2"> | ||||
|               <div class="block w-full h-32" :style="{ | ||||
|                 background: `linear-gradient(to top, ${compilation.color1}, ${compilation.color2})` | ||||
|               }"> | ||||
|               </div> | ||||
|               <label class="block"> | ||||
|                 size: {{ size }} | ||||
|                 <input v-model.number="size" type="range" step="1" min="1" max="14"> | ||||
|               </label> | ||||
|             </div> | ||||
|             <div> | ||||
|               <label class="block"> | ||||
|                 X: {{ currentPosition.x }} | ||||
|                 <input v-model.number="currentPosition.x" type="range" step="1" min="-180" max="180"> | ||||
|               </label> | ||||
|               <label class="block"> | ||||
|                 Y: {{ currentPosition.y }} | ||||
|                 <input v-model.number="currentPosition.y" type="range" step="1" min="-180" max="180"> | ||||
|               </label> | ||||
|               <label class="block"> | ||||
|                 Z: {{ currentPosition.z }} | ||||
|                 <input v-model.number="currentPosition.z" type="range" step="1" min="-180" max="180"> | ||||
|               </label> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script setup lang="ts"> | ||||
| import type { BoxPosition } from '~~/types/types' | ||||
|  | ||||
| const compilation = ref({ | ||||
|   id: 'ES00A', | ||||
|   name: 'zero', | ||||
|   duration: 2794, | ||||
|   description: 'Zero is for manifesto', | ||||
|   color1: '#ffffff', | ||||
|   color2: '#48959d', | ||||
| }) | ||||
|  | ||||
| const poser = { x: 76, y: 0, z: 150 } | ||||
| const face = { x: -20, y: 20, z: 0 } | ||||
| const dos = { x: -20, y: 200, z: 0 } | ||||
|  | ||||
| const size = ref(6) | ||||
|  | ||||
| const currentPosition: Ref<BoxPosition> = ref(poser) | ||||
|  | ||||
| //from-slate-800 to-zinc-900  | ||||
| </script> | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.2 KiB | 
| @@ -6,33 +6,37 @@ export default eventHandler(() => { | ||||
|       id: 'ES00A', | ||||
|       name: 'zero', | ||||
|       duration: 2794, | ||||
|       description: 'Zero is for manifesto ... ;)', | ||||
|       colorFrom: '#ffffff', | ||||
|       colorTo: '#48959d', | ||||
|       description: 'Zero is for manifesto', | ||||
|       color1: '#ffffff', | ||||
|       color2: '#48959d', | ||||
|       color3: '#00ff00', | ||||
|     }, | ||||
|     { | ||||
|       id: 'ES00B', | ||||
|       name: 'zero b-side', | ||||
|       duration: 2470, | ||||
|       description: 'Even Zero has a b-side', | ||||
|       colorFrom: '#0d01b9', | ||||
|       colorTo: '#3b7589', | ||||
|       color1: '#0d01b9', | ||||
|       color2: '#3b7589', | ||||
|       color3: '#00ff00', | ||||
|     }, | ||||
|     { | ||||
|       id: 'ES01A', | ||||
|       name: 'first', | ||||
|       duration: 3487, | ||||
|       description: '...', | ||||
|       colorFrom: '#c7b3aa', | ||||
|       colorTo: '#000100', | ||||
|       color1: '#c7b3aa', | ||||
|       color2: '#000100', | ||||
|       color3: '#00ff00', | ||||
|     }, | ||||
|     { | ||||
|       id: 'ES01B', | ||||
|       name: 'first b-side', | ||||
|       duration: 3773, | ||||
|       description: '...', | ||||
|       colorFrom: '#f7dd01', | ||||
|       colorTo: '#010103', | ||||
|       color1: '#f7dd01', | ||||
|       color2: '#010103', | ||||
|       color3: '#00ff00', | ||||
|     } | ||||
|   ] | ||||
| }) | ||||
|   | ||||
| @@ -5,8 +5,9 @@ export interface Compilation { | ||||
|   duration: number | ||||
|   tracks?: Track[] | ||||
|   description: string | ||||
|   colorFrom: string | ||||
|   colorTo: string | ||||
|   color2: string | ||||
|   color1: string | ||||
|   color3: string | ||||
| } | ||||
|  | ||||
| export interface Artist { | ||||
| @@ -26,3 +27,15 @@ export interface Track { | ||||
|   link: string | ||||
|   coverId: string | ||||
| } | ||||
|  | ||||
| export interface BoxPosition { | ||||
|   x: number | ||||
|   y: number | ||||
|   z: number | ||||
| } | ||||
|  | ||||
| export interface BoxSize { | ||||
|   h: number | ||||
|   w: number | ||||
|   d: number | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user