This commit is contained in:
valere
2024-08-18 18:47:15 +02:00
commit 24e7bb58fa
25 changed files with 8926 additions and 0 deletions

31
.drone.yml Normal file
View File

@@ -0,0 +1,31 @@
kind: pipeline
type: docker
name: default
steps:
- name: deploy
image: docker:dind
volumes:
- name: docker
path: /var/run/docker.sock
- name: docker-web
path: /root/docker-web
commands:
- apk add --upgrade npm bash findutils rsync sed
- source /root/docker-web/config.sh
- WORKDIR="/root/docker-web/apps/$DRONE_REPO_NAME"
- rm -rf $WORKDIR
- mkdir $WORKDIR
- rsync -av --exclude ./node_modules /drone/src/ $WORKDIR
- cd $WORKDIR
- npm install
- sed -i "/MEDIA_DIR/d" .env
- bash /root/docker-web/src/cli.sh up $DRONE_REPO_NAME
volumes:
- name: dockerweb
host:
path: /root/docker-web
- name: docker
host:
path: /var/run/docker.sock

4
.env Executable file
View File

@@ -0,0 +1,4 @@
DOMAIN=evilspins.com
PORT=7783
DASHBOARD_HIDDEN=false
MEDIA_DIR=~

19
.gitignore vendored Normal file
View File

@@ -0,0 +1,19 @@
# Nuxt dev/build outputs
.output
.data
.nuxt
.nitro
.cache
dist
# Node dependencies
node_modules
# Logs
logs
*.log
# Misc
.DS_Store
.fleet
.idea

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
18.20.2

19
Dockerfile Normal file
View File

@@ -0,0 +1,19 @@
# INSTALL
FROM node:18-alpine as builder
WORKDIR /app
COPY . .
RUN npm ci && npm cache clean --force
ADD . .
# BUILD
RUN npm run build
# PROD
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/.output /app/.output
COPY --from=builder /app/.nuxt /app/.nuxt
COPY --from=builder /app/.env /app/.env
ENV HOST 0.0.0.0
EXPOSE 3000
CMD source .env && node .output/server/index.mjs

1
README.md Normal file
View File

@@ -0,0 +1 @@
# evilSpins

3
app.vue Normal file
View File

@@ -0,0 +1,3 @@
<template>
<NuxtPage />
</template>

3
assets/css/main.css Normal file
View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -0,0 +1,31 @@
<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>

20
docker-compose.yml Executable file
View File

@@ -0,0 +1,20 @@
services:
evilspins:
build: .
container_name: evilspins
restart: unless-stopped
ports:
- $PORT:3000
volumes:
- "${MEDIA_DIR}:/media"
environment:
VIRTUAL_HOST: "${DOMAIN}"
LETSENCRYPT_HOST: "${DOMAIN}"
PUID: "${PUID}"
PGID: "${PGID}"
networks:
default:
name: dockerweb
external: true

103
logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 40 KiB

21
nuxt.config.ts Normal file
View File

@@ -0,0 +1,21 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
devtools: { enabled: true },
css: ['~/assets/css/main.css'],
postcss: {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
},
app: {
head: {
charset: 'utf-8',
viewport: 'width=device-width, initial-scale=1',
}
},
compatibilityDate: '2024-07-10'
})

8122
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

25
package.json Normal file
View File

@@ -0,0 +1,25 @@
{
"name": "nuxt-app",
"private": true,
"type": "module",
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"dependencies": {
"atropos": "^2.0.2",
"nuxt": "^3.12.3",
"unhead": "^1.9.15",
"vue": "^3.4.31",
"vue-router": "^4.4.0"
},
"devDependencies": {
"autoprefixer": "^10.4.19",
"postcss": "^8.4.39",
"sass": "^1.77.6",
"tailwindcss": "^3.4.4"
}
}

181
pages/index.vue Normal file
View File

