🚀 Init
This commit is contained in:
parent
340453c37a
commit
34873130d8
13 changed files with 423 additions and 0 deletions
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# build output
|
||||||
|
dist/
|
||||||
|
# generated types
|
||||||
|
.astro/
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# logs
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
|
||||||
|
# environment variables
|
||||||
|
.env
|
||||||
|
.env.production
|
||||||
|
|
||||||
|
# macOS-specific files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# jetbrains setting folder
|
||||||
|
.idea/
|
20
astro.config.mjs
Normal file
20
astro.config.mjs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import { defineConfig } from 'astro/config'
|
||||||
|
import node from "@astrojs/node"
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
output: 'server',
|
||||||
|
adapter: node({
|
||||||
|
mode: "standalone"
|
||||||
|
}),
|
||||||
|
devToolbar: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
vite: {
|
||||||
|
server: {
|
||||||
|
hmr: false, // Auto Reload
|
||||||
|
}
|
||||||
|
},
|
||||||
|
experimental: {
|
||||||
|
serverIslands: true
|
||||||
|
}
|
||||||
|
})
|
BIN
bun.lockb
Executable file
BIN
bun.lockb
Executable file
Binary file not shown.
19
package.json
Normal file
19
package.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "minpluto-server-island",
|
||||||
|
"type": "module",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "astro dev",
|
||||||
|
"start": "astro dev",
|
||||||
|
"build": "astro build",
|
||||||
|
"preview": "astro preview",
|
||||||
|
"astro": "astro"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@astrojs/node": "^8.3.3",
|
||||||
|
"astro": "^4.14.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"sass-embedded": "^1.77.8"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/default.jpg
Normal file
BIN
public/default.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 39 KiB |
88
src/components/ChannelCard.astro
Normal file
88
src/components/ChannelCard.astro
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
---
|
||||||
|
import Video from '@components/Video.astro'
|
||||||
|
const Channel = await fetch("https://yt.sudovanilla.org/api/v1/channels/UCY1kMZp36IQSyNx_9h4mpCg").then((response) => response.json())
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="channel">
|
||||||
|
<div class="channel-header">
|
||||||
|
<div class="channel-header-start">
|
||||||
|
<img src={Channel.authorThumbnails[5].url}/>
|
||||||
|
<h2>{Channel.author}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="channel-header-end">
|
||||||
|
<button>Subscribe</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tabs">
|
||||||
|
<a href="#">Videos</a>
|
||||||
|
<a href="#">Playlists</a>
|
||||||
|
<a href="#">Posts</a>
|
||||||
|
<a href="#">About</a>
|
||||||
|
</div>
|
||||||
|
<div class="video-grid">
|
||||||
|
{Channel.latestVideos.map((data) =>
|
||||||
|
<Video
|
||||||
|
ID={data.videoId}
|
||||||
|
Title={data.title}
|
||||||
|
Creator={data.author}
|
||||||
|
Views={data.viewCount}
|
||||||
|
UploadDate={data.published}
|
||||||
|
Length={data.lengthSeconds}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.channel {
|
||||||
|
.channel-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0px 24px;
|
||||||
|
.channel-header-start {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
img {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.channel-header-end {
|
||||||
|
button {
|
||||||
|
color: black;
|
||||||
|
background: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 3rem;
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 16px 0px;
|
||||||
|
padding: 0px 24px;
|
||||||
|
a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
background: #373737;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
grid-gap: 25px;
|
||||||
|
max-width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
padding: 0px 24px;
|
||||||
|
}
|
||||||
|
</style>
|
150
src/components/ChannelCardSkeleton.astro
Normal file
150
src/components/ChannelCardSkeleton.astro
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
---
|
||||||
|
import Video from '@components/Video.astro'
|
||||||
|
const Channel = await fetch("https://yt.sudovanilla.org/api/v1/channels/UCY1kMZp36IQSyNx_9h4mpCg").then((response) => response.json())
|
||||||
|
---
|
||||||
|
|
||||||
|
<div class="channel">
|
||||||
|
<div class="channel-header">
|
||||||
|
<div class="channel-header-start">
|
||||||
|
<div class="loading-skel-avatar"></div>
|
||||||
|
<div class="loading-skel"></div>
|
||||||
|
</div>
|
||||||
|
<div class="channel-header-end">
|
||||||
|
<div class="loading-skel"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tabs">
|
||||||
|
<div class="loading-skel"></div>
|
||||||
|
<div class="loading-skel"></div>
|
||||||
|
<div class="loading-skel"></div>
|
||||||
|
<div class="loading-skel"></div>
|
||||||
|
</div>
|
||||||
|
<div class="video-grid">
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
<div class="loading-skel-video"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@keyframes wave-lines {
|
||||||
|
0% {
|
||||||
|
background-position: -468px 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 468px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes wave-squares {
|
||||||
|
0% {
|
||||||
|
background-position: -468px 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: 468px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-skel {
|
||||||
|
height: 32px;
|
||||||
|
background: linear-gradient(to right, rgba(130, 130, 130, 0.2) 8%, rgba(130, 130, 130, 0.3) 18%, rgba(130, 130, 130, 0.2) 33%);
|
||||||
|
background-size: 800px 100px;
|
||||||
|
animation: wave-lines 1s infinite ease-out;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
max-width: 100px;
|
||||||
|
min-width: 100px;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-skel-avatar {
|
||||||
|
background: linear-gradient(to right, rgba(130, 130, 130, 0.2) 8%, rgba(130, 130, 130, 0.3) 18%, rgba(130, 130, 130, 0.2) 33%);
|
||||||
|
background-size: 800px 100px;
|
||||||
|
animation: wave-lines 1s infinite ease-out;
|
||||||
|
border-radius: 3rem;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
width: 137.7px;
|
||||||
|
height: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-skel-video {
|
||||||
|
height: 232px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
background: linear-gradient(to right, rgba(130, 130, 130, 0.2) 8%, rgba(130, 130, 130, 0.3) 18%, rgba(130, 130, 130, 0.2) 33%);
|
||||||
|
background-size: 800px 100px;
|
||||||
|
animation: wave-lines 2s infinite ease-out;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.channel {
|
||||||
|
.channel-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0px 24px;
|
||||||
|
.channel-header-start {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
img {
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
border-radius: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.channel-header-end {
|
||||||
|
button {
|
||||||
|
color: black;
|
||||||
|
background: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 3rem;
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 16px 0px;
|
||||||
|
padding: 0px 24px;
|
||||||
|
a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
background: #373737;
|
||||||
|
padding: 12px 24px;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||||
|
grid-gap: 25px;
|
||||||
|
max-width: 100%;
|
||||||
|
margin: auto;
|
||||||
|
padding: 0px 24px;
|
||||||
|
}
|
||||||
|
</style>
|
71
src/components/Video.astro
Normal file
71
src/components/Video.astro
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
---
|
||||||
|
// Properties
|
||||||
|
const {
|
||||||
|
ID,
|
||||||
|
Title,
|
||||||
|
Creator,
|
||||||
|
Views,
|
||||||
|
UploadDate,
|
||||||
|
Length
|
||||||
|
} = Astro.props
|
||||||
|
|
||||||
|
// Format Published Date
|
||||||
|
const DateFormat = new Date(UploadDate * 1000).toLocaleDateString()
|
||||||
|
|
||||||
|
// Format Views
|
||||||
|
const ViewsConversion = Intl.NumberFormat('en', { notation: 'compact'})
|
||||||
|
const ViewsFormat = ViewsConversion.format(Views)
|
||||||
|
---
|
||||||
|
|
||||||
|
<a href={'/watch?v=' + ID} class="video-item">
|
||||||
|
<div class="video-item-thumbnail">
|
||||||
|
<img onload="this.style.opacity = '1'" src={'https://ipx.sudovanilla.org' + '/https://i.ytimg.com/vi/' + ID + '/hqdefault.jpg'} loading="lazy"/>
|
||||||
|
<p id="vi-length">{Length}</p>
|
||||||
|
</div>
|
||||||
|
<div class="video-item-details">
|
||||||
|
<p id="vi-title">{Title}</p>
|
||||||
|
<p id="vi-author">By {Creator}</p>
|
||||||
|
<p id="vi-viewCount">{ViewsFormat} Views - {DateFormat}</p>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.video-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
.video-item-thumbnail {
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 6px;
|
||||||
|
aspect-ratio: 16/9;
|
||||||
|
object-fit: cover;
|
||||||
|
opacity: 0;
|
||||||
|
transition: 0.3s opacity;
|
||||||
|
}
|
||||||
|
p#vi-length {
|
||||||
|
margin: -41px 0px 0px 0px;
|
||||||
|
background: rgba(0,0,0,0.75);
|
||||||
|
padding: 12px 6px 6px 16px;
|
||||||
|
width: max-content;
|
||||||
|
border-radius: 50px 0px 6px 0px;
|
||||||
|
position: relative;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.video-item-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
p {
|
||||||
|
margin: 0px;
|
||||||
|
&#vi-title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
&#vi-author {
|
||||||
|
color: darkgrey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
1
src/env.d.ts
vendored
Normal file
1
src/env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/// <reference path="../.astro/types.d.ts" />
|
21
src/layouts/Default.astro
Normal file
21
src/layouts/Default.astro
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
---
|
||||||
|
const { Title } = Astro.props
|
||||||
|
---
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{Title}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p><a href="/">Without Server Island</a> | <a href="/island">Server Island</a></p>
|
||||||
|
<slot/>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
9
src/pages/index.astro
Normal file
9
src/pages/index.astro
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
import ChannelCard from '@components/ChannelCard.astro'
|
||||||
|
import ChannelCardSkeleton from '@components/ChannelCardSkeleton.astro'
|
||||||
|
import Base from '@layouts/Default.astro'
|
||||||
|
---
|
||||||
|
|
||||||
|
<Base Title="Server Island">
|
||||||
|
<ChannelCard/>
|
||||||
|
</Base>
|
11
src/pages/island.astro
Normal file
11
src/pages/island.astro
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
import ChannelCard from '@components/ChannelCard.astro'
|
||||||
|
import ChannelCardSkeleton from '@components/ChannelCardSkeleton.astro'
|
||||||
|
import Base from '@layouts/Default.astro'
|
||||||
|
---
|
||||||
|
|
||||||
|
<Base Title="Server Island">
|
||||||
|
<ChannelCard server:defer>
|
||||||
|
<ChannelCardSkeleton slot='fallback'/>
|
||||||
|
</ChannelCard>
|
||||||
|
</Base>
|
9
tsconfig.json
Normal file
9
tsconfig.json
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {
|
||||||
|
"@components/*": ["src/components/*"],
|
||||||
|
"@layouts/*": ["src/layouts/*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue