Merge pull request #3 from Drop-OSS/revert-2-revert-1-refine-website

Redo "better seo and first load performance"
This commit is contained in:
DecDuck
2025-04-20 23:07:04 +10:00
committed by GitHub
39 changed files with 4885 additions and 1568 deletions

View File

@@ -1,50 +1,50 @@
$motiva: (
("MotivaSansThin.ttf", "ttf", 100, normal),
("MotivaSansLight.woff.ttf", "woff", 300, normal),
("MotivaSansRegular.woff.ttf", "woff", 400, normal),
("MotivaSansMedium.woff.ttf", "woff", 500, normal),
("MotivaSansBold.woff.ttf", "woff", 600, normal),
("MotivaSansExtraBold.ttf", "woff", 700, normal),
("MotivaSansBlack.woff.ttf", "woff", 900, normal)
);
// $motiva: (
// ("MotivaSansThin.ttf", "ttf", 100, normal),
// ("MotivaSansLight.woff.ttf", "woff", 300, normal),
// ("MotivaSansRegular.woff.ttf", "woff", 400, normal),
// ("MotivaSansMedium.woff.ttf", "woff", 500, normal),
// ("MotivaSansBold.woff.ttf", "woff", 600, normal),
// ("MotivaSansExtraBold.ttf", "woff", 700, normal),
// ("MotivaSansBlack.woff.ttf", "woff", 900, normal)
// );
$helvetica: (
("Helvetica.woff", "woff", 400, normal),
("Helvetica-Oblique.woff", "woff", 400, italic),
("Helvetica-Bold.woff", "woff", 600, normal),
("Helvetica-BoldOblique.woff", "woff", 600, italic),
("helvetica-light-587ebe5a59211.woff2", "woff2", 300, normal)
);
// $helvetica: (
// ("Helvetica.woff", "woff", 400, normal),
// ("Helvetica-Oblique.woff", "woff", 400, italic),
// ("Helvetica-Bold.woff", "woff", 600, normal),
// ("Helvetica-BoldOblique.woff", "woff", 600, italic),
// ("helvetica-light-587ebe5a59211.woff2", "woff2", 300, normal)
// );
@each $file, $format, $weight, $style in $motiva {
@font-face {
font-family: "Motiva Sans";
src: url("/fonts/motiva/#{$file}") format($format);
font-weight: $weight;
font-style: $style;
}
}
// @each $file, $format, $weight, $style in $motiva {
// @font-face {
// font-family: "Motiva Sans";
// src: url("/fonts/motiva/#{$file}") format($format);
// font-weight: $weight;
// font-style: $style;
// }
// }
@each $file, $format, $weight, $style in $helvetica {
@font-face {
font-family: "Helvetica";
src: url("/fonts/helvetica/#{$file}") format($format);
font-weight: $weight;
font-style: $style;
}
}
// @each $file, $format, $weight, $style in $helvetica {
// @font-face {
// font-family: "Helvetica";
// src: url("/fonts/helvetica/#{$file}") format($format);
// font-weight: $weight;
// font-style: $style;
// }
// }
@font-face {
font-family: "Inter";
src: url("/fonts/inter/InterVariable.ttf");
font-style: normal;
}
// @font-face {
// font-family: "Inter";
// src: url("/fonts/inter/InterVariable.ttf");
// font-style: normal;
// }
@font-face {
font-family: "Inter";
src: url("/fonts/inter/InterVariable-Italic.ttf");
font-style: italic;
}
// @font-face {
// font-family: "Inter";
// src: url("/fonts/inter/InterVariable-Italic.ttf");
// font-style: italic;
// }
.carousel__icon {
color: #f4f4f5;
@@ -66,4 +66,4 @@ $helvetica: (
html {
background-color: oklch(0.21 0.006 285.885);
}
}

View File

@@ -5,16 +5,16 @@
class="-mb-6 flex flex-wrap justify-center gap-x-12 gap-y-3 text-sm/6"
aria-label="Footer"
>
<a
<NuxtLink
v-for="item in navigation.main"
:key="item.name"
:href="item.href"
class="text-zinc-400 hover:text-white"
>{{ item.name }}</a
>{{ item.name }}</NuxtLink
>
</nav>
<div class="mt-16 flex justify-center gap-x-10">
<a
<NuxtLink
v-for="item in navigation.social"
:key="item.name"
:href="item.href"
@@ -22,7 +22,7 @@
>
<span class="sr-only">{{ item.name }}</span>
<component :is="item.icon" class="size-6" aria-hidden="true" />
</a>
</NuxtLink>
</div>
<p class="mt-10 text-center text-sm/6 text-zinc-400">
&copy; {{ new Date().getFullYear() }} Drop OSS. Licensed under GNU
@@ -36,8 +36,7 @@
import { defineComponent, h } from "vue";
const navigation = {
main: [
],
main: [],
social: [
{
name: "GitHub",
@@ -53,20 +52,20 @@ const navigation = {
]),
}),
},
{
name: "YouTube",
href: "#",
icon: defineComponent({
render: () =>
h("svg", { fill: "currentColor", viewBox: "0 0 24 24" }, [
h("path", {
"fill-rule": "evenodd",
d: "M19.812 5.418c.861.23 1.538.907 1.768 1.768C21.998 8.746 22 12 22 12s0 3.255-.418 4.814a2.504 2.504 0 0 1-1.768 1.768c-1.56.419-7.814.419-7.814.419s-6.255 0-7.814-.419a2.505 2.505 0 0 1-1.768-1.768C2 15.255 2 12 2 12s0-3.255.417-4.814a2.507 2.507 0 0 1 1.768-1.768C5.744 5 11.998 5 11.998 5s6.255 0 7.814.418ZM15.194 12 10 15V9l5.194 3Z",
"clip-rule": "evenodd",
}),
]),
}),
},
// {
// name: "YouTube",
// href: "#",
// icon: defineComponent({
// render: () =>
// h("svg", { fill: "currentColor", viewBox: "0 0 24 24" }, [
// h("path", {
// "fill-rule": "evenodd",
// d: "M19.812 5.418c.861.23 1.538.907 1.768 1.768C21.998 8.746 22 12 22 12s0 3.255-.418 4.814a2.504 2.504 0 0 1-1.768 1.768c-1.56.419-7.814.419-7.814.419s-6.255 0-7.814-.419a2.505 2.505 0 0 1-1.768-1.768C2 15.255 2 12 2 12s0-3.255.417-4.814a2.507 2.507 0 0 1 1.768-1.768C5.744 5 11.998 5 11.998 5s6.255 0 7.814.418ZM15.194 12 10 15V9l5.194 3Z",
// "clip-rule": "evenodd",
// }),
// ]),
// }),
// },
],
};
</script>

View File

@@ -78,9 +78,7 @@
</Popover>
-->
<NuxtLink
href="/"
class="text-sm/6 font-semibold text-zinc-100"
<NuxtLink href="/" class="text-sm/6 font-semibold text-zinc-100"
>Home</NuxtLink
>
<NuxtLink
@@ -98,10 +96,10 @@
<div class="hidden lg:flex" />
<div class="hidden lg:flex lg:flex-1 lg:justify-end">
<a
<NuxtLink
href="https://wiki.droposs.org/guides/quickstart.html"
class="text-sm/6 font-semibold text-zinc-100"
>Quickstart <span aria-hidden="true">&rarr;</span></a
>Quickstart <span aria-hidden="true">&rarr;</span></NuxtLink
>
</div>
</nav>
@@ -169,10 +167,10 @@
>
</div>
<div class="py-6">
<a
<NuxtLink
href="https://wiki.droposs.org/guides/quickstart.html"
class="-mx-3 block rounded-lg px-3 py-2.5 text-base/7 font-semibold text-zinc-100 hover:bg-zinc-800"
>Get started &rarr;</a
>Get started &rarr;</NuxtLink
>
</div>
</div>

View File

@@ -4,6 +4,7 @@
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMidYMid meet"
>
<path
d="M4 13.5C4 11.0008 5.38798 8.76189 7.00766 7C8.43926 5.44272 10.0519 4.25811 11.0471 3.5959C11.6287 3.20893 12.3713 3.20893 12.9529 3.5959C13.9481 4.25811 15.5607 5.44272 16.9923 7C18.612 8.76189 20 11.0008 20 13.5C20 17.9183 16.4183 21.5 12 21.5C7.58172 21.5 4 17.9183 4 13.5Z"

View File

@@ -0,0 +1,84 @@
<script lang="ts" setup>
/**
* @credits Pergel <https://nuxtlabs.com/>
* Based on https://github.com/nuxt-modules/og-image/blob/b510a7170d8feeb70790707eab7a075f6b029339/src/runtime/app/components/Templates/Community/Pergel.vue
*/
import { computed } from "vue";
const {
title: propTitle = "title",
description = "description",
headline = "v0.2",
} = defineProps<{
title?: string;
description?: string;
headline?: string;
}>();
const title = computed(() => propTitle.slice(0, 60));
</script>
<template>
<div class="w-full h-full flex flex-col justify-center bg-[#121212]">
<svg
class="absolute top-0 right-0"
width="1200"
height="675"
viewBox="0 0 1200 675"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g
style="mix-blend-mode: overlay"
opacity="0.7"
filter="url(#filter0_f_448_25)"
>
<circle cx="901.5" cy="45.5" r="199.5" fill="#333333" />
<circle cx="600.5" cy="216.5" r="199.5" fill="#444444" />
<circle cx="179.5" cy="317.5" r="199.5" fill="#555555" />
</g>
<defs>
<filter
id="filter0_f_448_25"
x="-240"
y="-374"
width="1561"
height="1111"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB"
>
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feBlend
mode="normal"
in="SourceGraphic"
in2="BackgroundImageFix"
result="shape"
/>
<feGaussianBlur
stdDeviation="110"
result="effect1_foregroundBlur_448_25"
/>
</filter>
</defs>
</svg>
<div class="w-[600px] pl-[100px]">
<p
v-if="headline"
class="uppercase text-[24px] text-blue-400 mb-4 font-semibold"
>
{{ headline }}
</p>
<h1
class="w-[600px] m-0 text-[75px] font-semibold mb-4 text-[#E0E0E0] flex items-center"
>
<span>{{ title }}</span>
</h1>
<p class="text-[32px] text-[#B0B0B0] leading-tight">
{{ description.slice(0, 200) }}
</p>
</div>
<Logo class="absolute top-[180px] right-[190px]" height="250" />
</div>
</template>

View File

@@ -30,5 +30,14 @@
</template>
<script setup lang="ts">
const error = useError();
import { NuxtError } from "#app";
const { error } = defineProps<{
error: NuxtError;
}>();
defineOgImageComponent("NuxtSeo", {
title: error.statusCode.toString(),
description: error.statusMessage,
});
</script>

View File

@@ -95,3 +95,28 @@
</div>
</div>
</template>
<script setup lang="ts">
const siteDesc = "The open-source, self-hosted game distribution platform";
useSeoMeta({
description: siteDesc,
ogDescription: siteDesc,
});
useHead({
htmlAttrs: {
lang: "en",
},
link: [
{
rel: "icon",
type: "image/png",
href: "/favicon.png",
},
],
});
defineOgImageComponent("DropOG", {
title: "Drop OSS",
// logo: "/favicon.png",
});
</script>

View File

@@ -1,18 +1,114 @@
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
compatibilityDate: "2024-11-01",
devtools: { enabled: true },
modules: ["@nuxtjs/tailwindcss", "vue3-carousel-nuxt"],
extends: ["./drop-base"],
css: ["~/assets/core.scss"],
app: {
head: {
link: [{ rel: "icon", href: "/favicon.ico" }],
site: {
url: "https://droposs.org/",
name: "Drop OSS",
},
devtools: {
enabled: true,
timeline: {
enabled: true,
},
},
modules: [
"@nuxtjs/tailwindcss",
"vue3-carousel-nuxt",
"@nuxt/image",
"@nuxt/fonts",
"@nuxtjs/seo",
],
extends: ["./drop-base"],
css: ["~/assets/core.scss"],
carousel: {
prefix: "Vue",
},
ssr: false,
nitro: {
preset: "github_pages",
minify: true,
compressPublicAssets: true,
prerender: {
crawlLinks: true,
},
},
ogImage: {
zeroRuntime: true,
},
fonts: {
families: [
{
name: "Helvetica",
src: "/fonts/helvetica/helvetica-300-light.woff2",
},
{
name: "Helvetica",
src: "/fonts/helvetica/Helvetica-400-italic.woff",
},
{
name: "Helvetica",
src: "/fonts/helvetica/Helvetica-400.woff",
},
{
name: "Helvetica",
src: "/fonts/helvetica/Helvetica-600-bold-italic.woff",
},
{
name: "Helvetica",
src: "/fonts/helvetica/Helvetica-600-bold.woff",
},
{
name: "Inter",
src: "/fonts/inter/Inter-variable-400.ttf",
},
{
name: "Inter",
src: "/fonts/inter/Inter-variable-400-italic.ttf",
},
{
name: "Motiva Sans",
src: "/fonts/motiva/motiva-sans-100-thin.ttf",
},
{
name: "Motiva Sans",
src: "/fonts/motiva/motiva-sans-300-light.woff.ttf",
},
{
name: "Motiva Sans",
src: "/fonts/motiva/motiva-sans-400-regular.woff.ttf",
},
{
name: "Motiva Sans",
src: "/fonts/motiva/motiva-sans-500-medium.woff.ttf",
},
{
name: "Motiva Sans",
src: "/fonts/motiva/motiva-sans-600-bold.woff.ttf",
},
{
name: "Motiva Sans",
src: "/fonts/motiva/motiva-sans-700-extra-bold.ttf",
},
{
name: "Motiva Sans",
src: "/fonts/motiva/motiva-sans-900-black.woff.ttf",
},
],
},
typescript: {
typeCheck: false,
tsConfig: {
compilerOptions: {
verbatimModuleSyntax: false,
strictNullChecks: true,
exactOptionalPropertyTypes: true,
skipLibCheck: true,
},
},
},
});

