mirror of
https://github.com/modrinth/code.git
synced 2026-08-30 11:36:05 +00:00
172 lines
4.6 KiB
Vue
172 lines
4.6 KiB
Vue
<script setup lang="ts">
|
||
import { GitForkIcon, PlusIcon, TrashIcon } from '@modrinth/assets'
|
||
import {
|
||
Button,
|
||
commonMessages,
|
||
defineMessages,
|
||
SettingsFormGroup,
|
||
SettingsToggleCard,
|
||
StyledInput,
|
||
useVIntl,
|
||
} from '@modrinth/ui'
|
||
import { watch } from 'vue'
|
||
|
||
import type { DerivativeDisclosure, DerivativeSource } from './types'
|
||
|
||
const model = defineModel<DerivativeDisclosure>({ required: true })
|
||
|
||
defineProps<{
|
||
disabled?: boolean
|
||
}>()
|
||
|
||
const { formatMessage } = useVIntl()
|
||
|
||
const messages = defineMessages({
|
||
title: {
|
||
id: 'project.settings.disclosures.derivative.title',
|
||
defaultMessage: 'Contains derivative content',
|
||
},
|
||
description: {
|
||
id: 'project.settings.disclosures.derivative.description',
|
||
defaultMessage:
|
||
'You must enable this if your project is derivative of another project, such as being a fork or containing a substantial amount of someone else’s work.',
|
||
},
|
||
nameLabel: {
|
||
id: 'project.settings.disclosures.derivative.name-label',
|
||
defaultMessage: 'Name of original work',
|
||
},
|
||
namePlaceholder: {
|
||
id: 'project.settings.disclosures.derivative.name-placeholder',
|
||
defaultMessage: 'Example project',
|
||
},
|
||
linkLabel: {
|
||
id: 'project.settings.disclosures.derivative.link-label',
|
||
defaultMessage: 'Link to original work',
|
||
},
|
||
linkPlaceholder: {
|
||
id: 'project.settings.disclosures.derivative.link-placeholder',
|
||
defaultMessage: 'https://example.com',
|
||
},
|
||
noteLabel: {
|
||
id: 'project.settings.disclosures.derivative.note-label',
|
||
defaultMessage: 'Explain how your project is based on the original work',
|
||
},
|
||
})
|
||
|
||
function emptyDerivativeSource(): DerivativeSource {
|
||
return { label: '' }
|
||
}
|
||
|
||
function updateSource(index: number, patch: Partial<DerivativeSource>) {
|
||
model.value.sources = model.value.sources.map((source, i) =>
|
||
i === index ? { ...source, ...patch } : source,
|
||
)
|
||
}
|
||
|
||
watch(
|
||
() => model.value.enabled,
|
||
(enabled) => {
|
||
if (enabled && model.value.sources.length === 0) {
|
||
model.value.sources = [emptyDerivativeSource()]
|
||
}
|
||
},
|
||
)
|
||
|
||
function addSource() {
|
||
model.value.sources = [...model.value.sources, emptyDerivativeSource()]
|
||
}
|
||
|
||
function removeSource(index: number) {
|
||
if (model.value.sources.length <= 1) return
|
||
model.value.sources = model.value.sources.filter((_, i) => i !== index)
|
||
}
|
||
|
||
function setOptionalField(
|
||
index: number,
|
||
field: 'link' | 'note',
|
||
value: string | number | undefined,
|
||
) {
|
||
updateSource(index, {
|
||
[field]: typeof value === 'string' && value ? value : null,
|
||
})
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<SettingsToggleCard
|
||
v-model="model.enabled"
|
||
:disabled="disabled"
|
||
:icon="GitForkIcon"
|
||
:title="formatMessage(messages.title)"
|
||
:description="formatMessage(messages.description)"
|
||
>
|
||
<template #expanded>
|
||
<div
|
||
v-for="(source, index) in model.sources"
|
||
:key="index"
|
||
class="relative flex flex-col gap-4 rounded-2xl border border-solid border-surface-4 bg-surface-3 p-4"
|
||
>
|
||
<div class="absolute right-3 top-3">
|
||
<Button
|
||
v-if="model.sources.length > 1"
|
||
type="quiet"
|
||
color="red"
|
||
:disabled="disabled"
|
||
@click="removeSource(index)"
|
||
>
|
||
<TrashIcon />
|
||
{{ formatMessage(commonMessages.removeButton) }}
|
||
</Button>
|
||
</div>
|
||
<SettingsFormGroup
|
||
:title="formatMessage(messages.nameLabel)"
|
||
:title-for="`derivative-name-${index}`"
|
||
class="max-w-[40rem]"
|
||
>
|
||
<StyledInput
|
||
:id="`derivative-name-${index}`"
|
||
:model-value="source.label"
|
||
:disabled="disabled"
|
||
:placeholder="formatMessage(messages.namePlaceholder)"
|
||
@update:model-value="
|
||
(value) => updateSource(index, { label: typeof value === 'string' ? value : '' })
|
||
"
|
||
/>
|
||
</SettingsFormGroup>
|
||
<SettingsFormGroup
|
||
:title="formatMessage(messages.linkLabel)"
|
||
:title-for="`derivative-link-${index}`"
|
||
class="max-w-[40rem]"
|
||
>
|
||
<StyledInput
|
||
:id="`derivative-link-${index}`"
|
||
:model-value="source.link ?? undefined"
|
||
type="url"
|
||
:disabled="disabled"
|
||
:placeholder="formatMessage(messages.linkPlaceholder)"
|
||
@update:model-value="(value) => setOptionalField(index, 'link', value)"
|
||
/>
|
||
</SettingsFormGroup>
|
||
<SettingsFormGroup
|
||
:title="formatMessage(messages.noteLabel)"
|
||
:title-for="`derivative-note-${index}`"
|
||
class="max-w-[40rem]"
|
||
>
|
||
<StyledInput
|
||
:id="`derivative-note-${index}`"
|
||
:model-value="source.note ?? undefined"
|
||
multiline
|
||
:rows="3"
|
||
:disabled="disabled"
|
||
@update:model-value="(value) => setOptionalField(index, 'note', value)"
|
||
/>
|
||
</SettingsFormGroup>
|
||
</div>
|
||
<Button class="w-fit" :disabled="disabled" @click="addSource">
|
||
<PlusIcon />
|
||
{{ formatMessage(commonMessages.addAnotherButton) }}
|
||
</Button>
|
||
</template>
|
||
</SettingsToggleCard>
|
||
</template>
|