This commit is contained in:
@@ -7,7 +7,9 @@ const { get, post } = api();
|
||||
const { locale } = useI18n();
|
||||
const { t } = useI18n();
|
||||
|
||||
// Move useAsyncData to top level — NOT inside onMounted
|
||||
const currentPath = computed(() => route.path);
|
||||
const route = useRoute();
|
||||
|
||||
const { data: markdown } = await useAsyncData(`fixed-root`, async () =>
|
||||
await queryCollection(`fixed`).path(`/fixed/${locale.value}/root`).first()
|
||||
,{watch: [locale]})
|
||||
@@ -17,6 +19,66 @@ const { data: projects } = await useAsyncData(`projects`, async () =>
|
||||
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()),
|
||||
{ watch: [locale] })
|
||||
|
||||
const { data: posts } = await useAsyncData('blog-posts',
|
||||
() => queryCollection(`blog`).where('path', 'LIKE', `/blog/${locale.value}/%`).order('date', 'DESC').all(),
|
||||
{ watch: [locale] });
|
||||
|
||||
const { data: contactMarkdown } = await useAsyncData(`fixed-contact`, async () =>
|
||||
await queryCollection(`fixed`).path(`/fixed/${locale.value}/contact`).first()
|
||||
,{watch: [locale]})
|
||||
|
||||
const localePath = useLocalePath();
|
||||
|
||||
const artPosts = useState<any[]>('art-posts', () => null as any);
|
||||
if (!artPosts.value?.length) {
|
||||
const currentLocale = locale.value;
|
||||
(async () => {
|
||||
try {
|
||||
if (currentLocale === 'en') {
|
||||
artPosts.value = await queryCollection('art')
|
||||
.where('path', 'LIKE', `/art/en/%`)
|
||||
.order('date', 'DESC')
|
||||
.all();
|
||||
} else {
|
||||
const enPosts = await queryCollection('art')
|
||||
.where('path', 'LIKE', `/art/en/%`)
|
||||
.order('date', 'DESC')
|
||||
.all();
|
||||
const localePosts = await queryCollection('art')
|
||||
.where('path', 'LIKE', `/art/${currentLocale}/%`)
|
||||
.order('date', 'DESC')
|
||||
.all();
|
||||
const translatedSlugs = new Set(
|
||||
localePosts.map((p) => p.path.replace(`/art/${currentLocale}/`, ''))
|
||||
);
|
||||
const enFallbacks = enPosts.filter(
|
||||
(p) => !translatedSlugs.has(p.path.replace('/art/en/', ''))
|
||||
);
|
||||
artPosts.value = [...localePosts, ...enFallbacks].sort(
|
||||
(a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Error loading art posts:', e);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
const isArtFallback = (art) => art.path.startsWith('/art/en/') && locale.value !== 'en';
|
||||
|
||||
const HOME_BLOG_LIMIT = 3;
|
||||
const HOME_ART_LIMIT = 6;
|
||||
|
||||
const displayedBlogPosts = computed(() => {
|
||||
const all = posts.value || [];
|
||||
return all.slice(0, HOME_BLOG_LIMIT);
|
||||
});
|
||||
|
||||
const displayedArtPosts = computed(() => {
|
||||
const all = artPosts.value || [];
|
||||
return all.slice(0, HOME_ART_LIMIT);
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
const response = await get('/test');
|
||||
@@ -24,17 +86,46 @@ onMounted(async () => {
|
||||
console.error('API Error:', error);
|
||||
}
|
||||
});
|
||||
|
||||
function scrollToTop() {
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
}
|
||||
|
||||
function scrollToSection(e: Event, targetId: string) {
|
||||
e.preventDefault();
|
||||
const el = document.querySelector(targetId);
|
||||
if (el) {
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
} else {
|
||||
window.location.hash = targetId.substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
const sectionTargets = {
|
||||
index: '#top',
|
||||
blog: '#scroll-blog',
|
||||
contact: '#scroll-contact',
|
||||
art: '#scroll-art'
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TableHeader></TableHeader>
|
||||
|
||||
<div id="top" style="scroll-margin-top: 60px;"> </div>
|
||||
|
||||
<FixedLayout>
|
||||
<Container>
|
||||
<ContentRenderer v-if="markdown" :value="markdown"></ContentRenderer>
|
||||
|
||||
<section class="projects-section" v-if="projects && projects.length > 0">
|
||||
<section class="intro-section">
|
||||
<Container>
|
||||
<ContentRenderer v-if="markdown" :value="markdown"></ContentRenderer>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<section class="projects-section" id="scroll-projects" v-if="projects && projects.length > 0">
|
||||
<Container>
|
||||
<h2 class="section-title">{{ t('pages.projects_heading') }}</h2>
|
||||
<!--
|
||||
<div class="projects-grid">
|
||||
<div
|
||||
v-for="project in projects"
|
||||
@@ -58,9 +149,15 @@ onMounted(async () => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="stats-section">
|
||||
-->
|
||||
(Under construction...)
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<!--
|
||||
<section class="stats-section" id="scroll-stats">
|
||||
<Container>
|
||||
<h2 class="section-title">{{ t('pages.stats_heading') }}</h2>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
@@ -68,88 +165,215 @@ onMounted(async () => {
|
||||
<span class="stat-card-corner tr"></span>
|
||||
<span class="stat-card-corner bl"></span>
|
||||
<span class="stat-card-corner br"></span>
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 3h2v2H3V3zm4 0h2v2H7V3zm4 0h2v2h-2V3zM3 7h2v2H3V7zm6 0h2v2H9V7zm4 0h2v2h-2V7zM3 11h2v2H3v-2zm4 0h2v2H7v-2zm4 0h2v2h-2v-2z"/></svg>
|
||||
<span class="stat-number">50K+</span>
|
||||
<span class="stat-label">{{ t('pages.stat_lines_of_code') }}</span>
|
||||
<span class="stat-card-frame-top"></span>
|
||||
<span class="stat-card-frame-bottom"></span>
|
||||
<div class="stat-card-header">CODE</div>
|
||||
<div class="stat-card-content">
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M3 3h2v2H3V3zm4 0h2v2H7V3zm4 0h2v2h-2V3zM3 7h2v2H3V7zm6 0h2v2H9V7zm4 0h2v2h-2V7zM3 11h2v2H3v-2zm4 0h2v2H7v-2zm4 0h2v2h-2v-2z"/></svg>
|
||||
<span class="stat-number">50K+</span>
|
||||
<span class="stat-label">{{ t('pages.stat_lines_of_code') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-card-corner tl"></span>
|
||||
<span class="stat-card-corner tr"></span>
|
||||
<span class="stat-card-corner bl"></span>
|
||||
<span class="stat-card-corner br"></span>
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M4 3h8v2H6v2h6v2H8v2h4v2H4V3z"/></svg>
|
||||
<span class="stat-number">12+</span>
|
||||
<span class="stat-label">{{ t('pages.stat_projects') }}</span>
|
||||
<span class="stat-card-frame-top"></span>
|
||||
<span class="stat-card-frame-bottom"></span>
|
||||
<div class="stat-card-header">WORK</div>
|
||||
<div class="stat-card-content">
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M4 3h8v2H6v2h6v2H8v2h4v2H4V3z"/></svg>
|
||||
<span class="stat-number">12+</span>
|
||||
<span class="stat-label">{{ t('pages.stat_projects') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-card-corner tl"></span>
|
||||
<span class="stat-card-corner tr"></span>
|
||||
<span class="stat-card-corner bl"></span>
|
||||
<span class="stat-card-corner br"></span>
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M4 5h8v2H4V5zm-2 2h2v1H2V7zm10 0h2v1h-2V7zM3 9h1v3h1v-1h3v1h1V9h1v3h1v-1h2v1h1v-4H3z"/></svg>
|
||||
<span class="stat-number">∞</span>
|
||||
<span class="stat-label">{{ t('pages.stat_coffee') }}</span>
|
||||
<span class="stat-card-frame-top"></span>
|
||||
<span class="stat-card-frame-bottom"></span>
|
||||
<div class="stat-card-header">CAFFE</div>
|
||||
<div class="stat-card-content">
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M4 5h8v2H4V5zm-2 2h2v1H2V7zm10 0h2v1h-2V7zM3 9h1v3h1v-1h3v1h1V9h1v3h1v-1h2v1h1v-4H3z"/></svg>
|
||||
<span class="stat-number">∞</span>
|
||||
<span class="stat-label">{{ t('pages.stat_coffee') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-card-corner tl"></span>
|
||||
<span class="stat-card-corner tr"></span>
|
||||
<span class="stat-card-corner bl"></span>
|
||||
<span class="stat-card-corner br"></span>
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M2 4h3v2H3v1h2v2H8v-2h2V6h-1V4h3v2h-2v3H5V6H4V4zm7 2h2v2h-2V6z"/></svg>
|
||||
<span class="stat-number">28</span>
|
||||
<span class="stat-label">{{ t('pages.stat_board_games') }}</span>
|
||||
<span class="stat-card-frame-top"></span>
|
||||
<span class="stat-card-frame-bottom"></span>
|
||||
<div class="stat-card-header">PLAY</div>
|
||||
<div class="stat-card-content">
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M2 4h3v2H3v1h2v2H8v-2h2V6h-1V4h3v2h-2v3H5V6H4V4zm7 2h2v2h-2V6z"/></svg>
|
||||
<span class="stat-number">28</span>
|
||||
<span class="stat-label">{{ t('pages.stat_board_games') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-card-corner tl"></span>
|
||||
<span class="stat-card-corner tr"></span>
|
||||
<span class="stat-card-corner bl"></span>
|
||||
<span class="stat-card-corner br"></span>
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M5 2h6v2H5V2zm-2 4h10v1H3V6zm1 2h8v1H4V8zm2 2h4v1H6v-1zM6 2h4v12H6V2z"/></svg>
|
||||
<span class="stat-number">8+</span>
|
||||
<span class="stat-label">{{ t('pages.stat_years_programming') }}</span>
|
||||
<span class="stat-card-frame-top"></span>
|
||||
<span class="stat-card-frame-bottom"></span>
|
||||
<div class="stat-card-header">TIME</div>
|
||||
<div class="stat-card-content">
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M5 2h6v2H5V2zm-2 4h10v1H3V6zm1 2h8v1H4V8zm2 2h4v1H6v-1zM6 2h4v12H6V2z"/></svg>
|
||||
<span class="stat-number">8+</span>
|
||||
<span class="stat-label">{{ t('pages.stat_years_programming') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<span class="stat-card-corner tl"></span>
|
||||
<span class="stat-card-corner tr"></span>
|
||||
<span class="stat-card-corner bl"></span>
|
||||
<span class="stat-card-corner br"></span>
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M4 3h8v2H9v2h2v2h-2v2h-2v2h6v2H2v-2h2v-2H2V7h2V5H2V3z"/></svg>
|
||||
<span class="stat-number">150+</span>
|
||||
<span class="stat-label">{{ t('pages.stat_deployments') }}</span>
|
||||
<span class="stat-card-frame-top"></span>
|
||||
<span class="stat-card-frame-bottom"></span>
|
||||
<div class="stat-card-header">DEPLOY</div>
|
||||
<div class="stat-card-content">
|
||||
<svg class="stat-pixel-art" viewBox="0 0 16 16" aria-hidden="true"><path d="M4 3h8v2H9v2h2v2h-2v2h-2v2h6v2H2v-2h2v-2H2V7h2V5H2V3z"/></svg>
|
||||
<span class="stat-number">150+</span>
|
||||
<span class="stat-label">{{ t('pages.stat_deployments') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</Container>
|
||||
</Container>
|
||||
</section>
|
||||
-->
|
||||
|
||||
<section class="blog-section" id="scroll-blog">
|
||||
<Container>
|
||||
<h2 class="section-title">{{ t('pages.blog_heading') }}</h2>
|
||||
<ul class="tui-list">
|
||||
<li v-for="post in displayedBlogPosts" :key="post.slug" class="blog-entry">
|
||||
<a class="entry-link" :href="localePath({ name: 'blog-slug', params: { slug: post.slug } })">
|
||||
<span class="entry-title">{{ post.title }}</span>
|
||||
</a>
|
||||
<span class="entry-meta">[{{ post.date }}] {{ post.description }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p v-if="posts && posts.length > 0" class="show-more-link">
|
||||
<NuxtLink :to="localePath('/blog')" class="tui-link">{{ t('pages.show_more') }}</NuxtLink>
|
||||
</p>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<section class="contact-section" id="scroll-contact">
|
||||
<Container>
|
||||
<h2 class="section-title">{{ t('pages.contact_heading') }}</h2>
|
||||
<ContentRenderer v-if="contactMarkdown" :value="contactMarkdown"></ContentRenderer>
|
||||
</Container>
|
||||
</section>
|
||||
|
||||
<section class="art-section" id="scroll-art">
|
||||
<Container>
|
||||
<h2 class="section-title">{{ t('pages.art_heading') }}</h2>
|
||||
<div class="grid">
|
||||
<a v-for="art in displayedArtPosts" :key="art.slug"
|
||||
class="selector"
|
||||
:href="isArtFallback(art) ? localePath(`/art/${art.slug}`) : localePath(`/art/${art.slug}`)">
|
||||
<span class="selector-border-top" aria-hidden="true">────────</span>
|
||||
<img
|
||||
:src="art.thumb"
|
||||
:alt="art.title"
|
||||
class="selector-img"
|
||||
/>
|
||||
<span class="selector-border-bottom" aria-hidden="true">────────</span>
|
||||
<div class="overlay-label">{{ art.title }}</div>
|
||||
</a>
|
||||
</div>
|
||||
<p v-if="artPosts && artPosts.length > 0" class="show-more-link">
|
||||
<NuxtLink :to="localePath('/art')" class="tui-link">{{ t('pages.show_more') }}</NuxtLink>
|
||||
</p>
|
||||
</Container>
|
||||
</section>
|
||||
</FixedLayout>
|
||||
<Footer></Footer>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.projects-section {
|
||||
margin-top: 24px;
|
||||
.intro-section {
|
||||
margin-top: 290px;
|
||||
|
||||
> div:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.tui-frame:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) and (min-width: 900px) {
|
||||
margin-top: 380px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 900px) and (min-width: 600px) {
|
||||
margin-top: 280px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
margin-top: 280px;
|
||||
}
|
||||
}
|
||||
|
||||
.projects-section,
|
||||
.stats-section,
|
||||
.blog-section,
|
||||
.contact-section,
|
||||
.art-section {
|
||||
margin-top: 16px;
|
||||
|
||||
.tui-frame:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-family: 'Hurmit', monospace;
|
||||
color: var(--color-text);
|
||||
font-size: 1.3rem;
|
||||
font-size: 1.2rem;
|
||||
letter-spacing: 0.5px;
|
||||
margin-bottom: 16px;
|
||||
border-left: 3px solid var(--color-link);
|
||||
margin: 28px 0 16px 0;
|
||||
padding-left: 12px;
|
||||
line-height: 1.3;
|
||||
|
||||
&::before {
|
||||
content: "├";
|
||||
color: var(--color-link);
|
||||
margin-right: 8px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background-color: var(--color-link);
|
||||
margin-left: 6px;
|
||||
margin-left: 10px;
|
||||
vertical-align: middle;
|
||||
box-shadow: 0 0 6px var(--color-link);
|
||||
box-shadow: 0 0 4px var(--color-link);
|
||||
animation: blink-cursor 1s steps(1) infinite;
|
||||
}
|
||||
}
|
||||
|
||||
.section-title:first-child {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
@keyframes blink-cursor {
|
||||
0%, 50% { opacity: 1; }
|
||||
51%, 100% { opacity: 0; }
|
||||
}
|
||||
|
||||
.projects-grid {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -162,6 +386,24 @@ onMounted(async () => {
|
||||
border: 1px solid var(--color-border-color);
|
||||
box-shadow: 4px -4px 0px 0px var(--color-container-shadow);
|
||||
padding: 12px 16px;
|
||||
transition: all 0.1s steps(2, end);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-link);
|
||||
box-shadow: 4px -4px 0px 0px var(--color-link);
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: "[ PROJECT ]";
|
||||
position: absolute;
|
||||
top: -9px;
|
||||
left: 12px;
|
||||
background-color: var(--color-background-fore);
|
||||
padding: 0 6px;
|
||||
font-size: 0.65rem;
|
||||
color: var(--color-link);
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.project-card-corner {
|
||||
@@ -181,7 +423,7 @@ onMounted(async () => {
|
||||
color: var(--color-link);
|
||||
text-decoration: none;
|
||||
font-size: 1.05rem;
|
||||
text-shadow: 0 0 6px var(--color-link);
|
||||
text-shadow: 0 0 4px var(--color-link);
|
||||
display: block;
|
||||
|
||||
&:hover {
|
||||
@@ -193,7 +435,7 @@ onMounted(async () => {
|
||||
.project-description {
|
||||
font-family: 'Hurmit', monospace;
|
||||
color: var(--color-text);
|
||||
margin: 6px 0 10px 0;
|
||||
margin: 8px 0 12px 0;
|
||||
line-height: 1.5;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
@@ -201,16 +443,17 @@ onMounted(async () => {
|
||||
.project-tech {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.tech-tag {
|
||||
font-family: 'Hurmit', monospace;
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.7rem;
|
||||
color: var(--color-background-fore);
|
||||
background-color: var(--color-link);
|
||||
padding: 2px 8px;
|
||||
padding: 1px 6px;
|
||||
box-shadow: 2px -2px 0px 0px rgba(0, 0, 0, 0.3);
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.stats-section {
|
||||
@@ -226,40 +469,108 @@ onMounted(async () => {
|
||||
.stat-card {
|
||||
position: relative;
|
||||
background: var(--color-background-fore);
|
||||
border: 1px solid var(--color-border-color);
|
||||
box-shadow: 3px -3px 0px 0px var(--color-container-shadow);
|
||||
padding: 14px 10px;
|
||||
border: 2px solid var(--color-border-color);
|
||||
box-shadow:
|
||||
inset 1px -1px 0px 0px rgba(0,0,0,0.3),
|
||||
4px -4px 0px 0px var(--color-container-shadow);
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
gap: 6px;
|
||||
gap: 0;
|
||||
overflow: hidden;
|
||||
transition: all 0.1s steps(2, end);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-link);
|
||||
box-shadow:
|
||||
inset 1px -1px 0px 0px rgba(0,0,0,0.3),
|
||||
4px -4px 0px 0px var(--color-link);
|
||||
}
|
||||
|
||||
.stat-card-corner {
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-color: #cfcfcf;
|
||||
|
||||
&.tl { top: -1px; left: -1px; border-top: 2px solid; border-left: 2px solid; }
|
||||
&.tr { top: -1px; right: -1px; border-top: 2px solid; border-right: 2px solid; }
|
||||
&.bl { bottom: -1px; left: -1px; border-bottom: 2px solid; border-left: 2px solid; }
|
||||
&.br { bottom: -1px; right: -1px; border-bottom: 2px solid; border-right: 2px solid; }
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card-corner {
|
||||
.stat-card-frame-top {
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-color: #cfcfcf;
|
||||
top: -2px;
|
||||
left: 14px;
|
||||
right: 14px;
|
||||
height: 0;
|
||||
color: var(--color-border-color);
|
||||
font-family: 'Hurmit', monospace;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
white-space: nowrap;
|
||||
|
||||
&.tl { top: -1px; left: -1px; border-top: 2px solid; border-left: 2px solid; }
|
||||
&.tr { top: -1px; right: -1px; border-top: 2px solid; border-right: 2px solid; }
|
||||
&.bl { bottom: -1px; left: -1px; border-bottom: 2px solid; border-left: 2px solid; }
|
||||
&.br { bottom: -1px; right: -1px; border-bottom: 2px solid; border-right: 2px solid; }
|
||||
&::before {
|
||||
content: "═════";
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card-frame-bottom {
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 14px;
|
||||
right: 14px;
|
||||
height: 0;
|
||||
color: var(--color-border-color);
|
||||
font-family: 'Hurmit', monospace;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
white-space: nowrap;
|
||||
|
||||
&::before {
|
||||
content: "═════";
|
||||
}
|
||||
}
|
||||
|
||||
.stat-card-header {
|
||||
background-color: var(--color-link);
|
||||
color: var(--color-background-fore);
|
||||
padding: 3px 12px;
|
||||
font-family: 'Hurmit', monospace;
|
||||
font-size: 0.55rem;
|
||||
letter-spacing: 2px;
|
||||
text-transform: uppercase;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
box-shadow: inset 0 -2px 0px 0px rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.stat-card-content {
|
||||
padding: 16px 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.stat-pixel-art {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-bottom: 4px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
margin-bottom: 2px;
|
||||
fill: var(--color-link);
|
||||
filter: drop-shadow(0 0 6px var(--color-link));
|
||||
filter: drop-shadow(0 0 4px var(--color-link));
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-family: 'Hurmit', monospace;
|
||||
font-size: 1.8rem;
|
||||
font-size: 1.6rem;
|
||||
color: var(--color-link);
|
||||
text-shadow: 0 0 8px var(--color-link), 0 0 4px var(--color-link);
|
||||
font-weight: bold;
|
||||
@@ -269,16 +580,178 @@ onMounted(async () => {
|
||||
.stat-label {
|
||||
font-family: 'Hurmit', monospace;
|
||||
color: var(--color-text);
|
||||
font-size: 0.7rem;
|
||||
font-size: 0.65rem;
|
||||
line-height: 1.35;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Blog section */
|
||||
.blog-section {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.tui-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.blog-entry {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 8px 16px;
|
||||
border-left: 2px solid var(--color-border-color);
|
||||
margin-bottom: 4px;
|
||||
transition: all 0.1s steps(2, end);
|
||||
|
||||
&:hover {
|
||||
border-left-color: var(--color-link);
|
||||
background-color: var(--color-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.entry-link {
|
||||
text-decoration: none;
|
||||
color: var(--color-text);
|
||||
|
||||
&:hover {
|
||||
color: var(--color-link);
|
||||
text-shadow: 0 0 6px var(--color-link);
|
||||
}
|
||||
}
|
||||
|
||||
.entry-title {
|
||||
font-family: 'Hurmit', monospace;
|
||||
font-size: 1rem;
|
||||
transition: all 0.1s steps(2, end);
|
||||
}
|
||||
|
||||
.entry-meta {
|
||||
font-family: 'Hurmit', monospace;
|
||||
color: var(--color-text);
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.show-more-link {
|
||||
margin-top: 12px;
|
||||
padding-left: 14px;
|
||||
|
||||
a {
|
||||
color: var(--color-link);
|
||||
font-family: 'Hurmit', monospace;
|
||||
font-size: 0.85rem;
|
||||
text-shadow: 0 0 4px var(--color-link);
|
||||
transition: all 0.1s steps(2, end);
|
||||
|
||||
&:hover {
|
||||
text-shadow: 0 0 10px var(--color-link), 0 0 3px var(--color-link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Contact section */
|
||||
.contact-section {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
/* Art section */
|
||||
.art-section {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(250px, 1fr));
|
||||
gap: 16px;
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
.selector {
|
||||
width: 100%;
|
||||
height: 250px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
transition: all 0.1s steps(3, end);
|
||||
display: block;
|
||||
border: 2px solid var(--color-border-color);
|
||||
background-color: var(--color-background-fore);
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-link);
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 4px -4px 0px 0px var(--color-link);
|
||||
}
|
||||
|
||||
.selector-border-top,
|
||||
.selector-border-bottom {
|
||||
position: absolute;
|
||||
left: 30px;
|
||||
right: 30px;
|
||||
height: 0;
|
||||
color: var(--color-border-color);
|
||||
font-family: 'Hurmit', monospace;
|
||||
font-size: 0;
|
||||
line-height: 0;
|
||||
white-space: nowrap;
|
||||
z-index: 10;
|
||||
transition: color 0.1s steps(2, end);
|
||||
}
|
||||
|
||||
.selector-border-top {
|
||||
top: -2px;
|
||||
&::before { content: "═══════════════════"; }
|
||||
}
|
||||
|
||||
.selector-border-bottom {
|
||||
bottom: -2px;
|
||||
&::before { content: "═══════════════════"; }
|
||||
}
|
||||
}
|
||||
|
||||
.selector-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.overlay-label {
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 30px;
|
||||
background-color: var(--color-link);
|
||||
color: var(--color-background-fore);
|
||||
padding: 2px 8px;
|
||||
font-family: 'Hurmit', monospace;
|
||||
font-size: 0.7rem;
|
||||
letter-spacing: 1px;
|
||||
text-transform: uppercase;
|
||||
box-shadow: inset 0 -2px 0px 0px rgba(0,0,0,0.3);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes blink-cursor {
|
||||
0%, 50% { opacity: 1; }
|
||||
51%, 100% { opacity: 0; }
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.grid {
|
||||
grid-template-columns: repeat(2, minmax(200px, 1fr));
|
||||
}
|
||||
|
||||
.selector {
|
||||
height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
@@ -303,17 +776,35 @@ onMounted(async () => {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
padding: 10px 6px;
|
||||
.stat-card-header {
|
||||
padding: 2px 8px;
|
||||
font-size: 0.5rem;
|
||||
}
|
||||
|
||||
.stat-card-content {
|
||||
padding: 12px 6px;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 0.6rem;
|
||||
}
|
||||
|
||||
.stat-pixel-art {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
grid-template-columns: repeat(1, minmax(200px, 1fr));
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
.selector {
|
||||
height: 180px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user