This commit is contained in:
14
.github/workflows/deploy.yml
vendored
14
.github/workflows/deploy.yml
vendored
@@ -4,19 +4,19 @@ on: [push]
|
|||||||
jobs:
|
jobs:
|
||||||
deploy:
|
deploy:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
needs: test
|
|
||||||
container:
|
container:
|
||||||
volumes:
|
volumes:
|
||||||
- /var/docker-web:/var/docker-web
|
- /var/docker-web:/var/docker-web
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Deploy with docker-web
|
- name: Deploy with docker-web
|
||||||
run: |
|
run: |
|
||||||
APP_DIR=/var/docker-web/apps/${GITHUB_REPOSITORY##*/}
|
REPO_NAME="${GITHUB_REPOSITORY##*/}"
|
||||||
mkdir -p $APP_DIR
|
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/"
|
cp -a $(find . -mindepth 1 -maxdepth 1 ! -name '.git' ! -name 'node_modules') "$APP_DIR/"
|
||||||
export COMPOSE_BAKE=false
|
export COMPOSE_BAKE=false
|
||||||
bash /var/docker-web/src/cli.sh down ${GITHUB_REPOSITORY##*/}
|
docker rmi "local/${REPO_NAME}"
|
||||||
docker rmi local/${GITHUB_REPOSITORY##*/}
|
bash /var/docker-web/src/cli.sh up "${REPO_NAME}"
|
||||||
bash /var/docker-web/src/cli.sh up ${GITHUB_REPOSITORY##*/}
|
|
||||||
|
|||||||
@@ -10,44 +10,33 @@
|
|||||||
<div class="face left" ref="leftFace" />
|
<div class="face left" ref="leftFace" />
|
||||||
<div class="face top" ref="topFace">
|
<div class="face top" ref="topFace">
|
||||||
<img class="logo h-full p-1" src="/logo.svg" alt="">
|
<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>
|
||||||
<div class="face bottom" ref="bottomFace" />
|
<div class="face bottom" ref="bottomFace" />
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import compilations from '~~/server/api/compilations';
|
import type { Compilation, BoxPosition } from '~~/types/types';
|
||||||
import type { Compilation } 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
|
// States
|
||||||
const position = ref('')
|
|
||||||
const angleX = ref(76)
|
const angleX = ref(props.position.x)
|
||||||
const angleY = ref(0)
|
const angleY = ref(props.position.y)
|
||||||
const angleZ = ref(150)
|
const angleZ = ref(props.position.z)
|
||||||
|
|
||||||
const frontFace = ref()
|
const frontFace = ref()
|
||||||
const backFace = ref()
|
const backFace = ref()
|
||||||
@@ -56,18 +45,6 @@ const leftFace = ref()
|
|||||||
const topFace = ref()
|
const topFace = ref()
|
||||||
const bottomFace = 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 box = ref()
|
||||||
const scene = 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)`
|
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
|
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) {
|
function applyRotation() {
|
||||||
angleX.value = x
|
angleX.value = props.position.x
|
||||||
angleY.value = y
|
angleY.value = props.position.y
|
||||||
angleZ.value = z
|
angleZ.value = props.position.z
|
||||||
applyTransform()
|
applyTransform()
|
||||||
|
|
||||||
box.value.style.setProperty('transition', 'transform 800ms ease-in-out')
|
box.value.style.setProperty('transition', 'transform 800ms ease-in-out')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
box.value.style.setProperty('transition', 'transform 120ms linear')
|
box.value.style.setProperty('transition', 'transform 120ms linear')
|
||||||
console.log('dopne timeout')
|
|
||||||
}, 120)
|
}, 120)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -151,19 +138,8 @@ function tickInertia() {
|
|||||||
Mise en place des listeners une fois le composant monté
|
Mise en place des listeners une fois le composant monté
|
||||||
*/
|
*/
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// setup CSS vars pour la scène
|
applySize()
|
||||||
updateCssVar('--height', '200px', scene.value)
|
applyColor()
|
||||||
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}`)
|
|
||||||
|
|
||||||
|
|
||||||
applyTransform()
|
applyTransform()
|
||||||
|
|
||||||
// pointerdown = début du drag
|
// pointerdown = début du drag
|
||||||
@@ -221,6 +197,18 @@ onMounted(() => {
|
|||||||
cancelAnimationFrame(raf)
|
cancelAnimationFrame(raf)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(() => props.position, () => {
|
||||||
|
applyRotation()
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
watch(() => props.compilation, () => {
|
||||||
|
applyColor()
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
watch(() => props.size, () => {
|
||||||
|
applySize()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@@ -254,6 +242,7 @@ body {
|
|||||||
position: relative;
|
position: relative;
|
||||||
transform-style: preserve-3d;
|
transform-style: preserve-3d;
|
||||||
transition: transform 120ms linear;
|
transition: transform 120ms linear;
|
||||||
|
transition: height 120ms linear;
|
||||||
/* légère smoothing quand on lâche */
|
/* légère smoothing quand on lâche */
|
||||||
margin: auto;
|
margin: auto;
|
||||||
user-select: none;
|
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="flex flex-col-reverse bg-gradient-to-r from-primary to-primary-dark">
|
||||||
<div class="mt-8 flex flex-wrap justify-center"
|
<div class="mt-8 flex flex-wrap justify-center"
|
||||||
v-for="compilation in store.getAllCompilations.slice().reverse()">
|
v-for="compilation in store.getAllCompilations.slice().reverse()">
|
||||||
<compilationBox :compilation="compilation" template="full" />
|
<box :compilation="compilation" template="full" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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',
|
id: 'ES00A',
|
||||||
name: 'zero',
|
name: 'zero',
|
||||||
duration: 2794,
|
duration: 2794,
|
||||||
description: 'Zero is for manifesto ... ;)',
|
description: 'Zero is for manifesto',
|
||||||
colorFrom: '#ffffff',
|
color1: '#ffffff',
|
||||||
colorTo: '#48959d',
|
color2: '#48959d',
|
||||||
|
color3: '#00ff00',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ES00B',
|
id: 'ES00B',
|
||||||
name: 'zero b-side',
|
name: 'zero b-side',
|
||||||
duration: 2470,
|
duration: 2470,
|
||||||
description: 'Even Zero has a b-side',
|
description: 'Even Zero has a b-side',
|
||||||
colorFrom: '#0d01b9',
|
color1: '#0d01b9',
|
||||||
colorTo: '#3b7589',
|
color2: '#3b7589',
|
||||||
|
color3: '#00ff00',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ES01A',
|
id: 'ES01A',
|
||||||
name: 'first',
|
name: 'first',
|
||||||
duration: 3487,
|
duration: 3487,
|
||||||
description: '...',
|
description: '...',
|
||||||
colorFrom: '#c7b3aa',
|
color1: '#c7b3aa',
|
||||||
colorTo: '#000100',
|
color2: '#000100',
|
||||||
|
color3: '#00ff00',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'ES01B',
|
id: 'ES01B',
|
||||||
name: 'first b-side',
|
name: 'first b-side',
|
||||||
duration: 3773,
|
duration: 3773,
|
||||||
description: '...',
|
description: '...',
|
||||||
colorFrom: '#f7dd01',
|
color1: '#f7dd01',
|
||||||
colorTo: '#010103',
|
color2: '#010103',
|
||||||
|
color3: '#00ff00',
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ export interface Compilation {
|
|||||||
duration: number
|
duration: number
|
||||||
tracks?: Track[]
|
tracks?: Track[]
|
||||||
description: string
|
description: string
|
||||||
colorFrom: string
|
color2: string
|
||||||
colorTo: string
|
color1: string
|
||||||
|
color3: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Artist {
|
export interface Artist {
|
||||||
@@ -26,3 +27,15 @@ export interface Track {
|
|||||||
link: string
|
link: string
|
||||||
coverId: 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