931 lines
25 KiB
Vue
931 lines
25 KiB
Vue
<script setup lang="ts">
|
|
import { computed, nextTick, ref, watch } from 'vue'
|
|
import type { Component } from 'vue'
|
|
import {
|
|
PhCode,
|
|
PhCursorClick,
|
|
PhExport,
|
|
PhFilmStrip,
|
|
PhFrameCorners,
|
|
PhImageSquare,
|
|
PhListBullets,
|
|
PhMusicNote,
|
|
PhPencilSimpleLine,
|
|
PhQuestion,
|
|
PhSlidersHorizontal,
|
|
PhSparkle,
|
|
} from '@phosphor-icons/vue'
|
|
import { Modal } from '@/components/ui'
|
|
import { t } from '@/i18n'
|
|
import { hasDesktopRender } from '@/lib/desktopRenderExport'
|
|
|
|
const props = defineProps<{ modelValue: boolean }>()
|
|
const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>()
|
|
|
|
type ChapterId =
|
|
| 'getting-started'
|
|
| 'stage'
|
|
| 'assets'
|
|
| 'layers-timeline'
|
|
| 'clips'
|
|
| 'buttons'
|
|
| 'scenes'
|
|
| 'audio'
|
|
| 'markers'
|
|
| 'scripts-actions'
|
|
| 'script-language'
|
|
| 'export'
|
|
| 'shortcuts'
|
|
|
|
interface HelpListItem {
|
|
bodyKey: string
|
|
icon?: Component
|
|
labelKey?: string
|
|
}
|
|
|
|
interface HelpTableRow {
|
|
effectKey: string
|
|
syntaxKey: string
|
|
}
|
|
|
|
type HelpBlock =
|
|
| { kind: 'paragraph'; bodyKey: string; titleKey?: string }
|
|
| { items: HelpListItem[]; kind: 'list'; titleKey?: string }
|
|
| { items: string[]; kind: 'steps'; titleKey: string }
|
|
| { kind: 'table'; rows: HelpTableRow[]; titleKey: string }
|
|
| { bodyKey: string; kind: 'code'; titleKey: string }
|
|
| { kind: 'shortcuts' }
|
|
|
|
interface Chapter {
|
|
blocks: HelpBlock[]
|
|
icon: Component
|
|
id: ChapterId
|
|
introKey: string
|
|
titleKey: string
|
|
}
|
|
|
|
const isDesktop = !!window.ruwioDesktop
|
|
const hasDesktopMp4 = hasDesktopRender()
|
|
|
|
const CHAPTERS: Chapter[] = [
|
|
{
|
|
id: 'getting-started',
|
|
titleKey: 'help.chapters.gettingStarted',
|
|
icon: PhSparkle,
|
|
introKey: 'help.content.gettingStarted.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.gettingStarted.modelTitle',
|
|
bodyKey: 'help.content.gettingStarted.modelBody',
|
|
},
|
|
{
|
|
kind: 'list',
|
|
titleKey: 'help.content.gettingStarted.whereTitle',
|
|
items: [
|
|
{
|
|
icon: PhQuestion,
|
|
labelKey: 'help.content.gettingStarted.where.topBar.label',
|
|
bodyKey: 'help.content.gettingStarted.where.topBar.body',
|
|
},
|
|
{
|
|
icon: PhImageSquare,
|
|
labelKey: 'help.content.gettingStarted.where.assets.label',
|
|
bodyKey: 'help.content.gettingStarted.where.assets.body',
|
|
},
|
|
{
|
|
icon: PhFrameCorners,
|
|
labelKey: 'help.content.gettingStarted.where.stage.label',
|
|
bodyKey: 'help.content.gettingStarted.where.stage.body',
|
|
},
|
|
{
|
|
icon: PhSlidersHorizontal,
|
|
labelKey: 'help.content.gettingStarted.where.properties.label',
|
|
bodyKey: 'help.content.gettingStarted.where.properties.body',
|
|
},
|
|
{
|
|
icon: PhFilmStrip,
|
|
labelKey: 'help.content.gettingStarted.where.timeline.label',
|
|
bodyKey: 'help.content.gettingStarted.where.timeline.body',
|
|
},
|
|
{
|
|
icon: PhListBullets,
|
|
labelKey: 'help.content.gettingStarted.where.scenes.label',
|
|
bodyKey: 'help.content.gettingStarted.where.scenes.body',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
kind: 'steps',
|
|
titleKey: 'help.content.gettingStarted.quickStartTitle',
|
|
items: [
|
|
'help.content.gettingStarted.quickStart.step1',
|
|
'help.content.gettingStarted.quickStart.step2',
|
|
'help.content.gettingStarted.quickStart.step3',
|
|
'help.content.gettingStarted.quickStart.step4',
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'stage',
|
|
titleKey: 'help.chapters.stage',
|
|
icon: PhFrameCorners,
|
|
introKey: 'help.content.stage.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'list',
|
|
titleKey: 'help.content.stage.viewTitle',
|
|
items: [
|
|
{ bodyKey: 'help.content.stage.view.zoom' },
|
|
{ bodyKey: 'help.content.stage.view.pan' },
|
|
{ bodyKey: 'help.content.stage.view.fit' },
|
|
],
|
|
},
|
|
{
|
|
kind: 'list',
|
|
titleKey: 'help.content.stage.selectionTitle',
|
|
items: [
|
|
{ bodyKey: 'help.content.stage.selection.pick' },
|
|
{ bodyKey: 'help.content.stage.selection.clear' },
|
|
{ bodyKey: 'help.content.stage.selection.handles' },
|
|
],
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.stage.lockingTitle',
|
|
bodyKey: 'help.content.stage.lockingBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.stage.drawingTitle',
|
|
bodyKey: 'help.content.stage.drawingBody',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'assets',
|
|
titleKey: 'help.chapters.assets',
|
|
icon: PhImageSquare,
|
|
introKey: 'help.content.assets.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'list',
|
|
titleKey: 'help.content.assets.sectionsTitle',
|
|
items: [
|
|
{ bodyKey: 'help.content.assets.sections.shapes', icon: PhSparkle },
|
|
{ bodyKey: 'help.content.assets.sections.images', icon: PhImageSquare },
|
|
{ bodyKey: 'help.content.assets.sections.clips', icon: PhFilmStrip },
|
|
{ bodyKey: 'help.content.assets.sections.buttons', icon: PhCursorClick },
|
|
{ bodyKey: 'help.content.assets.sections.audio', icon: PhMusicNote },
|
|
],
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.assets.thumbsTitle',
|
|
bodyKey: 'help.content.assets.thumbsBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.assets.foldTitle',
|
|
bodyKey: 'help.content.assets.foldBody',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'layers-timeline',
|
|
titleKey: 'help.chapters.layersTimeline',
|
|
icon: PhFilmStrip,
|
|
introKey: 'help.content.layersTimeline.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'list',
|
|
titleKey: 'help.content.layersTimeline.keyframesTitle',
|
|
items: [
|
|
{ bodyKey: 'help.content.layersTimeline.keyframes.add' },
|
|
{ bodyKey: 'help.content.layersTimeline.keyframes.drag' },
|
|
{ bodyKey: 'help.content.layersTimeline.keyframes.jump' },
|
|
{ bodyKey: 'help.content.layersTimeline.keyframes.menu' },
|
|
],
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.layersTimeline.holdsTitle',
|
|
bodyKey: 'help.content.layersTimeline.holdsBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.layersTimeline.separateTitle',
|
|
bodyKey: 'help.content.layersTimeline.separateBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.layersTimeline.groupsTitle',
|
|
bodyKey: 'help.content.layersTimeline.groupsBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.layersTimeline.snappingTitle',
|
|
bodyKey: 'help.content.layersTimeline.snappingBody',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'clips',
|
|
titleKey: 'help.chapters.clips',
|
|
icon: PhFilmStrip,
|
|
introKey: 'help.content.clips.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'steps',
|
|
titleKey: 'help.content.clips.createTitle',
|
|
items: [
|
|
'help.content.clips.create.step1',
|
|
'help.content.clips.create.step2',
|
|
'help.content.clips.create.step3',
|
|
],
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.clips.editTitle',
|
|
bodyKey: 'help.content.clips.editBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.clips.trimTitle',
|
|
bodyKey: 'help.content.clips.trimBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.clips.transformTitle',
|
|
bodyKey: 'help.content.clips.transformBody',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'buttons',
|
|
titleKey: 'help.chapters.buttons',
|
|
icon: PhCursorClick,
|
|
introKey: 'help.content.buttons.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.buttons.editingTitle',
|
|
bodyKey: 'help.content.buttons.editingBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.buttons.stateKeyframesTitle',
|
|
bodyKey: 'help.content.buttons.stateKeyframesBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.buttons.stillFramesTitle',
|
|
bodyKey: 'help.content.buttons.stillFramesBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.buttons.hitShapesTitle',
|
|
bodyKey: 'help.content.buttons.hitShapesBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.buttons.actionsTitle',
|
|
bodyKey: 'help.content.buttons.actionsBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.buttons.disabledTitle',
|
|
bodyKey: 'help.content.buttons.disabledBody',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'scenes',
|
|
titleKey: 'help.chapters.scenes',
|
|
icon: PhListBullets,
|
|
introKey: 'help.content.scenes.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.scenes.drawerTitle',
|
|
bodyKey: 'help.content.scenes.drawerBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.scenes.switchingTitle',
|
|
bodyKey: 'help.content.scenes.switchingBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.scenes.referencesTitle',
|
|
bodyKey: 'help.content.scenes.referencesBody',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'audio',
|
|
titleKey: 'help.chapters.audio',
|
|
icon: PhMusicNote,
|
|
introKey: 'help.content.audio.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'steps',
|
|
titleKey: 'help.content.audio.addTitle',
|
|
items: [
|
|
'help.content.audio.add.step1',
|
|
'help.content.audio.add.step2',
|
|
'help.content.audio.add.step3',
|
|
],
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.audio.tracksTitle',
|
|
bodyKey: 'help.content.audio.tracksBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.audio.movingTitle',
|
|
bodyKey: 'help.content.audio.movingBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.audio.waveformsTitle',
|
|
bodyKey: 'help.content.audio.waveformsBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.audio.urlsTitle',
|
|
bodyKey: 'help.content.audio.urlsBody',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'markers',
|
|
titleKey: 'help.chapters.markers',
|
|
icon: PhPencilSimpleLine,
|
|
introKey: 'help.content.markers.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'list',
|
|
titleKey: 'help.content.markers.editingTitle',
|
|
items: [
|
|
{ bodyKey: 'help.content.markers.editing.add' },
|
|
{ bodyKey: 'help.content.markers.editing.drag' },
|
|
{ bodyKey: 'help.content.markers.editing.rename' },
|
|
{ bodyKey: 'help.content.markers.editing.delete' },
|
|
{ bodyKey: 'help.content.markers.editing.clear' },
|
|
],
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.markers.sceneTitle',
|
|
bodyKey: 'help.content.markers.sceneBody',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'scripts-actions',
|
|
titleKey: 'help.chapters.scriptsActions',
|
|
icon: PhCode,
|
|
introKey: 'help.content.scriptsActions.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'steps',
|
|
titleKey: 'help.content.scriptsActions.addTitle',
|
|
items: [
|
|
'help.content.scriptsActions.add.step1',
|
|
'help.content.scriptsActions.add.step2',
|
|
'help.content.scriptsActions.add.step3',
|
|
],
|
|
},
|
|
{
|
|
kind: 'list',
|
|
titleKey: 'help.content.scriptsActions.firingTitle',
|
|
items: [
|
|
{ bodyKey: 'help.content.scriptsActions.firing.forward' },
|
|
{ bodyKey: 'help.content.scriptsActions.firing.exact' },
|
|
{ bodyKey: 'help.content.scriptsActions.firing.order' },
|
|
{ bodyKey: 'help.content.scriptsActions.firing.replay' },
|
|
],
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.scriptsActions.menuTitle',
|
|
bodyKey: 'help.content.scriptsActions.menuBody',
|
|
},
|
|
{
|
|
kind: 'list',
|
|
titleKey: 'help.content.scriptsActions.typesTitle',
|
|
items: [
|
|
{ bodyKey: 'help.content.scriptsActions.types.transport' },
|
|
{ bodyKey: 'help.content.scriptsActions.types.jump' },
|
|
{ bodyKey: 'help.content.scriptsActions.types.scene' },
|
|
{ bodyKey: 'help.content.scriptsActions.types.button' },
|
|
{ bodyKey: 'help.content.scriptsActions.types.script' },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'script-language',
|
|
titleKey: 'help.chapters.scriptLanguage',
|
|
icon: PhCode,
|
|
introKey: 'help.content.scriptLanguage.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'list',
|
|
titleKey: 'help.content.scriptLanguage.syntaxTitle',
|
|
items: [
|
|
{ bodyKey: 'help.content.scriptLanguage.syntax.onePerLine' },
|
|
{ bodyKey: 'help.content.scriptLanguage.syntax.comments' },
|
|
{ bodyKey: 'help.content.scriptLanguage.syntax.tokens' },
|
|
{ bodyKey: 'help.content.scriptLanguage.syntax.case' },
|
|
],
|
|
},
|
|
{
|
|
kind: 'table',
|
|
titleKey: 'help.content.scriptLanguage.commandsTitle',
|
|
rows: [
|
|
{
|
|
syntaxKey: 'help.content.scriptLanguage.commands.play.syntax',
|
|
effectKey: 'help.content.scriptLanguage.commands.play.effect',
|
|
},
|
|
{
|
|
syntaxKey: 'help.content.scriptLanguage.commands.pause.syntax',
|
|
effectKey: 'help.content.scriptLanguage.commands.pause.effect',
|
|
},
|
|
{
|
|
syntaxKey: 'help.content.scriptLanguage.commands.rewind.syntax',
|
|
effectKey: 'help.content.scriptLanguage.commands.rewind.effect',
|
|
},
|
|
{
|
|
syntaxKey: 'help.content.scriptLanguage.commands.jumpSeconds.syntax',
|
|
effectKey: 'help.content.scriptLanguage.commands.jumpSeconds.effect',
|
|
},
|
|
{
|
|
syntaxKey: 'help.content.scriptLanguage.commands.jumpFrame.syntax',
|
|
effectKey: 'help.content.scriptLanguage.commands.jumpFrame.effect',
|
|
},
|
|
{
|
|
syntaxKey: 'help.content.scriptLanguage.commands.jumpMarker.syntax',
|
|
effectKey: 'help.content.scriptLanguage.commands.jumpMarker.effect',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
kind: 'code',
|
|
titleKey: 'help.content.scriptLanguage.exampleTitle',
|
|
bodyKey: 'help.content.scriptLanguage.exampleBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.scriptLanguage.errorsTitle',
|
|
bodyKey: 'help.content.scriptLanguage.errorsBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.scriptLanguage.notInDslTitle',
|
|
bodyKey: 'help.content.scriptLanguage.notInDslBody',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'export',
|
|
titleKey: 'help.chapters.export',
|
|
icon: PhExport,
|
|
introKey: 'help.content.export.intro',
|
|
blocks: [
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.export.editorPreviewTitle',
|
|
bodyKey: 'help.content.export.editorPreviewBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.export.fullscreenPreviewTitle',
|
|
bodyKey: 'help.content.export.fullscreenPreviewBody',
|
|
},
|
|
{
|
|
kind: 'list',
|
|
titleKey: 'help.content.export.formatsTitle',
|
|
items: [
|
|
{ bodyKey: 'help.content.export.formats.runtime' },
|
|
{ bodyKey: 'help.content.export.formats.scene' },
|
|
{ bodyKey: 'help.content.export.formats.html' },
|
|
{
|
|
bodyKey: hasDesktopMp4
|
|
? 'help.content.export.formats.mp4Desktop'
|
|
: 'help.content.export.formats.mp4',
|
|
},
|
|
{
|
|
bodyKey: isDesktop
|
|
? 'help.content.export.formats.webmDesktop'
|
|
: 'help.content.export.formats.webm',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.export.skipHiddenTitle',
|
|
bodyKey: 'help.content.export.skipHiddenBody',
|
|
},
|
|
{
|
|
kind: 'paragraph',
|
|
titleKey: 'help.content.export.assetsTitle',
|
|
bodyKey: 'help.content.export.assetsBody',
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'shortcuts',
|
|
titleKey: 'help.chapters.shortcuts',
|
|
icon: PhQuestion,
|
|
introKey: 'help.content.shortcuts.intro',
|
|
blocks: [{ kind: 'shortcuts' }],
|
|
},
|
|
]
|
|
|
|
const activeChapter = ref<ChapterId>('getting-started')
|
|
const contentRef = ref<HTMLElement | null>(null)
|
|
|
|
const activeChapterDef = computed<Chapter>(
|
|
() => CHAPTERS.find((chapter) => chapter.id === activeChapter.value) ?? CHAPTERS[0],
|
|
)
|
|
|
|
watch(
|
|
() => props.modelValue,
|
|
async (open) => {
|
|
if (!open) return
|
|
activeChapter.value = 'getting-started'
|
|
await nextTick()
|
|
if (contentRef.value) contentRef.value.scrollTop = 0
|
|
},
|
|
)
|
|
|
|
function selectChapter(id: ChapterId) {
|
|
activeChapter.value = id
|
|
if (contentRef.value) contentRef.value.scrollTop = 0
|
|
}
|
|
|
|
const APP_SHORTCUTS = [
|
|
{ labelKey: 'help.shortcut.playPause', keys: 'Space' },
|
|
{ labelKey: 'help.shortcut.fullscreen', keys: 'Shift+Space' },
|
|
{ labelKey: 'help.shortcut.undo', keys: 'Ctrl/Cmd+Z' },
|
|
{ labelKey: 'help.shortcut.redo', keys: 'Ctrl/Cmd+Shift+Z' },
|
|
{ labelKey: 'help.shortcut.save', keys: 'Ctrl/Cmd+S' },
|
|
{ labelKey: 'help.shortcut.inPoint', keys: 'I' },
|
|
{ labelKey: 'help.shortcut.outPoint', keys: 'O' },
|
|
{ labelKey: 'help.shortcut.rewind', keys: 'R' },
|
|
{ labelKey: 'help.shortcut.addMarker', keys: 'M' },
|
|
{ labelKey: 'help.shortcut.deleteSelected', keys: 'Backspace / Delete' },
|
|
{ labelKey: 'help.shortcut.clearSelection', keys: 'Escape' },
|
|
{ labelKey: 'help.shortcut.panCanvas', keys: 'Middle-click / Ctrl+drag' },
|
|
{ labelKey: 'help.shortcut.zoomCanvas', keys: 'Ctrl/Cmd+wheel' },
|
|
{ labelKey: 'help.shortcut.pasteImage', keys: 'Ctrl/Cmd+V' },
|
|
{ labelKey: 'help.shortcut.tests', keys: 'Ctrl+Shift+Alt+T' },
|
|
]
|
|
</script>
|
|
|
|
<template>
|
|
<Modal
|
|
:model-value="modelValue"
|
|
size="xl"
|
|
:title="t('help.title')"
|
|
:dialog-style="{
|
|
width: 'min(1100px, calc(100% - 32px))',
|
|
height: 'min(760px, calc(100vh - 48px))',
|
|
}"
|
|
:body-style="{
|
|
display: 'flex',
|
|
overflow: 'hidden',
|
|
minHeight: 0,
|
|
}"
|
|
@update:model-value="emit('update:modelValue', $event)"
|
|
>
|
|
<div class="help">
|
|
<aside class="toc" :aria-label="t('help.tocLabel')">
|
|
<button
|
|
v-for="chapter in CHAPTERS"
|
|
:key="chapter.id"
|
|
class="toc-item"
|
|
:class="{ active: activeChapter === chapter.id }"
|
|
@click="selectChapter(chapter.id)"
|
|
>
|
|
<component :is="chapter.icon" :size="15" class="toc-icon" />
|
|
<span>{{ t(chapter.titleKey) }}</span>
|
|
</button>
|
|
</aside>
|
|
|
|
<div ref="contentRef" class="content">
|
|
<section class="chapter">
|
|
<h3 class="chapter-title">{{ t(activeChapterDef.titleKey) }}</h3>
|
|
|
|
<p class="chapter-intro" v-html="t(activeChapterDef.introKey)" />
|
|
|
|
<template v-for="block in activeChapterDef.blocks" :key="JSON.stringify(block)">
|
|
<div v-if="block.kind === 'paragraph'" class="chapter-block">
|
|
<h4 v-if="block.titleKey">{{ t(block.titleKey) }}</h4>
|
|
<p v-html="t(block.bodyKey)" />
|
|
</div>
|
|
|
|
<div v-else-if="block.kind === 'list'" class="chapter-block">
|
|
<h4 v-if="block.titleKey">{{ t(block.titleKey) }}</h4>
|
|
<ul
|
|
class="bullets"
|
|
:class="block.items.some((i) => i.icon) ? 'bullets-icon' : 'bullets-disc'"
|
|
>
|
|
<li v-for="item in block.items" :key="item.bodyKey" class="bullet-item">
|
|
<span v-if="item.icon" class="bullet-icon">
|
|
<component :is="item.icon" :size="14" />
|
|
</span>
|
|
<div class="bullet-copy">
|
|
<strong v-if="item.labelKey">{{ t(item.labelKey) }}:</strong>
|
|
<span v-html="t(item.bodyKey)" />
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div v-else-if="block.kind === 'steps'" class="chapter-block">
|
|
<h4>{{ t(block.titleKey) }}</h4>
|
|
<ol class="bullets bullets-steps">
|
|
<li v-for="item in block.items" :key="item" v-html="t(item)" />
|
|
</ol>
|
|
</div>
|
|
|
|
<div v-else-if="block.kind === 'table'" class="chapter-block">
|
|
<h4>{{ t(block.titleKey) }}</h4>
|
|
<table class="cmd-table">
|
|
<thead>
|
|
<tr>
|
|
<th>{{ t('help.table.syntax') }}</th>
|
|
<th>{{ t('help.table.effect') }}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr v-for="row in block.rows" :key="row.syntaxKey">
|
|
<td v-html="t(row.syntaxKey)" />
|
|
<td v-html="t(row.effectKey)" />
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div v-else-if="block.kind === 'code'" class="chapter-block">
|
|
<h4>{{ t(block.titleKey) }}</h4>
|
|
<pre class="code">{{ t(block.bodyKey) }}</pre>
|
|
</div>
|
|
|
|
<div v-else-if="block.kind === 'shortcuts'" class="chapter-block">
|
|
<ul class="shortcuts">
|
|
<li v-for="shortcut in APP_SHORTCUTS" :key="shortcut.keys + shortcut.labelKey">
|
|
<span class="shortcut-label">{{ t(shortcut.labelKey) }}</span>
|
|
<kbd>{{ shortcut.keys }}</kbd>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</template>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.help {
|
|
display: flex;
|
|
flex: 1 1 auto;
|
|
min-height: 0;
|
|
}
|
|
|
|
.toc {
|
|
flex: 0 0 220px;
|
|
border-right: 1px solid var(--border);
|
|
padding: 10px 8px;
|
|
overflow-y: auto;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
background: var(--panel-alt);
|
|
min-height: 0;
|
|
}
|
|
|
|
.toc-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
text-align: left;
|
|
padding: 8px 10px;
|
|
font-size: 12px;
|
|
color: var(--text-dim);
|
|
background: transparent;
|
|
border: 1px solid transparent;
|
|
border-radius: var(--radius-sm);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.toc-icon {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.toc-item:hover:not(.active) {
|
|
background: var(--panel-hover);
|
|
color: var(--text);
|
|
}
|
|
|
|
.toc-item.active {
|
|
background: var(--accent);
|
|
color: #fff;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.content {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 18px 22px 22px;
|
|
min-width: 0;
|
|
min-height: 0;
|
|
}
|
|
|
|
.chapter {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
}
|
|
|
|
.chapter-title {
|
|
margin: 0;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.chapter-intro {
|
|
margin: 0;
|
|
font-size: 13px;
|
|
line-height: 1.6;
|
|
color: var(--text);
|
|
}
|
|
|
|
.chapter-block {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
|
|
.chapter h4 {
|
|
margin: 0;
|
|
font-size: 12px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
color: var(--text-dim);
|
|
}
|
|
|
|
.chapter p {
|
|
margin: 0;
|
|
font-size: 13px;
|
|
line-height: 1.55;
|
|
color: var(--text);
|
|
}
|
|
|
|
.bullets {
|
|
margin: 0;
|
|
font-size: 13px;
|
|
line-height: 1.55;
|
|
}
|
|
|
|
.bullets-disc {
|
|
list-style: disc;
|
|
padding-left: 22px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
|
|
.bullets-disc::marker,
|
|
.bullets-disc li::marker {
|
|
color: var(--text-dim);
|
|
}
|
|
|
|
.bullets-icon {
|
|
list-style: none;
|
|
padding-left: 4px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
}
|
|
|
|
.bullets-steps {
|
|
padding-left: 22px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
|
|
.bullets-icon .bullet-item {
|
|
display: flex;
|
|
gap: 10px;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.bullet-icon {
|
|
width: 18px;
|
|
color: var(--text-dim);
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: flex-start;
|
|
flex-shrink: 0;
|
|
margin-top: 2px;
|
|
}
|
|
|
|
.bullet-copy {
|
|
min-width: 0;
|
|
}
|
|
|
|
.bullet-copy strong {
|
|
color: var(--text);
|
|
margin-right: 4px;
|
|
}
|
|
|
|
.chapter code {
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
font-size: 12px;
|
|
background: var(--panel-alt);
|
|
padding: 1px 5px;
|
|
border-radius: 3px;
|
|
color: var(--text);
|
|
}
|
|
|
|
.chapter em {
|
|
font-style: italic;
|
|
color: var(--text);
|
|
}
|
|
|
|
.code {
|
|
margin: 0;
|
|
padding: 10px 12px;
|
|
background: var(--panel-alt);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
white-space: pre-wrap;
|
|
color: var(--text);
|
|
}
|
|
|
|
.cmd-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.cmd-table th,
|
|
.cmd-table td {
|
|
text-align: left;
|
|
padding: 6px 8px;
|
|
border-bottom: 1px solid var(--border);
|
|
vertical-align: top;
|
|
}
|
|
|
|
.cmd-table th {
|
|
font-size: 10px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.06em;
|
|
color: var(--text-dim);
|
|
}
|
|
|
|
.shortcuts {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 6px 12px;
|
|
}
|
|
|
|
.shortcuts li {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 10px;
|
|
padding: 5px 8px;
|
|
background: var(--panel-alt);
|
|
border-radius: var(--radius-sm);
|
|
font-size: 12px;
|
|
}
|
|
|
|
.shortcut-label {
|
|
color: var(--text);
|
|
}
|
|
|
|
kbd {
|
|
background: var(--panel);
|
|
border: 1px solid var(--border);
|
|
border-radius: 4px;
|
|
padding: 2px 6px;
|
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
font-size: 10px;
|
|
color: var(--text-dim-strong);
|
|
}
|
|
</style>
|