feat:加上 Vue 学习站与可嵌入机芯

站点按 bloub 三栏做自定义、动画时间线和设置,支持序列导出。
形体只留常见几种并配中文名;动画页右栏拉满时间线旁空位,滚动条隐藏。
机芯补 GROK.create / <grok-bot>,以及暂停冻结。
This commit is contained in:
Edom
2026-08-19 01:29:13 +08:00
parent 891f6ef7e7
commit 1ba126c92b
55 changed files with 8998 additions and 224 deletions
+97
View File
@@ -0,0 +1,97 @@
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { t } from '@/i18n'
import { mountReplica, type ReplicaMount } from '@/replica/host'
const props = withDefaults(
defineProps<{
size?: number
shape?: string
color?: string
state?: string
follow?: boolean
paper?: string
}>(),
{
size: 440,
shape: 'blob',
color: 'black',
state: 'idle',
follow: false,
paper: '#f9f9f9'
}
)
const emit = defineEmits<{ ready: [ok: boolean] }>()
const svg = ref<SVGSVGElement | null>(null)
const live = ref(false)
const tried = ref(false)
let replica: ReplicaMount | null = null
let alive = true
function input() {
return {
state: props.state,
shape: props.shape,
color: props.color,
follow: props.follow,
paper: props.paper,
size: props.size
}
}
async function attach() {
const node = svg.value
if (!node) return
const mount = await mountReplica(node, input(), true)
if (!alive) {
mount?.destroy()
return
}
replica = mount
live.value = !!replica
tried.value = true
replica?.apply(input())
emit('ready', live.value)
}
onMounted(() => {
void attach()
})
onBeforeUnmount(() => {
alive = false
replica?.destroy()
replica = null
})
watch(
() => [props.state, props.shape, props.color, props.follow, props.paper, props.size],
() => replica?.apply(input())
)
defineExpose({
spin: () => replica?.spin(),
orbitGaze: (ms?: number) => replica?.orbitGaze(ms),
svg: () => svg.value
})
</script>
<template>
<div class="relative inline-block aspect-square max-w-full" :style="{ width: `${props.size}px` }">
<svg
ref="svg"
class="absolute inset-0 h-full w-full overflow-visible"
:width="props.size"
:height="props.size"
role="img"
:aria-label="t('app.botAria')"
/>
<p
v-if="tried && !live"
class="absolute inset-6 flex items-center justify-center text-center text-xs text-[var(--muted)]"
>
{{ t('app.missingGeo') }}
</p>
</div>
</template>