This commit is contained in:
2026-05-23 17:17:56 -07:00
commit 448f2e33ef
135 changed files with 11817 additions and 0 deletions
@@ -0,0 +1,199 @@
import { type MouseEventHandler, forwardRef, useEffect, useMemo, useState } from 'react'
import type { BackendArt } from '../../functions/BackendTypes'
import { WEB_BASE } from '../../functions/Backend'
import { wtEvent } from '../../functions/Watchtower'
import { toast } from '../../functions/Context'
import './styles/ModalEmbed.css'
import VectorBackgroundEmbed from '../../vectors/background-embed.svg'
import HeaderMessage from './HeaderMessage'
import InputButtonRow from '../inputs/ButtonRow'
import InputButton from '../inputs/Button'
import InputDescription from '../inputs/Description'
import InputLabel from '../inputs/Label'
interface PropsForModalEmbed {
item: BackendArt
onClose: MouseEventHandler<HTMLButtonElement>
}
export default forwardRef<HTMLDialogElement, PropsForModalEmbed>(function ModalEmbed(
{ item, onClose }: PropsForModalEmbed,
ref,
) {
// Keep User Preferences
const KEY_QUALITY = 'preference_embed_quality'
const KEY_SCALE = 'preference_embed_scale'
const [preferQuality, setQuality] = useState<'standard' | 'transparent'>(
(() => {
let raw = localStorage.getItem(KEY_QUALITY) ?? 'standard'
if (raw !== 'standard' && raw !== 'transparent') {
return 'standard'
} else {
return raw
}
})(),
)
const [preferScale, setScale] = useState<number>(
(() => {
let raw = localStorage.getItem(KEY_SCALE) ?? String('1')
let val = parseFloat(raw)
if (isNaN(val) || val < 0 || val > 1) return 1
return val
})(),
)
useEffect(() => localStorage.setItem(KEY_QUALITY, String(preferQuality)), [preferQuality])
useEffect(() => localStorage.setItem(KEY_SCALE, String(preferScale)), [preferScale])
// Calculate Embed Values
const embedScale = useMemo(() => {
const maxDim = Math.max(item.width, item.height)
const baseScale = maxDim > 640 ? 640 / maxDim : 1
return baseScale * preferScale
}, [item.width, item.height, preferScale])
const embedHeight = useMemo(() => (item.height * embedScale) | 0, [embedScale])
const embedWidth = useMemo(() => (item.width * embedScale) | 0, [embedScale])
// const embedQuality = useMemo(() => {
// if (preferQuality === 'standard.avif') return 'standard'
// return 'transparent'
// }, [preferQuality])
const embedHTML = useMemo(
() =>
`<iframe src="${WEB_BASE}/embed.html?id=${item.id}&quality=${preferQuality}" width="${embedWidth}" height="${embedHeight}" style="border:none; background: transparent" allowtransparency="true"></iframe>`,
[preferQuality, embedScale],
)
function onCopy() {
navigator.clipboard.writeText(embedHTML)
toast('action-copy', 'Copied Code to Clipboard!')
wtEvent('action_animation_embed_copy', {
id: item.id,
height: embedHeight,
width: embedWidth,
scale: (embedScale * 100) | 0,
quality: preferQuality,
})
}
return (
<dialog ref={ref} className="modal-embed animation-fall-in animation-caution">
<HeaderMessage label="MENU: Embed Generator" />
<div className="wrapper">
{/* Left-Pane */}
<div className="preview">
<img className="background animation-fade-in" src={VectorBackgroundEmbed} />
<iframe
className="animation-fall-in"
style={{ border: 'none', background: 'transparent' }}
src={`${WEB_BASE}/embed.html?id=${item.id}&quality=${preferQuality}`}
width={embedWidth}
height={embedHeight}
allowTransparency
/>
</div>
{/* Right-Pane */}
<div className="toggles">
<InputLabel for="" label="Quality" />
<InputDescription>
We recommend using Standard quality, if you require transparency use Alpha quality.
</InputDescription>
<InputDescription>
Using more than three Alpha embeds may slow down your site, and up to twelve can be displayed at
any given time.
</InputDescription>
<InputButtonRow split={false}>
<InputButton
id="quality-alpha"
label="Alpha"
onClick={() => setQuality('transparent')}
selected={preferQuality === 'transparent'}
disabled={false}
rainbow={false}
/>
<InputButton
id="quality-standard"
label="Standard"
onClick={() => setQuality('standard')}
selected={preferQuality === 'standard'}
disabled={false}
rainbow={false}
/>
</InputButtonRow>
<InputLabel for="" label="Scale" />
<InputDescription>
Sizing is as follows: Small @ 320px; Medium @ 480px; Large @ 640px.
</InputDescription>
<InputDescription>If an image is too small, it wont get any larger.</InputDescription>
<InputButtonRow split={false}>
<InputButton
id="size-small"
label="Small"
selected={preferScale < 0.6}
onClick={() => setScale(0.5)}
disabled={false}
rainbow={false}
/>
<InputButton
id="size-medium"
label="Medium"
selected={preferScale > 0.6 && preferScale < 0.9}
onClick={() => setScale(0.75)}
disabled={false}
rainbow={false}
/>
<InputButton
id="size-large"
label="Large"
selected={preferScale > 0.9}
onClick={() => setScale(1)}
disabled={false}
rainbow={false}
/>
</InputButtonRow>
<InputLabel for="" label="Code" />
<InputDescription>
Use this code snippet to display this {item.sticker ? 'sticker' : 'animation'} on your website.
</InputDescription>
<InputDescription>Clicking on the embed will direct users to gifuu in a new tab.</InputDescription>
<textarea
id="input-url"
className="input-url"
value={embedHTML}
onKeyDown={(e) => e.preventDefault()}
/>
<InputLabel for="" label="" /* lazy divider */ />
<InputButtonRow split={true}>
<InputButton
id="action-copy"
label="Copy HTML"
onClick={onCopy}
selected={false}
disabled={false}
rainbow={false}
/>
<InputButton
id="action-exit"
label="Exit"
onClick={onClose}
selected={false}
disabled={false}
rainbow={false}
/>
</InputButtonRow>
</div>
</div>
</dialog>
)
})