View File

@@ -7,19 +7,34 @@
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
"postinstall": "nuxt prepare",
"typecheck": "nuxt typecheck"
},
"dependencies": {
"@headlessui/vue": "^1.7.23",
"@heroicons/vue": "^2.2.0",
"@nuxt/fonts": "0.11.1",
"@nuxt/image": "1.10.0",
"@nuxtjs/seo": "3.0.3",
"@nuxtjs/tailwindcss": "6.13.1",
"nuxt": "^3.15.2",
"nuxt": "^3.16.2",
"vite": "6.3.2",
"vue": "latest",
"vue-router": "latest",
"vue3-carousel-nuxt": "^1.1.5"
},
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e",
"devDependencies": {
"sass-embedded": "^1.83.4"
"@nuxt/icon": "^1.12.0",
"sass-embedded": "^1.83.4",
"serve": "^14.2.4",
"typescript": "^5.8.3",
"unstorage": "1.15.0",
"vue-tsc": "^2.2.8"
},
"overrides": {
"vue3-carousel-nuxt": {
"vue3-carousel": "^0.15.0"
}
}
}
}

View File

@@ -32,14 +32,14 @@
project removed or updated.
</p>
<p class="mt-3 text-sm md:ml-6 md:mt-0">
<a
<NuxtLink
href="https://github.com/Drop-OSS/drop-website"
target="_blank"
class="whitespace-nowrap font-medium text-blue-400 hover:text-blue-500"
>
GitHub
<span aria-hidden="true"> &rarr;</span>
</a>
</NuxtLink>
</p>
</div>
</div>

View File

@@ -17,10 +17,13 @@
</div>
<div class="relative overflow-hidden pt-16">
<div class="mx-auto max-w-7xl px-6 lg:px-8">
<img
src="@/assets/ss/admin-metadata.png"
alt="App screenshot"
<NuxtImg
src="/images/ss/admin-metadata.png"
alt="App screenshot"
class="rounded-xl shadow-2xl ring-1 ring-white/10"
quality="80"
format="webp"
preload
/>
</div>
</div>
@@ -50,7 +53,12 @@
</template>
<script setup lang="ts">
import { DocumentDuplicateIcon, PencilIcon, ServerStackIcon } from "@heroicons/vue/24/outline";
import { NuxtImg } from "#components";
import {
DocumentDuplicateIcon,
PencilIcon,
ServerStackIcon,
} from "@heroicons/vue/24/outline";
const features = [
{
@@ -74,6 +82,6 @@ const features = [
];
useHead({
title: "Library"
})
title: "Library",
});
</script>

View File