@@ -0,0 +1,181 @@
<template>
<section class="splash-screen flex items-center flex-col" @keydown.esc="closePlayer" @keydown.enter="play()">
<figure class="ui">
<!-- <ul>
<li>
<a href="mailto:contact@evilspins.com">contact</a>
<a href="/newsletter">newsletter</a>
<a href="/infos">?</a>
</li>
</ul> -->
<img class="logo" src="/logo.svg">
<button class="button flex justify-center items-center" @click="play()">
<svg width="40px" height="30px">
<polygon points="0,0 0,30 30,15" />
</svg>
</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>
<div class="mix screen hide">
<video class="mixPlayer screen" controls ref="mixPlayer">
<source src="https://files.erudi.fr/evilspins/zero-hd.mp4" type="video/mp4">
<source src="https://files.erudi.fr/evilspins/zero-sd.mp4" type="video/webm" media="all and (max-width: 640px)">
</video>
<button class="button button--close flex justify-center items-center" @click="closePlayer()">
<svg width="40px" height="30px">
<line x1="0" y1="0" x2="20" y2="20" stroke="black" stroke-width="2" />
<line x1="0" y1="20" x2="20" y2="0" stroke="black" stroke-width="2" />
</svg>
</button>
</div>
</section>
</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'
})
// animate player
const mixPlayer = ref()
const play = () => {
fadeOut(document.querySelector('.button'))
fadeOut(document.querySelector('.logo'))
fadeOut(document.querySelector('.animation'))
fadeIn(document.querySelector('.mix'))
fadeOut(document.querySelector('.shadow'))
mixPlayer.value.play()
mixPlayer.value.focus()
}
const closePlayer = () => {
fadeIn(document.querySelector('.animation'))
fadeIn(document.querySelector('.button'))
fadeIn(document.querySelector('.logo'))
fadeOut(document.querySelector('.mix'))
fadeIn(document.querySelector('.shadow'))
mixPlayer.value.pause()
}
const fadeOut = (elt: HTMLElement) => {
elt.classList.add('hide')
}
const fadeIn = (elt: HTMLElement) => {
elt.classList.remove('hide')
}
// load data
const { data: artists} = await useFetch('/api/artists')
const { data: styles, status: statusStyles} = await useFetch('/api/styles', { lazy: true })
const { data: compilations} = await useFetch('/api/compilations')
console.log(compilations.value)
console.log(styles.value)
console.log(statusStyles.value)
</script>
<style lang="scss">
body {
margin: 0;
}
.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;
}
.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));
}
.button {
position: relative;
top: 60px;
padding-left: 16px;
text-decoration: none;
box-shadow: 0 8px 0 0 black;
transition: all .3s;
border: 8px black solid;
line-height: 100%;
height: 70px;
width: 70px;
border-width: 2px;
border-radius: 100px;
cursor: pointer;
color: #fdec50ff;
font-size: 26px;
background-color: rgba(255, 255, 255, 0.35);
&:hover {
background-color: #fdec50ff;
color: black;
}
&:active {
top: 64px;
box-shadow: 0 0 0 0 black;
}
&--close {
right: 24px;
padding-top: 10px;
position: absolute;
}
}
.hide {
opacity: 0;
z-index: 0;
}
.show {
opacity: 1;
}
</style>

5
pages/logo.vue Normal file
View File

@@ -0,0 +1,5 @@
<template>
<div class="bg-black h-screen w-full flex justify-center p-16">
<img src="/logo.svg">
</div>
</template>

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

103
public/logo.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 40 KiB

70
server/api/artists.ts Normal file
View File

@@ -0,0 +1,70 @@
export default eventHandler(() => {
return [
{
id: 0,
name: "L'efondras",
link: "https://leffondras.bandcamp.com/music",
style: [0, 1, 2]
},
{
id: 1,
name: "The kundalini genie",
link: "https://the-kundalini-genie.bandcamp.com",
style: [0, 1, 2]
},
{
id: 2,
name: "Fontaines D.C.",
link: "https://fontainesdc.bandcamp.com",
style: [0, 1, 2]
},
{
id: 3,
name: "Fontanarosa",
link: "https://fontanarosa.bandcamp.com",
style: [0, 1, 2]
},
{
id: 4,
name: "Johnny mafia",
link: "https://johnnymafia.bandcamp.com",
style: [0, 1, 2]
},
{
id: 5,
name: "New candys",
link: "https://newcandys.bandcamp.com",
style: [0, 1, 2]
},
{
id: 6,
name: "Magic shoppe",
link: "https://magicshoppe.bandcamp.com",
style: [0, 1, 2]
},
{
id: 7,
name: "Les jaguars",
link: "https://radiomartiko.bandcamp.com/album/surf-qu-b-cois",
style: [0, 1, 2]
},
{
id: 8,
name: "TRAAMS",
link: "https://traams.bandcamp.com",
style: [0, 1, 2]
},
{
id: 9,
name: "Blue orchid",
link: "https://blue-orchid.bandcamp.com",
style: [0, 1, 2]
},
{
id: 10,
name: "I love UFO",
link: "https://bruitblanc.bandcamp.com",
style: [0, 1, 2]
}
]
})

