feat: right side panel (#6952)

<img width="1183" height="809" alt="CleanShot 2025-11-26 at 16 01 15"
src="https://github.com/user-attachments/assets/c14dc5c3-a672-4dcd-917d-14f16310188e"
/>

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6952-feat-right-side-panel-2b76d73d36508112b121c283a479f42a)
by [Unito](https://www.unito.io)

---------

Co-authored-by: github-actions <github-actions@github.com>
This commit is contained in:
Rizumu Ayaka
2025-12-03 13:55:24 +08:00
committed by GitHub
parent fb54669dc3
commit 68274134c8
42 changed files with 1271 additions and 374 deletions

View File

@@ -17,17 +17,19 @@
'text-center text-xs font-normal',
{
'bg-interface-menu-component-surface-selected':
isSelected(option) && !disabled,
'hover:bg-interface-menu-component-surface-hovered':
!isSelected(option) && !disabled,
isSelected(index) && !disabled,
'hover:bg-interface-menu-component-surface-selected/50':
!isSelected(index) && !disabled,
'opacity-50 cursor-not-allowed': disabled,
'cursor-pointer': !disabled
},
isSelected(option) && !disabled ? 'text-primary' : 'text-secondary'
isSelected(index) && !disabled
? 'text-text-primary'
: 'text-text-secondary'
)
"
:disabled="disabled"
@click="handleSelect(option)"
@click="handleSelect(index)"
>
{{ getOptionLabel(option) }}
</button>
@@ -37,14 +39,18 @@
<script
setup
lang="ts"
generic="T extends string | number | { label: string; value: any }"
generic="
T extends string | number | { label: string; value: string | number }
"
>
import { cn } from '@/utils/tailwindUtil'
import { WidgetInputBaseClass } from '../layout'
type ModelValue = T extends object ? T['value'] : T
interface Props {
modelValue: string | null | undefined
modelValue: ModelValue | null | undefined
options: T[]
optionLabel?: string // PrimeVue compatible prop
optionValue?: string // PrimeVue compatible prop
@@ -52,7 +58,7 @@ interface Props {
}
interface Emits {
'update:modelValue': [value: string]
'update:modelValue': [value: ModelValue]
}
const props = withDefaults(defineProps<Props>(), {
@@ -64,18 +70,19 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits<Emits>()
// handle both string/number arrays and object arrays with PrimeVue compatibility
const getOptionValue = (option: T, index: number): string => {
if (typeof option === 'object' && option !== null) {
const valueField = props.optionValue
const value =
(option as any)[valueField] ??
(option as any).value ??
(option as any).name ??
(option as any).label ??
index
return String(value)
const getOptionValue = (option: T, index: number): ModelValue => {
if (typeof option !== 'object') {
return option as ModelValue
}
return String(option)
const valueField = props.optionValue
const value =
(option as any)[valueField] ??
option.value ??
(option as any).name ??
option.label ??
index
return value
}
// for display with PrimeVue compatibility
@@ -84,24 +91,24 @@ const getOptionLabel = (option: T): string => {
const labelField = props.optionLabel
return (
(option as any)[labelField] ??
(option as any).label ??
option.label ??
(option as any).name ??
(option as any).value ??
option.value ??
String(option)
)
}
return String(option)
}
const isSelected = (option: T): boolean => {
const optionValue = getOptionValue(option, props.options.indexOf(option))
return optionValue === String(props.modelValue ?? '')
const isSelected = (index: number): boolean => {
const optionValue = getOptionValue(props.options[index], index)
return String(optionValue) === String(props.modelValue ?? '')
}
const handleSelect = (option: T) => {
const handleSelect = (index: number) => {
if (props.disabled) return
const optionValue = getOptionValue(option, props.options.indexOf(option))
const optionValue = getOptionValue(props.options[index], index)
emit('update:modelValue', optionValue)
}
</script>

View File

@@ -1,18 +1,24 @@
<script setup lang="ts">
import { noop } from 'es-toolkit'
import { inject } from 'vue'
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
defineProps<{
widget: Pick<SimplifiedWidget<string | number | undefined>, 'name' | 'label'>
}>()
const hideLayoutField = inject<boolean>('hideLayoutField', false)
</script>
<template>
<div
class="grid grid-cols-subgrid h-7.5 min-w-0 items-center justify-between gap-1"
>
<div class="relative flex h-full min-w-0 items-center">
<div
v-if="!hideLayoutField"
class="relative flex h-full min-w-0 items-center"
>
<p
v-if="widget.name"
class="flex-1 truncate text-xs font-normal text-node-component-slot-text"