@@ -14,35 +14,63 @@
creating a Steam-like experience for DRM-free games.
</p>
<div class="mt-10 flex items-center justify-center gap-x-6">
<a
<NuxtLink
href="https://wiki.droposs.org/guides/quickstart.html"
class="rounded-md bg-blue-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-blue-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-400"
>Quickstart &rarr;</a
>Quickstart &rarr;</NuxtLink
>
<a
<NuxtLink
href="https://github.com/Drop-OSS/drop-app/releases"
class="inline-flex items-center gap-x-2 rounded-md bg-zinc-900 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-zinc-950 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-400"
>Download <ArrowDownTrayIcon class="size-4" /> </a
>
>Download <ArrowDownTrayIcon class="size-4" />
</NuxtLink>
</div>
</div>
<div
class="mt-16 rounded-md sm:mt-24 bg-white/5 shadow-2xl ring-1 ring-white/10 p-2"
>
<VueCarousel
:wrapAround="true"
:items-to-show="1"
:autoplay="15 * 1000"
:pauseAutoplayOnHover="true"
>
<VueSlide v-for="image in images" :key="image">
<img class="w-full rounded-md" :src="image" />
</VueSlide>
<ClientOnly fallback-tag="span">
<VueCarousel
:wrapAround="true"
:items-to-show="1"
:autoplay="15 * 1000"
:pauseAutoplayOnHover="true"
>
<VueSlide v-for="(image, i) in images" :key="i">
<!-- when editing this, make sure to change values in prerender thing below -->
<NuxtImg
class="w-full rounded-md"
:src="image"
quality="80"
format="webp"
:placeholder="[100, 100, 75, 5]"
/>
</VueSlide>
<template #addons>
<VueNavigation />
<template #addons>
<VueNavigation />
</template>
</VueCarousel>
<template #fallback>
<div
class="flex flex-nowrap flex-row overflow-hidden whitespace-nowrap"
>
<p>Loading carousel...</p>
</div>
<!-- Invisible pre-rendering hint -->
<div class="hidden">
<NuxtImg
v-for="img in allImages"
:key="img"
:src="img"
quality="80"
format="webp"
preload
:placeholder="[100, 100, 75, 5]"
/>
</div>
</template>
</VueCarousel>
</ClientOnly>
</div>
</div>
</div>
@@ -62,10 +90,13 @@
class="w-full overflow-hidden rounded-lg bg-zinc-800 ring-1 ring-white/15 max-lg:rounded-t-[2rem] lg:rounded-tl-[2rem]"
>
<div class="squiggles relative h-80 w-full overflow-hidden">
<img
<NuxtImg
class="absolute rotate-[-6deg] left-[25%] w-[30rem] z-10 rounded-md"
src="@/assets/updates.png"
src="/images/updates.png"
alt=""
quality="80"
format="webp"
loading="lazy"
/>
</div>
<div class="p-10">
@@ -86,10 +117,13 @@
class="overflow-hidden rounded-lg bg-zinc-800 ring-1 ring-white/15 lg:rounded-tr-[2rem]"
>
<div class="hexagons relative h-80 w-full overflow-hidden">
<img
<NuxtImg
class="absolute rotate-[-6deg] top-[20%] w-[30rem] z-10 rounded-md"
src="@/assets/proton.webp"
src="/images/proton.webp"
alt=""
quality="80"
format="webp"
loading="lazy"
/>
</div>
<div class="p-10">
@@ -133,7 +167,7 @@
<div
class="w-full overflow-hidden rounded-lg bg-zinc-800 ring-1 ring-white/15 max-lg:rounded-b-[2rem] lg:rounded-br-[2rem]"
>
<div class="bubbles relative h-80 w-full overflow-hidden">
<div class="bubbles relative h-80 w-full overflow-hidden">
<P2PIconPlaceholder
class="text-zinc-300 absolute rotate-[0deg] left-1/2 -translate-x-1/2 top-[5%] w-[20rem] z-10 rounded-md"
alt=""
@@ -176,18 +210,37 @@ import { ArrowDownTrayIcon, UserGroupIcon } from "@heroicons/vue/24/outline";
const imageNames = ["hzd.png", "store.png", "hl.png"];
const desktopImages = computed(() =>
imageNames.map((e) => `/images/carousel/${e}`)
);
const mobileImages = computed(() =>
imageNames.map((e) => `/images/carousel/mobile/${e}`)
);
const allImages = computed(() => [
...desktopImages.value,
...mobileImages.value,
]);
const images = ref<string[]>([]);
onMounted(() => {
const handleResize = () => {
const width = window.innerWidth;
if (width <= 640) {
images.value = imageNames.map((e) => `/carousel/mobile/${e}`);
images.value = mobileImages.value;
} else {
images.value = imageNames.map((e) => `/carousel/${e}`);
images.value = desktopImages.value;
}
};
onMounted(() => {
handleResize();
window.addEventListener("resize", handleResize);
});
onBeforeUnmount(() => {
window.removeEventListener("resize", handleResize);
});
useHead({
title: "Home"
})
title: "Home",
});
</script>

View File

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 256 KiB

View File

Before

Width:  |  Height:  |  Size: 294 KiB

After

Width:  |  Height:  |  Size: 294 KiB

View File

Before

Width:  |  Height:  |  Size: 287 KiB

After

Width:  |  Height:  |  Size: 287 KiB

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 MiB

After

Width:  |  Height:  |  Size: 3.0 MiB

View File

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 78 KiB

View File

@@ -1 +0,0 @@

View File

@@ -11,8 +11,8 @@ export default {
theme: {
extend: {
fontFamily: {
sans: ["Inter"],
display: ["Motiva Sans"],
sans: ["Inter", "San Francisco", "sans-serif"],
display: ["Motiva Sans", "Arial", "sans-serif"],
},
colors: {
zinc: {

5922
yarn.lock

File diff suppressed because it is too large Load Diff