Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6cfcf535e7 | |||
| 1f5c887c7f | |||
| 0de6f55378 |
+52
-11
@@ -9,9 +9,9 @@
|
|||||||
|
|
||||||
--color-surface-background: #f9f9f9;
|
--color-surface-background: #f9f9f9;
|
||||||
--color-on-surface-background: #111111;
|
--color-on-surface-background: #111111;
|
||||||
--color-primary: #2e2e2e;
|
--color-primary: #1a1a1a;
|
||||||
--color-primary-strong: #3e3e3e;
|
--color-primary-strong: #3e3e3e;
|
||||||
--color-on-primary: white;
|
--color-on-primary: #eeeeee;
|
||||||
--color-on-primary-weak: #ebebeb;
|
--color-on-primary-weak: #ebebeb;
|
||||||
--color-secondary: #efefef;
|
--color-secondary: #efefef;
|
||||||
--color-secondary-strong: #dfdfdf;
|
--color-secondary-strong: #dfdfdf;
|
||||||
@@ -35,6 +35,26 @@
|
|||||||
--ease-fluid-in: .6, .2, .7, .4;
|
--ease-fluid-in: .6, .2, .7, .4;
|
||||||
--ease-out-back: 0.34, 1.56, 0.64, 1;
|
--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 {
|
@keyframes ring {
|
||||||
0% {
|
0% {
|
||||||
outline: 0px solid var(--ui-ring-color);
|
outline: 0px solid var(--ui-ring-color);
|
||||||
@@ -624,15 +644,36 @@ a.btn {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.btn {
|
.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;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
height: calc(var(--ui-spacing)*10);
|
border-width: var(--ui-btn-border-width);
|
||||||
background: var(--color-primary);
|
border-color: var(--ui-btn-border-color);
|
||||||
color: var(--color-on-primary);
|
border-style: var(--ui-btn-border-style);
|
||||||
padding-inline: calc(var(--ui-spacing)*4);
|
height: var(--ui-btn-height);
|
||||||
border-radius: calc(var(--ui-spacing)*5);
|
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 {
|
.btn.btn-secondary {
|
||||||
background: var(--color-secondary);
|
background: var(--color-secondary);
|
||||||
@@ -646,7 +687,7 @@ a.btn {
|
|||||||
}
|
}
|
||||||
.btn.btn-sm .material-symbols-outlined {
|
.btn.btn-sm .material-symbols-outlined {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-variation-setting:
|
font-variation-settings:
|
||||||
'opsz' 20
|
'opsz' 20
|
||||||
}
|
}
|
||||||
.prose-blog-pretext {
|
.prose-blog-pretext {
|
||||||
@@ -734,7 +775,7 @@ a.btn {
|
|||||||
.toc .toc-link-indent-4 {
|
.toc .toc-link-indent-4 {
|
||||||
margin-left: calc(var(--ui-spacing)*6);
|
margin-left: calc(var(--ui-spacing)*6);
|
||||||
}
|
}
|
||||||
.web-dismissable-banner {
|
.web-dismissible-banner {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -742,7 +783,7 @@ a.btn {
|
|||||||
background: var(--color-primary);
|
background: var(--color-primary);
|
||||||
color: var(--color-on-primary);
|
color: var(--color-on-primary);
|
||||||
}
|
}
|
||||||
.web-dismissable-banner > .web-dismissable-banner-content {
|
.web-dismissible-banner > .web-dismissible-banner-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
text-align: start;
|
text-align: start;
|
||||||
align-items: center;
|
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,7 +7,7 @@ const currentYear = new Date().getFullYear();
|
|||||||
<div class="article article-footer">
|
<div class="article article-footer">
|
||||||
<section class="web-section">
|
<section class="web-section">
|
||||||
<div class="web-footer-links-container-container">
|
<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>
|
<h3 class="web-footer-link-title">Site</h3>
|
||||||
<ul class="web-footer-links">
|
<ul class="web-footer-links">
|
||||||
<li class="web-footer-link"><NuxtLink href="/posts">Posts</NuxtLink></li>
|
<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>
|
<li class="web-footer-link"><NuxtLink href="/collections">Collections</NuxtLink></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="web-section">
|
<section class="web-section">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<WebDismissableGlobalBanner/>
|
<WebDismissibleGlobalBanner/>
|
||||||
<WebHeader/>
|
<WebHeader/>
|
||||||
<slot/>
|
<slot/>
|
||||||
<WebFooter/>
|
<WebFooter/>
|
||||||
|
|||||||
Reference in New Issue
Block a user