feat: 轮播图组件

This commit is contained in:
2026-05-14 15:10:57 +08:00
parent 5668ec3747
commit 89ea954743
9 changed files with 361 additions and 400 deletions

10
.prettierrc.json Normal file
View File

@@ -0,0 +1,10 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 4,
"singleQuote": true,
"printWidth": 100,
"useTabs": true,
"trailingComma": "none",
"vueIndentScriptAndStyle": true
}

View File

@@ -1,5 +1,5 @@
{
"name": "Codecreate",
"name": "code-create",
"private": true,
"version": "0.0.0",
"type": "module",
@@ -9,7 +9,9 @@
"preview": "vite preview"
},
"dependencies": {
"@kagol/vue-carousel": "^0.1.2",
"@unhead/vue": "^2.1.15",
"unhead": "2.1.15",
"vite-ssg": "^28.3.0",
"vue": "^3.5.34",
"vue-router": "^4.6.4"

92
pnpm-lock.yaml generated
View File

@@ -8,12 +8,18 @@ importers:
.:
dependencies:
'@kagol/vue-carousel':
specifier: ^0.1.2
version: 0.1.2(typescript@6.0.3)
'@unhead/vue':
specifier: ^2.1.15
version: 2.1.15(vue@3.5.34(typescript@6.0.3))
unhead:
specifier: 2.1.15
version: 2.1.15
vite-ssg:
specifier: ^28.3.0
version: 28.3.0(unhead@3.1.0(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1)))(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1))(vue-router@4.6.4(vue@3.5.34(typescript@6.0.3)))(vue@3.5.34(typescript@6.0.3))
version: 28.3.0(unhead@2.1.15)(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1))(vue-router@4.6.4(vue@3.5.34(typescript@6.0.3)))(vue@3.5.34(typescript@6.0.3))
vue:
specifier: ^3.5.34
version: 3.5.34(typescript@6.0.3)
@@ -140,9 +146,6 @@ packages:
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
'@jridgewell/remapping@2.3.5':
resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==}
'@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
@@ -156,6 +159,9 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@kagol/vue-carousel@0.1.2':
resolution: {integrity: sha512-znX+G+QxksjXve0XoTuPT4Sgbqa9XeMDTMlrlY312BDMdbbLWZOUifr0b16ExxHvBOzrBKVPo5e1Zs5JNRoqww==}
'@napi-rs/wasm-runtime@1.1.4':
resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==}
peerDependencies:
@@ -260,6 +266,16 @@ packages:
'@rolldown/pluginutils@1.0.0-rc.13':
resolution: {integrity: sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==}
'@rollup/rollup-darwin-x64@4.14.1':
resolution: {integrity: sha512-2pYRzEjVqq2TB/UNv47BV/8vQiXkFGVmPFwJb+1E0IFFZbIX8/jo1olxqqMbo6xCXf8kabANhp5bzCij2tFLUA==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-linux-x64-gnu@4.14.1':
resolution: {integrity: sha512-9Q7DGjZN+hTdJomaQ3Iub4m6VPu1r94bmK2z3UeWP3dGUecRC54tmVu9vKHTm1bOt3ASoYtEz6JSRLFzrysKlA==}
cpu: [x64]
os: [linux]
'@tybys/wasm-util@0.10.2':
resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
@@ -673,18 +689,6 @@ packages:
unhead@2.1.15:
resolution: {integrity: sha512-MCt5T90mCWyr3Z6pUCdM9lVRXoMoVBlL7z7U4CYVIiaDiuzad/UCfLuMqz5MeNmpZUgoBCQnrucJimU7EZR+XA==}
unhead@3.1.0:
resolution: {integrity: sha512-SH1PAjAMspLIoBjAjE/R8hty2NYo7YcIrdu5I+PVfiW4QmmwEG4pgoiKG0MCs6WRSwiatzeha+4lqSqvHW9PEg==}
peerDependencies:
vite: '>=6.4.2'
peerDependenciesMeta:
vite:
optional: true
unplugin@3.0.0:
resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==}
engines: {node: ^20.19.0 || >=22.12.0}
vite-ssg-sitemap@0.10.0:
resolution: {integrity: sha512-OIja4fqUMcvWl5+bxQARe3LgzWTd8U/dWHWgrqiC7vv3AmTn0YnhMNUAimQ0M/0Aa9myEIAGLV0yKlYbKP8BJQ==}
@@ -771,6 +775,9 @@ packages:
typescript:
optional: true
vueuse-components@0.0.1:
resolution: {integrity: sha512-VaodJj28CTwBEuUdAYkx2qmgUI18AnVrzu7gjwCfVSfnuUoQZDF33px9WNdbmEKpoUGXbhVDM1j/kv3xVcAlKQ==}
w3c-xmlserializer@5.0.0:
resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
engines: {node: '>=18'}
@@ -779,9 +786,6 @@ packages:
resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==}
engines: {node: '>=20'}
webpack-virtual-modules@0.6.2:
resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
whatwg-mimetype@5.0.0:
resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==}
engines: {node: '>=20'}
@@ -885,11 +889,6 @@ snapshots:
'@jridgewell/sourcemap-codec': 1.5.5
'@jridgewell/trace-mapping': 0.3.31
'@jridgewell/remapping@2.3.5':
dependencies:
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/source-map@0.3.11':
@@ -904,6 +903,16 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
'@kagol/vue-carousel@0.1.2(typescript@6.0.3)':
dependencies:
vue: 3.5.34(typescript@6.0.3)
vueuse-components: 0.0.1(typescript@6.0.3)
optionalDependencies:
'@rollup/rollup-darwin-x64': 4.14.1
'@rollup/rollup-linux-x64-gnu': 4.14.1
transitivePeerDependencies:
- typescript
'@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)':
dependencies:
'@emnapi/core': 1.10.0
@@ -966,6 +975,12 @@ snapshots:
'@rolldown/pluginutils@1.0.0-rc.13': {}
'@rollup/rollup-darwin-x64@4.14.1':
optional: true
'@rollup/rollup-linux-x64-gnu@4.14.1':
optional: true
'@tybys/wasm-util@0.10.2':
dependencies:
tslib: 2.8.1
@@ -975,9 +990,9 @@ snapshots:
dependencies:
undici-types: 7.16.0
'@unhead/dom@2.1.15(unhead@3.1.0(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1)))':
'@unhead/dom@2.1.15(unhead@2.1.15)':
dependencies:
unhead: 3.1.0(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1))
unhead: 2.1.15
'@unhead/vue@2.1.15(vue@3.5.34(typescript@6.0.3))':
dependencies:
@@ -1395,24 +1410,11 @@ snapshots:
dependencies:
hookable: 6.1.1
unhead@3.1.0(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1)):
dependencies:
hookable: 6.1.1
unplugin: 3.0.0
optionalDependencies:
vite: 8.0.12(@types/node@24.12.4)(terser@5.47.1)
unplugin@3.0.0:
dependencies:
'@jridgewell/remapping': 2.3.5
picomatch: 4.0.4
webpack-virtual-modules: 0.6.2
vite-ssg-sitemap@0.10.0: {}
vite-ssg@28.3.0(unhead@3.1.0(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1)))(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1))(vue-router@4.6.4(vue@3.5.34(typescript@6.0.3)))(vue@3.5.34(typescript@6.0.3)):
vite-ssg@28.3.0(unhead@2.1.15)(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1))(vue-router@4.6.4(vue@3.5.34(typescript@6.0.3)))(vue@3.5.34(typescript@6.0.3)):
dependencies:
'@unhead/dom': 2.1.15(unhead@3.1.0(vite@8.0.12(@types/node@24.12.4)(terser@5.47.1)))
'@unhead/dom': 2.1.15(unhead@2.1.15)
'@unhead/vue': 2.1.15(vue@3.5.34(typescript@6.0.3))
ansis: 4.3.0
cac: 6.7.14
@@ -1464,14 +1466,18 @@ snapshots:
optionalDependencies:
typescript: 6.0.3
vueuse-components@0.0.1(typescript@6.0.3):
dependencies:
vue: 3.5.34(typescript@6.0.3)
transitivePeerDependencies:
- typescript
w3c-xmlserializer@5.0.0:
dependencies:
xml-name-validator: 5.0.0
webidl-conversions@8.0.1: {}
webpack-virtual-modules@0.6.2: {}
whatwg-mimetype@5.0.0: {}
whatwg-url@16.0.1:

