This commit is contained in:
th committed 2026-04-20 01:05:27 +02:00
1 parent 43933f93d1
commit 03b1147a93
10 files changed
+804 -80

No files matched your search

+107
View File
@@ -39,6 +39,17 @@ const blurAsset = computed(() => {
return a && (a.kind === 'rect' || a.kind === 'circle') ? a : null
})
const canBeMask = computed(() => {
const a = selectedAsset.value
return !!a && (a.kind === 'rect' || a.kind === 'circle' || a.kind === 'text')
})
const maskInGroup = computed(() => {
if (!selected.value) return false
const id = selected.value.id
return (store.scene.groups ?? []).some((g) => g.childIds.includes(id))
})
const blurValue = computed<number>({
get: () => {
const a = blurAsset.value
@@ -255,6 +266,43 @@ function removeKeyframeHere() {
<RangeSlider v-model="opacity" :min="0" :max="1" :step="0.01" :format="formatPercent" />
</label>
<section v-if="canBeMask" class="mask-group">
<h4>{{ t('properties.mask') }}</h4>
<label class="mask-toggle">
<input
type="checkbox"
:checked="!!selected.isMask"
@change="store.setLayerMask(selected.id, ($event.target as HTMLInputElement).checked)"
/>
<span>{{ t('properties.maskUse') }}</span>
</label>
<div v-if="selected.isMask" class="mask-mode-row">
<label class="mask-radio">
<input
type="radio"
:checked="(selected.maskMode ?? 'positive') === 'positive'"
@change="store.setLayerMaskMode(selected.id, 'positive')"
/>
<span>{{ t('properties.maskPositive') }}</span>
</label>
<label class="mask-radio">
<input
type="radio"
:checked="selected.maskMode === 'negative'"
@change="store.setLayerMaskMode(selected.id, 'negative')"
/>
<span>{{ t('properties.maskNegative') }}</span>
</label>
</div>
<p v-if="selected.isMask && maskInGroup" class="status-active">
{{ t('properties.maskActive') }}
</p>
<p v-if="selected.isMask && !maskInGroup" class="status-warn">
{{ t('properties.maskNeedsGroup') }}
</p>
<p v-if="selected.isMask" class="hint">{{ t('properties.maskHint') }}</p>
</section>
<button class="danger-btn" @click="store.removeLayer(selected.id)">
<PhTrash :size="13" />
{{ t('properties.deleteLayer') }}
@@ -332,6 +380,65 @@ input {
font-weight: 500;
}
.mask-group {
display: flex;
flex-direction: column;
gap: 6px;
padding-top: 8px;
border-top: 1px solid var(--border);
}
.mask-group h4 {
margin: 0;
font-size: 10px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-dim);
font-weight: 500;
}
.mask-toggle,
.mask-radio {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--text);
text-transform: none;
letter-spacing: 0;
cursor: pointer;
flex: 0 0 auto;
}
.mask-mode-row {
display: flex;
gap: 16px;
}
.mask-toggle input,
.mask-radio input {
width: auto;
margin: 0;
}
.status-active,
.status-warn {
margin: 0;
font-size: 11px;
padding: 4px 8px;
border-radius: var(--radius-sm);
}
.status-active {
color: #6ea8ff;
background: color-mix(in srgb, #6ea8ff 14%, transparent);
}
.status-warn {
color: #ffb84d;
background: color-mix(in srgb, #ffb84d 16%, transparent);
}
.kf-row {
display: flex;
align-items: center;