Compare commits

...

3 Commits

Author SHA1 Message Date
techit 6cfcf535e7 new footer section
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled
2025-10-26 21:34:52 +07:00
techit 1f5c887c7f new style for buttons 2025-10-26 21:34:41 +07:00
techit 0de6f55378 Fix dissmissible banner typo 2025-10-26 21:34:32 +07:00
5 changed files with 130 additions and 71 deletions
+52 -11
View File
@@ -9,9 +9,9 @@
--color-surface-background: #f9f9f9;
--color-on-surface-background: #111111;
--color-primary: #2e2e2e;
--color-primary: #1a1a1a;
--color-primary-strong: #3e3e3e;
--color-on-primary: white;
--color-on-primary: #eeeeee;
--color-on-primary-weak: #ebebeb;
--color-secondary: #efefef;
--color-secondary-strong: #dfdfdf;
@@ -35,6 +35,26 @@
--ease-fluid-in: .6, .2, .7, .4;
--ease-out-back: 0.34, 1.56, 0.64, 1;
}
/*
Coming soon...
@media screen and (prefers-color-scheme: dark) {
:root {
--color-surface-background: #111111;
--color-on-surface-background: #f9f9f9;
--color-primary: #d9d9d9;
--color-primary-strong: #c0c0c0;
--color-on-primary: #111111;
--color-on-primary-weak: #2e2e2e;
--color-secondary: #2e2e2e;
--color-secondary-strong: #3e3e3e;
--color-on-secondary: #efefef;
--color-container: #0e0e0e;
--color-on-container: #f8f8f8;
--color-outline-very-intense: #5f5f5f;
--color-outline-intense: #3f3f3f;
--color-outline: #262626;
}
} */
@keyframes ring {
0% {
outline: 0px solid var(--ui-ring-color);
@@ -624,15 +644,36 @@ a.btn {
cursor: pointer;
}
.btn {
all: unset;
--ui-btn-bg: var(--color-surface-background);
--ui-btn-bg-active: var(--color-secondary);
--ui-btn-text: var(--color-on-surface-background);
--ui-btn-border-width: 1px;
--ui-btn-border-color: var(--color-outline);
--ui-btn-border-style: solid;
--ui-btn-height: calc(var(--ui-spacing)*10);
--ui-btn-padding-x: calc(var(--ui-spacing)*4);
--ui-btn-radius: calc(var(--ui-btn-height)/2);
display: flex;
align-items: center;
width: fit-content;
height: calc(var(--ui-spacing)*10);
background: var(--color-primary);
color: var(--color-on-primary);
padding-inline: calc(var(--ui-spacing)*4);
border-radius: calc(var(--ui-spacing)*5);
border-width: var(--ui-btn-border-width);
border-color: var(--ui-btn-border-color);
border-style: var(--ui-btn-border-style);
height: var(--ui-btn-height);
background: var(--ui-btn-bg);
color: var(--ui-btn-text);
padding-inline: var(--ui-btn-padding-x);
border-radius: var(--ui-btn-radius);
}
.btn:active {
background: var(--ui-btn-bg-active);
}
.btn.btn-primary {
--ui-btn-bg: var(--color-primary);
--ui-btn-bg-active: var(--color-primary-strong);
--ui-btn-text: var(--color-on-primary);
--ui-btn-border-width: 0;
}
.btn.btn-secondary {
background: var(--color-secondary);
@@ -646,7 +687,7 @@ a.btn {
}
.btn.btn-sm .material-symbols-outlined {
font-size: 20px;
font-variation-setting:
font-variation-settings:
'opsz' 20
}
.prose-blog-pretext {
@@ -734,7 +775,7 @@ a.btn {
.toc .toc-link-indent-4 {
margin-left: calc(var(--ui-spacing)*6);
}
.web-dismissable-banner {
.web-dismissible-banner {
position: sticky;
width: 100%;
text-align: center;
@@ -742,7 +783,7 @@ a.btn {
background: var(--color-primary);
color: var(--color-on-primary);
}
.web-dismissable-banner > .web-dismissable-banner-content {
.web-dismissible-banner > .web-dismissible-banner-content {
display: flex;
text-align: start;
align-items: center;
@@ -1,58 +0,0 @@
<template>
<div
v-if="visible && banner && banner.active"
class="web-dismissable-banner"
>
<div class="web-dismissable-banner-content">
<a :href="banner.link" target="_blank" rel="noopener">
{{ banner.message }}
</a>
<button class="btn btn-secondary btn-sm" @click="dismiss"><span class="material-symbols-outlined">close</span></button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
// 🍪 Cookies
const bannerDismissedCookie = useCookie('web_banner_dismissed', { maxAge: 60 * 60 * 24 * 30 }) // 30 days
const bannerLastIdCookie = useCookie('web_banner_last_id', { maxAge: 60 * 60 * 24 * 30 }) // 30 days
// 🔹 State
const banner = ref<any>(null)
const visible = ref(false)
onMounted(async () => {
try {
const data = await $fetch('https://files.thawia.ng/files/config/web/banner/tmp/index.json')
// If no data or inactive, bail
if (!data || !data.active) return
banner.value = data
// Check if the banner is new or dismissed
const currentId = data.id?.toString() || ''
const lastSeenId = bannerLastIdCookie.value?.toString() || ''
const dismissed = bannerDismissedCookie.value === currentId
// Show banner only if new or not dismissed yet
if (currentId && (currentId !== lastSeenId || !dismissed)) {
visible.value = true
}
// Update last seen id
bannerLastIdCookie.value = currentId
} catch (err) {
console.error('Banner fetch failed:', err)
}
})
function dismiss() {
if (banner.value?.id) {
bannerDismissedCookie.value = banner.value.id.toString()
}
visible.value = false
}
</script>
@@ -0,0 +1,70 @@
<template>
<div
v-if="visible && banner && banner.active"
class="web-dismissible-banner"
>
<div class="web-dismissible-banner-content">
<a :href="banner.link" target="_blank" rel="noopener">
{{ banner.message }}
</a>
<button class="btn btn-secondary btn-sm" @click="dismiss"><span class="material-symbols-outlined">close</span></button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const banner = ref<any>(null)
const visible = ref(false)
const STORAGE_KEY_DISMISSED = 'web_banner_dismissed'
const STORAGE_KEY_LAST_ID = 'web_banner_last_id'
function getStorageItem(key: string): string | null {
if (typeof window === 'undefined') return null
return localStorage.getItem(key)
}
function setStorageItem(key: string, value: string) {
if (typeof window === 'undefined') return
localStorage.setItem(key, value)
}
function removeStorageItem(key: string) {
if (typeof window === 'undefined') return
localStorage.removeItem(key)
}
onMounted(async () => {
try {
const data = await $fetch('https://files.thawia.ng/files/config/web/banner/tmp/index.json')
// If no data or inactive, bail
if (!data) return
banner.value = data
const currentId = data.id?.toString() || ''
const lastSeenId = getStorageItem(STORAGE_KEY_LAST_ID) || ''
const dismissedId = getStorageItem(STORAGE_KEY_DISMISSED)
// Show banner only if new or not dismissed yet
if (currentId && (currentId !== lastSeenId || dismissedId !== currentId)) {
visible.value = true
}
// Update last seen ID
setStorageItem(STORAGE_KEY_LAST_ID, currentId)
} catch (err) {
console.error('Banner fetch failed:', err)
}
})
function dismiss() {
if (banner.value?.id) {
setStorageItem(STORAGE_KEY_DISMISSED, banner.value.id.toString())
}
visible.value = false
}
</script>
+7 -1
View File
@@ -7,7 +7,7 @@ const currentYear = new Date().getFullYear();
<div class="article article-footer">
<section class="web-section">
<div class="web-footer-links-container-container">
<div class="web-footer-links-container">
<div class="web-footer-links-container" style="margin-right: 4rem;">
<h3 class="web-footer-link-title">Site</h3>
<ul class="web-footer-links">
<li class="web-footer-link"><NuxtLink href="/posts">Posts</NuxtLink></li>
@@ -18,6 +18,12 @@ const currentYear = new Date().getFullYear();
<li class="web-footer-link"><NuxtLink href="/collections">Collections</NuxtLink></li>
</ul>
</div>
<div class="web-footer-links-container">
<h3 class="web-footer-link-title">More</h3>
<ul class="web-footer-links">
<li class="web-footer-link"><NuxtLink href="/services">Services</NuxtLink></li>
</ul>
</div>
</div>
</section>
<section class="web-section">
+1 -1
View File
@@ -4,7 +4,7 @@
<template>
<div>
<WebDismissableGlobalBanner/>
<WebDismissibleGlobalBanner/>
<WebHeader/>
<slot/>
<WebFooter/>