View File

@@ -0,0 +1,181 @@
<template>
<section class="carousel-container" aria-label="Featured content">
<KagolCarousel
v-model="activePage"
class="home-carousel"
:autoplay="isAutoplayEnabled"
:interval="5000"
>
<article v-for="slide in slides" :key="slide.id" class="carousel-slide">
<img class="carousel-image" :src="slide.image" :alt="slide.alt" />
</article>
<template #pagination="{ prevPage, nextPage }">
<nav class="carousel-pagination" aria-label="Carousel pagination">
<button
class="carousel-pagination-button carousel-pagination-button-prev"
type="button"
aria-label="Previous slide"
@click="prevPage"
>
<span
class="carousel-pagination-arrow carousel-pagination-arrow-prev"
></span>
</button>
<button
class="carousel-pagination-button carousel-pagination-button-next"
type="button"
aria-label="Next slide"
@click="nextPage"
>
<span
class="carousel-pagination-arrow carousel-pagination-arrow-next"
></span>
</button>
</nav>
</template>
<template #indicator></template>
</KagolCarousel>
</section>
</template>
<script setup lang="ts">
import { Carousel as KagolCarousel } from '@kagol/vue-carousel'
import '@kagol/vue-carousel/dist/style.css'
import { onMounted, shallowRef } from 'vue'
import mainBanner01 from '../../../assets/images/home/mainbanner01.jpg'
import mainBanner02 from '../../../assets/images/home/mainbanner02.jpg'
const activePage = shallowRef(1)
const isAutoplayEnabled = shallowRef(false)
const slides = [
{
id: 'aida',
image: mainBanner01,
alt: 'AiDA product banner'
},
{
id: 'mixi',
image: mainBanner02,
alt: 'Mixi product banner'
}
] as const
onMounted(() => {
isAutoplayEnabled.value = true
})
</script>
<style scoped>
.carousel-container {
width: 100%;
overflow: hidden;
background: #070b14;
}
.home-carousel {
width: 100%;
}
.carousel-slide {
position: relative;
width: 100%;
aspect-ratio: 16 / 9;
min-height: 360px;
max-height: 680px;
overflow: hidden;
background: #070b14;
}
.carousel-image {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
}
.carousel-pagination {
position: absolute;
right: 0;
bottom: 0;
z-index: 2;
display: flex;
flex-direction: column;
width: 70px;
height: 140px;
transform: translateX(100%);
transition: transform 0.28s ease;
will-change: transform;
}
.carousel-container:hover .carousel-pagination {
transform: translateX(0);
}
.carousel-pagination-button {
position: relative;
display: flex;
flex: 1 1 0;
align-items: center;
justify-content: center;
width: 100%;
padding: 0;
border: 0;
color: #ffffff;
background: #65090c;
cursor: pointer;
appearance: none;
transition: background-color 0.2s ease;
}
.carousel-pagination-button:hover {
background: rgba(255, 255, 255, 0.75);
}
.carousel-pagination-button:focus-visible {
position: relative;
z-index: 1;
outline: 2px solid #ffffff;
outline-offset: -6px;
}
.carousel-pagination-arrow {
position: absolute;
top: 50%;
left: 50%;
display: block;
box-sizing: border-box;
width: 20px;
height: 20px;
border-top: 2.5px solid currentColor;
border-right: 2.5px solid currentColor;
}
.carousel-pagination-arrow-prev {
transform: translate(-50%, -50%) rotate(225deg);
}
.carousel-pagination-arrow-next {
transform: translate(-50%, -50%) rotate(45deg);
}
:deep(.xui-carousel) {
width: 100%;
}
:deep(.xui-carousel-item-container) {
height: 100%;
}
@media (max-width: 768px) {
.carousel-slide {
min-height: 320px;
}
.carousel-pagination-arrow {
width: 18px;
height: 18px;
}
}
</style>