View File

@@ -0,0 +1,12 @@
export default eventHandler(() => {
return [
{
id: 'ES00',
name: 'Zero'
},
{
id: 'ES01',
name: 'Zero B-Side'
}
]
})

16
server/api/styles.ts Normal file
View File

@@ -0,0 +1,16 @@
export default eventHandler(() => {
return [
{
"id": 0,
"name": "post-rock"
},
{
"id": 1,
"name": "math-rock"
},
{
"id": 2,
"name": "indie-pop"
}
]
})

114
server/api/tracks.ts Normal file
View File

@@ -0,0 +1,114 @@
export default eventHandler(() => {
return [
{
id: 0,
number: 1,
compilation: 'ES00',
title: 'The grinding wheel',
artist: 0,
duration: 392,
bpm: 0,
link: 'https://arakirecords.bandcamp.com/track/the-grinding-wheel'
},
{
id: 1,
number: 2,
compilation: 'ES00',
title: 'Bleach',
artist: 1,
duration: 500,
bpm: 0,
link: 'https://the-kundalini-genie.bandcamp.com/track/bleach-2'
},
{
id: 2,
number: 3,
compilation: 'ES00',
title: 'Televised mind',
artist: 2,
duration: 0,
bpm: 0,
link: 'https://fontainesdc.bandcamp.com/track/televised-mind'
},
{
id: 3,
number: 4,
compilation: 'ES00',
title: 'In it',
artist: 3,
duration: 0,
bpm: 0,
link: 'https://howlinbananarecords.bandcamp.com/track/in-it'
},
{
id: 4,
number: 5,
compilation: 'ES00',
title: 'Bad michel',
artist: 4,
duration: 0,
bpm: 0,
link: 'https://johnnymafia.bandcamp.com/track/bad-michel-3'
},
{
id: 5,
number: 6,
compilation: 'ES00',
title: 'Overall',
artist: 5,
duration: 0,
bpm: 0,
link: 'https://newcandys.bandcamp.com/track/overall'
},
{
id: 6,
number: 6,
compilation: 'ES00',
title: 'Guitar jet',
artist: 5,
duration: 0,
bpm: 0,
link: 'https://radiomartiko.bandcamp.com/track/guitare-jet'
},
{
id: 7,
number: 6,
compilation: 'ES00',
title: 'Blowup',
artist: 5,
duration: 0,
bpm: 0,
link: 'https://magicshoppe.bandcamp.com/track/blowup'
},
{
id: 8,
number: 6,
compilation: 'ES00',
title: 'Intercontinental radio waves',
artist: 5,
duration: 0,
bpm: 0,
link: 'https://traams.bandcamp.com/track/intercontinental-radio-waves'
},
{
id: 9,
number: 6,
compilation: 'ES00',
title: 'Here comes the sun',
artist: 5,
duration: 0,
bpm: 0,
link: 'https://blue-orchid.bandcamp.com/track/here-come-the-sun'
},
{
id: 10,
number: 11,
compilation: 'ES00',
title: 'Like in the movies',
artist: 5,
duration: 0,
bpm: 0,
link: 'https://bruitblanc.bandcamp.com/track/like-in-the-movies-2'
},
]
})

3
server/tsconfig.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": "../.nuxt/tsconfig.server.json"
}

15
tailwind.config.js Normal file
View File

@@ -0,0 +1,15 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./components/**/*.{js,vue,ts}",
"./layouts/**/*.vue",
"./pages/**/*.vue",
"./plugins/**/*.{js,ts}",
"./app.vue",
"./error.vue",
],
theme: {
extend: {},
},
plugins: [],
}

4
tsconfig.json Normal file
View File

@@ -0,0 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
}