Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added src/assets/images/backgrounds/lake.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed src/assets/images/generic/hyde.jpg
Binary file not shown.
Binary file added src/assets/images/generic/hyde.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 15 additions & 43 deletions src/components/CanvasEditor/CanvasEditorTools.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script setup lang="ts">
import { computed } from 'vue'
import { Button } from '@/components/ui/button'
import { ColorPicker } from '@/components/ui/color-picker'
import BrushSize from './BrushSize.vue'
import { Brush, Eraser, PaintBucket, Undo2, Redo2, Trash2, Download } from 'lucide-vue-next'
import { DrawingToolbar } from '@/components/DrawingToolbar'
import type { DrawingTool as CanvasDrawingTool } from '@/components/DrawingToolbar'
import { Undo2, Redo2, Trash2, Download } from 'lucide-vue-next'
import type { DrawingTool } from '@webgamekit/canvas-editor'
import type { CanvasEditorToolButton } from './types'

Expand Down Expand Up @@ -46,6 +46,10 @@ const emit = defineEmits<{
clear: []
}>()

const toolbarTools = computed(() =>
(['brush', 'eraser', 'fill', 'color', 'size'] as const).filter((t) => show.value.has(t))
)

const download = (): void => {
const snapshot = props.getSnapshot()
const dataUrl = (JSON.parse(snapshot) as { front: string }).front
Expand All @@ -59,46 +63,14 @@ const download = (): void => {

<template>
<div class="canvas-editor-tools">
<Button
v-if="show.has('brush')"
:variant="tool === 'brush' ? 'default' : 'outline'"
size="icon"
title="Brush"
@click="emit('update:tool', 'brush')"
>
<Brush class="canvas-editor-tools__icon" />
</Button>
<Button
v-if="show.has('eraser')"
:variant="tool === 'eraser' ? 'default' : 'outline'"
size="icon"
title="Eraser"
@click="emit('update:tool', 'eraser')"
>
<Eraser class="canvas-editor-tools__icon" />
</Button>
<Button
v-if="show.has('fill')"
:variant="tool === 'fill' ? 'default' : 'outline'"
size="icon"
title="Fill"
@click="emit('update:tool', 'fill')"
>
<PaintBucket class="canvas-editor-tools__icon" />
</Button>
<ColorPicker
v-if="show.has('color')"
:model-value="color"
:hide-value="hideColorValue"
title="Color"
@update:model-value="emit('update:color', $event)"
/>
<BrushSize
v-if="show.has('size')"
:model-value="size"
:min="1"
:max="80"
@update:model-value="emit('update:size', $event)"
<DrawingToolbar
:tool="tool as CanvasDrawingTool"
:color="color"
:size="size"
:visible-tools="toolbarTools"
@update:tool="emit('update:tool', $event as DrawingTool)"
@update:color="emit('update:color', $event)"
@update:size="emit('update:size', $event)"
/>
<Button
v-if="show.has('undo')"
Expand Down
126 changes: 126 additions & 0 deletions src/components/DrawingToolbar/DrawingToolbar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<script setup lang="ts">
import { computed } from 'vue'
import { Button } from '@/components/ui/button'
import { ColorPicker } from '@/components/ui/color-picker'
import BrushSize from '@/components/CanvasEditor/BrushSize.vue'
import { Brush, Eraser, PaintBucket, RotateCw, Undo2, Redo2 } from 'lucide-vue-next'

export type DrawingTool = 'brush' | 'eraser' | 'fill' | 'rotate'
export type DrawingToolbarButton = DrawingTool | 'color' | 'size' | 'undo' | 'redo'

const props = withDefaults(
defineProps<{
tool: DrawingTool
color: string
size: number
canUndo?: boolean
canRedo?: boolean
visibleTools?: readonly DrawingToolbarButton[]
}>(),
{
canUndo: false,
canRedo: false,
visibleTools: () => ['brush', 'eraser', 'fill', 'color', 'size']
}
)

const emit = defineEmits<{
'update:tool': [value: DrawingTool]
'update:color': [value: string]
'update:size': [value: number]
undo: []
redo: []
}>()

const show = computed(() => new Set(props.visibleTools))
</script>

<template>
<div class="drawing-toolbar">
<Button
v-if="show.has('brush')"
:variant="tool === 'brush' ? 'default' : 'outline'"
size="icon"
title="Brush"
@click="emit('update:tool', 'brush')"
>
<Brush class="drawing-toolbar__icon" />
</Button>
<Button
v-if="show.has('eraser')"
:variant="tool === 'eraser' ? 'default' : 'outline'"
size="icon"
title="Eraser"
@click="emit('update:tool', 'eraser')"
>
<Eraser class="drawing-toolbar__icon" />
</Button>
<Button
v-if="show.has('fill')"
:variant="tool === 'fill' ? 'default' : 'outline'"
size="icon"
title="Fill"
@click="emit('update:tool', 'fill')"
>
<PaintBucket class="drawing-toolbar__icon" />
</Button>
<Button
v-if="show.has('rotate')"
:variant="tool === 'rotate' ? 'default' : 'outline'"
size="icon"
title="Rotate sphere"
@click="emit('update:tool', 'rotate')"
>
<RotateCw class="drawing-toolbar__icon" />
</Button>
<ColorPicker
v-if="show.has('color')"
:model-value="color"
:hide-value="true"
title="Color"
@update:model-value="emit('update:color', $event)"
/>
<BrushSize
v-if="show.has('size')"
:model-value="size"
:min="1"
:max="80"
@update:model-value="emit('update:size', $event)"
/>
<Button
v-if="show.has('undo')"
variant="outline"
size="icon"
:disabled="!canUndo"
title="Undo"
@click="emit('undo')"
>
<Undo2 class="drawing-toolbar__icon" />
</Button>
<Button
v-if="show.has('redo')"
variant="outline"
size="icon"
:disabled="!canRedo"
title="Redo"
@click="emit('redo')"
>
<Redo2 class="drawing-toolbar__icon" />
</Button>
</div>
</template>

<style scoped>
.drawing-toolbar {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-2);
align-items: center;
}

.drawing-toolbar__icon {
width: 1rem;
height: 1rem;
flex-shrink: 0;
}
</style>
2 changes: 2 additions & 0 deletions src/components/DrawingToolbar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as DrawingToolbar } from './DrawingToolbar.vue'
export type { DrawingTool, DrawingToolbarButton } from './DrawingToolbar.vue'
11 changes: 7 additions & 4 deletions src/components/panels/ConfigControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const props = defineProps<{
}>()