95
src/pages/home/index.vue Normal file
View File

@@ -0,0 +1,95 @@
<template>
<main class="home-page">
<HomeCarousel />
<section class="home-links" aria-label="Site pages">
<RouterLink
v-for="page in pageLinks"
:key="page.to"
class="home-link"
:to="page.to"
>
{{ page.label }}
</RouterLink>
</section>
</main>
</template>
<script setup lang="ts">
import { useHead } from '@unhead/vue'
import { RouterLink } from 'vue-router'
import HomeCarousel from './components/Carousel.vue'
const pageLinks = [
{ label: 'About', to: '/about' },
{ label: 'Products', to: '/products' },
{ label: 'Contact', to: '/contact' },
] as const
useHead({
title: 'Home | Code Create',
meta: [
{
name: 'description',
content: 'Code Create home page rendered with Vite SSG.',
},
],
})
</script>
<style scoped>
.home-page {
/* width: 100%; */
/* min-height: 100svh; */
/* background: #ffffff; */
}
.home-links {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 12px;
padding: 32px 20px 48px;
}
.home-link {
min-width: 112px;
padding: 10px 16px;
border: 1px solid #d9dde6;
border-radius: 6px;
color: #1d2430;
background: #ffffff;
font-size: 15px;
line-height: 1.2;
text-align: center;
text-decoration: none;
box-sizing: border-box;
transition:
border-color 0.2s,
color 0.2s,
box-shadow 0.2s;
}
.home-link:hover,
.home-link:focus-visible,
.home-link.router-link-active {
border-color: #2f6df6;
color: #2f6df6;
box-shadow: 0 8px 24px rgba(36, 55, 92, 0.12);
}
.home-link:focus-visible {
outline: 2px solid #2f6df6;
outline-offset: 2px;
}
@media (max-width: 640px) {
.home-links {
padding: 24px 16px 40px;
}
.home-link {
flex: 1 1 calc(50% - 12px);
}
}
</style>

