Surface image stickers in chat picker
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
const CACHE_VERSION = "gashboard-pwa-v1";
|
||||
const CACHE_VERSION = "gashboard-pwa-v2";
|
||||
const APP_SHELL = ["/", "/manifest.webmanifest", "/icons/icon.svg", "/icons/maskable.svg"];
|
||||
const MINER_ASSETS = [
|
||||
"/miners/nerdqaxe.svg",
|
||||
@@ -7,9 +7,23 @@ const MINER_ASSETS = [
|
||||
"/miners/avalon-mini-3.svg",
|
||||
"/miners/boomer-heater.svg",
|
||||
];
|
||||
const STICKER_ASSETS = [
|
||||
"/stickers/anon-miner.svg",
|
||||
"/stickers/block-denied.svg",
|
||||
"/stickers/block-hopium.svg",
|
||||
"/stickers/boomer-unit.svg",
|
||||
"/stickers/chad-hash.svg",
|
||||
"/stickers/chart-crime.svg",
|
||||
"/stickers/fan-panic.svg",
|
||||
"/stickers/fiat-npc.svg",
|
||||
"/stickers/heat-death.svg",
|
||||
"/stickers/money-printer.svg",
|
||||
"/stickers/odds-wizard.svg",
|
||||
"/stickers/printer-loop.svg",
|
||||
];
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
event.waitUntil(caches.open(CACHE_VERSION).then((cache) => cache.addAll([...APP_SHELL, ...MINER_ASSETS])));
|
||||
event.waitUntil(caches.open(CACHE_VERSION).then((cache) => cache.addAll([...APP_SHELL, ...MINER_ASSETS, ...STICKER_ASSETS])));
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
@@ -35,7 +49,7 @@ self.addEventListener("fetch", (event) => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (url.pathname.startsWith("/assets/") || url.pathname.startsWith("/icons/")) {
|
||||
if (url.pathname.startsWith("/assets/") || url.pathname.startsWith("/icons/") || url.pathname.startsWith("/stickers/")) {
|
||||
event.respondWith(cacheFirst(req));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ let sub: { close: () => void } | null = null;
|
||||
|
||||
const ownPubkey = computed(() => chat.pubkeyFromNpub(auth.npub));
|
||||
const canSend = computed(() => auth.hasActiveSigner);
|
||||
const mediaStickers = computed(() => CHAT_STICKERS.filter((sticker) => sticker.image));
|
||||
const textStickers = computed(() => CHAT_STICKERS.filter((sticker) => !sticker.image));
|
||||
|
||||
onMounted(() => {
|
||||
if (auth.isLoggedIn) void start();
|
||||
@@ -191,17 +193,38 @@ async function scrollBottom(): Promise<void> {
|
||||
<button type="button" class="thin" aria-label="close stickers" @click="showStickers = false">×</button>
|
||||
</div>
|
||||
<div class="sticker-tray">
|
||||
<button
|
||||
v-for="sticker in CHAT_STICKERS"
|
||||
:key="sticker.label"
|
||||
type="button"
|
||||
:disabled="!canSend"
|
||||
@click="sendSticker(sticker)"
|
||||
>
|
||||
<img v-if="sticker.image" :src="sticker.image" alt="" />
|
||||
<span>{{ sticker.label }}</span>
|
||||
<small>{{ sticker.text }}</small>
|
||||
</button>
|
||||
<div class="sticker-section">
|
||||
<div class="section-title">image / gif stickers</div>
|
||||
<div class="sticker-grid media-grid">
|
||||
<button
|
||||
v-for="sticker in mediaStickers"
|
||||
:key="sticker.label"
|
||||
type="button"
|
||||
:disabled="!canSend"
|
||||
@click="sendSticker(sticker)"
|
||||
>
|
||||
<img :src="sticker.image || ''" alt="" />
|
||||
<span>{{ sticker.label }}</span>
|
||||
<small>{{ sticker.text }}</small>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sticker-section">
|
||||
<div class="section-title">text stickers</div>
|
||||
<div class="sticker-grid text-grid">
|
||||
<button
|
||||
v-for="sticker in textStickers"
|
||||
:key="sticker.label"
|
||||
type="button"
|
||||
:disabled="!canSend"
|
||||
@click="sendSticker(sticker)"
|
||||
>
|
||||
<span>{{ sticker.label }}</span>
|
||||
<small>{{ sticker.text }}</small>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
@@ -447,14 +470,31 @@ p {
|
||||
font-size: 14px;
|
||||
}
|
||||
.sticker-tray {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 6px;
|
||||
min-height: 0;
|
||||
overflow: auto;
|
||||
padding-right: 2px;
|
||||
}
|
||||
.sticker-tray button {
|
||||
.sticker-section + .sticker-section {
|
||||
margin-top: 14px;
|
||||
}
|
||||
.section-title {
|
||||
margin-bottom: 8px;
|
||||
color: var(--fg-2);
|
||||
font-size: 10px;
|
||||
letter-spacing: 0.14em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.sticker-grid {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
.media-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
.text-grid {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
.sticker-grid button {
|
||||
min-width: 0;
|
||||
min-height: 138px;
|
||||
display: flex;
|
||||
@@ -469,18 +509,22 @@ p {
|
||||
text-align: left;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.sticker-tray button img {
|
||||
.text-grid button {
|
||||
min-height: 74px;
|
||||
}
|
||||
.sticker-grid button img {
|
||||
width: 100%;
|
||||
aspect-ratio: 1 / 1;
|
||||
max-height: 118px;
|
||||
min-height: 120px;
|
||||
max-height: 156px;
|
||||
object-fit: contain;
|
||||
border: 1px solid var(--line);
|
||||
background: var(--bg-0);
|
||||
}
|
||||
.sticker-tray button span {
|
||||
.sticker-grid button span {
|
||||
color: var(--neon-cyan);
|
||||
}
|
||||
.sticker-tray button small {
|
||||
.sticker-grid button small {
|
||||
color: var(--fg-1);
|
||||
font-size: 10px;
|
||||
line-height: 1.25;
|
||||
@@ -555,6 +599,10 @@ textarea {
|
||||
max-height: calc(100% - 12px);
|
||||
}
|
||||
.sticker-tray {
|
||||
padding-right: 0;
|
||||
}
|
||||
.media-grid,
|
||||
.text-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user