const isControlSchema = (object: any): object is ControlSchema => {
if (typeof object !== 'object' || object === null) return false
if (typeof object !== 'object' || object === null || Array.isArray(object)) return false
const keys = Object.keys(object)
const controlKeys = [
'min',
Expand Down Expand Up @@ -83,6 +83,7 @@ const groups = computed(() => {
const controls: { key: string; path: string; schema: ControlSchema }[] = []

Object.entries(props.schema).forEach(([key, value]) => {
if (key.startsWith('__')) return
if (isControlSchema(value)) {
controls.push({ key, path: getFullPath(key), schema: value })
} else {
Expand All @@ -93,8 +94,11 @@ const groups = computed(() => {
return { groups: result, controls }
})

// All group keys for default-open accordion
const defaultOpenGroups = computed(() => groups.value.groups.map((g) => g.key))
const defaultOpenGroups = computed(() => {
const meta = (props.schema as Record<string, unknown>)['__defaultOpenGroups']
if (!props.basePath && Array.isArray(meta)) return meta as string[]
return groups.value.groups.map((g) => g.key)
})

const handleSliderUpdate = (path: string, value: number[]) => {
props.onUpdate(path, value[0])
Expand Down Expand Up @@ -357,7 +361,6 @@ const handleButtonSelectorUpdate = (path: string, value: string) => {

<style scoped>
.config-controls {
overflow-x: hidden;
padding-bottom: 0.25rem;
}

Expand Down
6 changes: 5 additions & 1 deletion src/components/panels/PanelContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,14 @@ defineProps<{
align-items: flex-start;
z-index: calc(var(--z-overlay) + 1);
pointer-events: none;
overflow-y: auto;

> * {
pointer-events: auto;
}

@media (max-width: 600px) {
overflow-y: auto;
}
}

.panel-container--right {
Expand All @@ -81,6 +84,7 @@ defineProps<{
background-color: var(--color-background);
padding: var(--spacing-2);
overflow-x: hidden;
overflow-y: auto;
max-height: 100%;
display: flex;
flex-direction: column;
Expand Down
Loading
Loading