View File

@@ -1,7 +1,7 @@
import type { RouteRecordRaw } from 'vue-router'
import AboutView from './pages/AboutView.vue'
import ContactView from './pages/ContactView.vue'
import HomeView from './pages/HomeView.vue'
import HomeView from './pages/home/index.vue'
import ProductsView from './pages/ProductsView.vue'
export const routes: RouteRecordRaw[] = [

View File

@@ -1,365 +1,11 @@
:root {
--text: #6b6375;
--text-h: #08060d;
--bg: #fff;
--border: #e5e4e7;
--code-bg: #f4f3ec;
--accent: #aa3bff;
--accent-bg: rgba(170, 59, 255, 0.1);
--accent-border: rgba(170, 59, 255, 0.5);
--social-bg: rgba(244, 243, 236, 0.5);
--shadow:
rgba(0, 0, 0, 0.1) 0 10px 15px -3px, rgba(0, 0, 0, 0.05) 0 4px 6px -2px;
--sans: system-ui, 'Segoe UI', Roboto, sans-serif;
--heading: system-ui, 'Segoe UI', Roboto, sans-serif;
--mono: ui-monospace, Consolas, monospace;
font: 18px/145% var(--sans);
letter-spacing: 0.18px;
color-scheme: light dark;
color: var(--text);
background: var(--bg);
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@media (max-width: 1024px) {
font-size: 16px;
}
}
@media (prefers-color-scheme: dark) {
:root {
--text: #9ca3af;
--text-h: #f3f4f6;
--bg: #16171d;
--border: #2e303a;
--code-bg: #1f2028;
--accent: #c084fc;
--accent-bg: rgba(192, 132, 252, 0.15);
--accent-border: rgba(192, 132, 252, 0.5);
--social-bg: rgba(47, 48, 58, 0.5);
--shadow:
rgba(0, 0, 0, 0.4) 0 10px 15px -3px, rgba(0, 0, 0, 0.25) 0 4px 6px -2px;
}
#social .button-icon {
filter: invert(1) brightness(2);
}
}
body {
html,body{
margin: 0;
}
h1,
h2 {
font-family: var(--heading);
font-weight: 500;
color: var(--text-h);
}
h1 {
font-size: 56px;
letter-spacing: -1.68px;
margin: 32px 0;
@media (max-width: 1024px) {
font-size: 36px;
margin: 20px 0;
}
}
h2 {
font-size: 24px;
line-height: 118%;
letter-spacing: -0.24px;
margin: 0 0 8px;
@media (max-width: 1024px) {
font-size: 20px;
}
}
p {
margin: 0;
}
code,
.counter {
font-family: var(--mono);
display: inline-flex;
border-radius: 4px;
color: var(--text-h);
}
code {
font-size: 15px;
line-height: 135%;
padding: 4px 8px;
background: var(--code-bg);
}
.counter {
font-size: 16px;
padding: 5px 10px;
border-radius: 5px;
color: var(--accent);
background: var(--accent-bg);
border: 2px solid transparent;
transition: border-color 0.3s;
margin-bottom: 24px;
&:hover {
border-color: var(--accent-border);
}
&:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
}
.site-pages {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 10px;
}
.site-page-link {
min-width: 92px;
padding: 8px 14px;
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-h);
background: var(--social-bg);
font-size: 15px;
line-height: 1.2;
text-decoration: none;
box-sizing: border-box;
transition:
border-color 0.2s,
color 0.2s,
box-shadow 0.2s;
&:hover,
&:focus-visible,
&.router-link-active {
border-color: var(--accent-border);
color: var(--accent);
}
&:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
@media (max-width: 480px) {
flex: 1 1 calc(50% - 10px);
}
}
.hero {
position: relative;
.base,
.framework,
.vite {
inset-inline: 0;
margin: 0 auto;
}
.base {
width: 170px;
position: relative;
z-index: 0;
}
.framework,
.vite {
position: absolute;
}
.framework {
z-index: 1;
top: 34px;
height: 28px;
transform: perspective(2000px) rotateZ(300deg) rotateX(44deg) rotateY(39deg)
scale(1.4);
}
.vite {
z-index: 0;
top: 107px;
height: 26px;
width: auto;
transform: perspective(2000px) rotateZ(300deg) rotateX(40deg) rotateY(39deg)
scale(0.8);
}
}
#app {
width: 1126px;
max-width: 100%;
margin: 0 auto;
text-align: center;
border-inline: 1px solid var(--border);
min-height: 100svh;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
#center {
display: flex;
flex-direction: column;
gap: 25px;
place-content: center;
place-items: center;
flex-grow: 1;
@media (max-width: 1024px) {
padding: 32px 20px 24px;
gap: 18px;
}
}
#next-steps {
display: flex;
border-top: 1px solid var(--border);
text-align: left;
& > div {
flex: 1 1 0;
padding: 32px;
@media (max-width: 1024px) {
padding: 24px 20px;
}
}
.icon {
margin-bottom: 16px;
width: 22px;
height: 22px;
}
@media (max-width: 1024px) {
flex-direction: column;
text-align: center;
}
}
#docs {
border-right: 1px solid var(--border);
@media (max-width: 1024px) {
border-right: none;
border-bottom: 1px solid var(--border);
}
}
#next-steps ul {
list-style: none;
padding: 0;
display: flex;
gap: 8px;
margin: 32px 0 0;
.logo {
height: 18px;
}
a {
color: var(--text-h);
font-size: 16px;
border-radius: 6px;
background: var(--social-bg);
display: flex;
padding: 6px 12px;
align-items: center;
gap: 8px;
text-decoration: none;
transition: box-shadow 0.3s;
&:hover {
box-shadow: var(--shadow);
}
.button-icon {
height: 18px;
width: 18px;
}
}
@media (max-width: 1024px) {
margin-top: 20px;
flex-wrap: wrap;
justify-content: center;
li {
flex: 1 1 calc(50% - 8px);
}
a {
width: 100%;
justify-content: center;
box-sizing: border-box;
}
}
}
#spacer {
height: 88px;
border-top: 1px solid var(--border);
@media (max-width: 1024px) {
height: 48px;
}
}
.ticks {
position: relative;
width: 100%;
&::before,
&::after {
content: '';
position: absolute;
top: -4.5px;
border: 5px solid transparent;
}
&::before {
left: 0;
border-left-color: var(--border);
}
&::after {
right: 0;
border-right-color: var(--border);
}
}
.placeholder-page {
min-height: 100svh;
padding: 96px 24px;
box-sizing: border-box;
display: flex;
flex-direction: column;
place-content: center;
place-items: center;
gap: 16px;
}
.placeholder-page p {
max-width: 560px;
}
.placeholder-page a {
color: var(--accent);
text-decoration-thickness: 2px;
text-underline-offset: 4px;
}
.placeholder-kicker {
color: var(--accent);
font-family: var(--mono);
font-size: 14px;
letter-spacing: 0;
text-transform: uppercase;
}

18
src/types/kagol-vue-carousel.d.ts vendored Normal file
View File

@@ -0,0 +1,18 @@
declare module '@kagol/vue-carousel' {
import type { Component, Plugin } from 'vue'
export const Carousel: Component
export const CarouselIndicator: Component
export const CarouselPrev: Component
export const CarouselNext: Component
export const usePage: (initialPage?: number) => {
pageIndex: { value: number }
setPageIndex: (pageIndex: number) => void
jumpPage: (step: number) => void
prevPage: () => void
nextPage: () => void
}
const plugin: Plugin
export default plugin
}

View File

@@ -8,6 +8,9 @@ import generateSitemap from 'vite-ssg-sitemap'
const config = {
base: '/',
plugins: [vue()],
ssr: {
noExternal: ['@kagol/vue-carousel']
},
ssgOptions: {
dirStyle: 'nested',
script: 'defer',