Fishies 0.8.11

This commit is contained in:
CRTkafa 2026-10-30 08:23:23 +00:00
parent 9020cffee7
commit ed00d055ae
23 changed files with 108 additions and 52 deletions

View file

@ -1,7 +1,7 @@
'use client'
import { useCallback, useEffect, useLayoutEffect, useRef, useState, type ImgHTMLAttributes, type Ref } from 'react'
import { reveal } from './fx-image'
import { imageFallback, reveal } from './fx-image'
import './loader.css'
const useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect
@ -23,9 +23,16 @@ export default function FishiesImg({ ref, decoding, ...props }: ImgHTMLAttribute
mounted.current = true
reveal(img, first && img.complete)
const settle = () => reveal(img)
delete img.dataset.webpFallback
const failed = () => {
const png = imageFallback(img.currentSrc || img.src)
if (png && !img.dataset.webpFallback) { img.dataset.webpFallback = '1'; img.src = png; return }
reveal(img)
}
img.addEventListener('load', settle)
img.addEventListener('error', settle)
return () => { img.removeEventListener('load', settle); img.removeEventListener('error', settle) }
img.addEventListener('error', failed)
return () => { img.removeEventListener('load', settle); img.removeEventListener('error', failed) }
}, [props.src, props.srcSet])
return <img {...props} ref={setRef} decoding={decoding ?? 'async'} data-fx="wait" suppressHydrationWarning/>
}

View file

@ -1,5 +1,9 @@
export type FxState = 'wait' | 'fade' | 'ready' | 'error'
let alternative: (src: string) => string | null = () => null
export function configureImageFallback(find: (src: string) => string | null): void { alternative = find }
export const imageFallback = (src: string): string | null => alternative(src)
export function reveal(img: HTMLImageElement, instant?: boolean): void {
if (img.getAttribute('data-fx') !== 'wait' || !img.complete) return
const src = img.currentSrc || img.src

View file

@ -1,15 +1,15 @@
export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly sharpTo: number; readonly usedBy: readonly string[] }>> = {
"feed": {
"px": 56,
"sharpTo": 28,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Reef Journal"
]
},
"net": {
"px": 56,
"sharpTo": 28,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
@ -17,8 +17,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
]
},
"clean": {
"px": 56,
"sharpTo": 28,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
@ -26,8 +26,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
]
},
"decorate": {
"px": 56,
"sharpTo": 28,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Reef Journal"
@ -37,7 +37,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game"
"Game",
"Reef Journal"
]
},
"remedy": {
@ -68,8 +69,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
]
},
"explore": {
"px": 56,
"sharpTo": 28,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
@ -86,8 +87,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
]
},
"shop": {
"px": 56,
"sharpTo": 28,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
@ -112,8 +113,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
]
},
"inventory": {
"px": 56,
"sharpTo": 28,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
@ -147,16 +148,16 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
]
},
"pin": {
"px": 40,
"sharpTo": 20,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS"
]
},
"menu": {
"px": 52,
"sharpTo": 26,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
@ -164,8 +165,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
]
},
"bell": {
"px": 52,
"sharpTo": 26,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
@ -192,8 +193,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
]
},
"sound": {
"px": 52,
"sharpTo": 26,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
@ -202,8 +203,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
]
},
"mute": {
"px": 52,
"sharpTo": 26,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
@ -211,17 +212,18 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
]
},
"music": {
"px": 52,
"sharpTo": 26,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game"
]
},
"fullscreen": {
"px": 52,
"sharpTo": 26,
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game",
"Reef Journal",
"Video player"
]
},
@ -310,7 +312,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS"
"Keeper OS",
"Reef Journal"
]
},
"lock": {
@ -375,6 +378,7 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
"Reef Journal"
]
},
@ -424,6 +428,7 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS",
"Reef Journal"
]
},
@ -438,7 +443,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game"
"Game",
"Reef Journal"
]
},
"block": {
@ -498,7 +504,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game"
"Game",
"Reef Journal"
]
},
"thermometer": {
@ -520,7 +527,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game"
"Game",
"Keeper OS"
]
},
"gift": {
@ -551,15 +559,17 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
"sharpTo": 84,
"usedBy": [
"Game",
"Keeper OS"
"Keeper OS",
"Reef Journal"
]
},
"quest": {
"px": 168,
"sharpTo": 84,
"px": 320,
"sharpTo": 160,
"usedBy": [
"Game",
"Keeper OS"
"Keeper OS",
"Reef Journal"
]
},
"check": {
@ -620,7 +630,8 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
"px": 168,
"sharpTo": 84,
"usedBy": [
"Game"
"Game",
"Keeper OS"
]
},
"journal": {
@ -630,6 +641,14 @@ export const ICON_FACTS: Readonly<Record<string, { readonly px: number; readonly
"Game"
]
},
"research": {
"px": 320,
"sharpTo": 160,
"usedBy": [
"Game",
"Reef Journal"
]
},
"add": {
"px": 168,
"sharpTo": 84,

View file

@ -58,6 +58,7 @@ export const SYSTEM_ICONS = [
ui('keyboard', 'Keys', 'system', 'shortcuts and keys'), ui('external', 'Opens elsewhere', 'system', 'opens in a new tab'),
ui('journal', 'Reef Journal', 'places', 'the Reef Journal notebook'),
ui('research', 'Research', 'places', 'the Research app: studies, levers and the tree'),
ui('add', 'New', 'system', 'new, create'), ui('download', 'Download', 'system', 'download'), ui('mail', 'Mail', 'system', 'email, the newsletter'),
emote('hello', 'Hello', 'wave hello'), emote('heart', 'Love', 'send love'), emote('question', 'Question', 'wonder aloud'), emote('surprise', 'Surprise', 'be surprised'),
emote('food', 'Food', 'ask for food'), emote('sleep', 'Sleepy', 'feel sleepy'), emote('music', 'Music', 'enjoy the music'), emote('sparkle', 'Sparkle', 'something wonderful'),