|
| 1 | +<script setup lang="ts"> |
| 2 | +import { RightArrowIcon, SearchIcon, SortAscIcon, SortDescIcon } from '@modrinth/assets' |
| 3 | +import { |
| 4 | + Admonition, |
| 5 | + ButtonStyled, |
| 6 | + Combobox, |
| 7 | + type ComboboxOption, |
| 8 | + commonMessages, |
| 9 | + defineMessages, |
| 10 | + EmptyState, |
| 11 | + IntlFormatted, |
| 12 | + StyledInput, |
| 13 | + useVIntl, |
| 14 | +} from '@modrinth/ui' |
| 15 | +import ExternalProjectPermissionsCard from '@modrinth/ui/src/components/external_files/ExternalProjectPermissionsCard.vue' |
| 16 | +import { ref } from 'vue' |
| 17 | +
|
| 18 | +const { formatMessage } = useVIntl() |
| 19 | +const flags = useFeatureFlags() |
| 20 | +
|
| 21 | +if (!flags.value.modpackPermissionsPage) { |
| 22 | + throw createError({ |
| 23 | + fatal: true, |
| 24 | + statusCode: 404, |
| 25 | + }) |
| 26 | +} |
| 27 | +
|
| 28 | +const externalFiles = ref([{}]) |
| 29 | +const searchQuery = ref('') |
| 30 | +const currentSortType = ref('Oldest') |
| 31 | +
|
| 32 | +const sortTypes: ComboboxOption<string>[] = [ |
| 33 | + { value: 'Oldest', label: 'Oldest' }, |
| 34 | + { value: 'Newest', label: 'Newest' }, |
| 35 | +] |
| 36 | +const messages = defineMessages({ |
| 37 | + searchPlaceholder: { |
| 38 | + id: 'project.settings.permissions.search-placeholder', |
| 39 | + defaultMessage: |
| 40 | + 'Search {count} {count, plural, one {external project} other {external projects}}...', |
| 41 | + }, |
| 42 | + infoBannerTitle: { |
| 43 | + id: 'project.settings.permissions.info-banner.title', |
| 44 | + defaultMessage: 'Learn how attributions work', |
| 45 | + }, |
| 46 | + infoBannerDescription: { |
| 47 | + id: 'project.settings.permissions.info-banner.description', |
| 48 | + defaultMessage: `If you include content that isn’t hosted on Modrinth, you need to let us know where it’s from and verify that you have permission to distribute the files. Check out <link>our guide</link> to learn about how to do this properly!`, |
| 49 | + }, |
| 50 | + learnMore: { |
| 51 | + id: 'project.settings.permissions.learn-more', |
| 52 | + defaultMessage: 'Learn more', |
| 53 | + }, |
| 54 | + emptyStateHeading: { |
| 55 | + id: 'project.settings.permissions.empty-state.heading', |
| 56 | + defaultMessage: `You're all set!`, |
| 57 | + }, |
| 58 | + emptyStateDescription: { |
| 59 | + id: 'project.settings.permissions.empty-state.description', |
| 60 | + defaultMessage: `None of your versions contain external content, so you don't need to worry about obtaining permissions.`, |
| 61 | + }, |
| 62 | + completedTitle: { |
| 63 | + id: 'project.settings.permissions.completed.title', |
| 64 | + defaultMessage: `Attributions completed!`, |
| 65 | + }, |
| 66 | + completedDescription: { |
| 67 | + id: 'project.settings.permissions.completed.description', |
| 68 | + defaultMessage: 'All external content has attributions provided.', |
| 69 | + }, |
| 70 | + failTitle: { |
| 71 | + id: 'project.settings.permissions.fail.title', |
| 72 | + defaultMessage: `Some content can't be included`, |
| 73 | + }, |
| 74 | + failDescription: { |
| 75 | + id: 'project.settings.permissions.fail.description', |
| 76 | + defaultMessage: `You don't have permission to redistribute some of the external content you've added. In order to publish on Modrinth, remove the infringing content.`, |
| 77 | + }, |
| 78 | + attentionNeededTitle: { |
| 79 | + id: 'project.settings.permissions.attention-needed.title', |
| 80 | + defaultMessage: `Unknown embedded content`, |
| 81 | + }, |
| 82 | + attentionNeededDescriptionApproved: { |
| 83 | + id: 'project.settings.permissions.attention-needed.description.proj-approved', |
| 84 | + defaultMessage: `Please provide proof that you have permission to redistribute all of the following files and any withheld versions will be automatically published.`, |
| 85 | + }, |
| 86 | + attentionNeededDescriptionDraft: { |
| 87 | + id: 'project.settings.permissions.attention-needed.description.proj-draft', |
| 88 | + defaultMessage: `Please provide proof that you have permission to redistribute all of the following files before you can submit your project for review.`, |
| 89 | + }, |
| 90 | +}) |
| 91 | +
|
| 92 | +function dismissInfoBanner() { |
| 93 | + flags.value.dismissedExternalProjectsInfo = true |
| 94 | + saveFeatureFlags() |
| 95 | +} |
| 96 | +</script> |
| 97 | +<template> |
| 98 | + <template v-if="externalFiles.length > 0"> |
| 99 | + <Admonition |
| 100 | + v-if="!flags.dismissedExternalProjectsInfo" |
| 101 | + type="info" |
| 102 | + class="mb-4" |
| 103 | + :header="formatMessage(messages.infoBannerTitle)" |
| 104 | + dismissible |
| 105 | + @dismiss="dismissInfoBanner" |
| 106 | + > |
| 107 | + <IntlFormatted :message-id="messages.infoBannerDescription"> |
| 108 | + <template #link="{ children }"> |
| 109 | + <a class="text-link" target="_blank"> <component :is="() => children" /> </a> |
| 110 | + </template> |
| 111 | + </IntlFormatted> |
| 112 | + <template #actions> |
| 113 | + <div class="flex"> |
| 114 | + <ButtonStyled color="blue"> |
| 115 | + <a> {{ formatMessage(messages.learnMore) }} <RightArrowIcon /> </a> |
| 116 | + </ButtonStyled> |
| 117 | + </div> |
| 118 | + </template> |
| 119 | + </Admonition> |
| 120 | + <Admonition |
| 121 | + v-if="true" |
| 122 | + type="success" |
| 123 | + class="mb-4" |
| 124 | + :header="formatMessage(messages.completedTitle)" |
| 125 | + :body="formatMessage(messages.completedDescription)" |
| 126 | + /> |
| 127 | + <Admonition |
| 128 | + v-if="true" |
| 129 | + type="warning" |
| 130 | + class="mb-4" |
| 131 | + :header="formatMessage(messages.attentionNeededTitle)" |
| 132 | + :body="formatMessage(messages.attentionNeededDescriptionDraft)" |
| 133 | + /> |
| 134 | + <Admonition |
| 135 | + v-if="true" |
| 136 | + type="critical" |
| 137 | + class="mb-4" |
| 138 | + :header="formatMessage(messages.failTitle)" |
| 139 | + :body="formatMessage(messages.failDescription)" |
| 140 | + /> |
| 141 | + <div class="grid grid-cols-[1fr_auto] gap-2"> |
| 142 | + <StyledInput |
| 143 | + v-model="searchQuery" |
| 144 | + type="search" |
| 145 | + :placeholder=" |
| 146 | + formatMessage(messages.searchPlaceholder, { |
| 147 | + count: externalFiles.length, |
| 148 | + }) |
| 149 | + " |
| 150 | + :icon="SearchIcon" |
| 151 | + input-class="h-[40px]" |
| 152 | + /> |
| 153 | + <div> |
| 154 | + <Combobox |
| 155 | + v-model="currentSortType" |
| 156 | + class="!w-full flex-grow sm:!w-[150px] sm:flex-grow-0 lg:!w-[150px]" |
| 157 | + :options="sortTypes" |
| 158 | + :placeholder="formatMessage(commonMessages.sortByLabel)" |
| 159 | + > |
| 160 | + <template #selected> |
| 161 | + <span class="flex flex-row gap-2 align-middle font-semibold"> |
| 162 | + <SortAscIcon |
| 163 | + v-if="currentSortType === 'Oldest'" |
| 164 | + class="size-5 flex-shrink-0 text-secondary" |
| 165 | + /> |
| 166 | + <SortDescIcon v-else class="size-5 flex-shrink-0 text-secondary" /> |
| 167 | + <span class="truncate text-contrast">{{ currentSortType }}</span> |
| 168 | + </span> |
| 169 | + </template> |
| 170 | + </Combobox> |
| 171 | + </div> |
| 172 | + </div> |
| 173 | + <div class="mt-4 flex flex-col gap-3"> |
| 174 | + <ExternalProjectPermissionsCard title="FTB Library" /> |
| 175 | + </div> |
| 176 | + </template> |
| 177 | + <template v-else> |
| 178 | + <EmptyState |
| 179 | + :heading="formatMessage(messages.emptyStateHeading)" |
| 180 | + :description="formatMessage(messages.emptyStateDescription)" |
| 181 | + type="done" |
| 182 | + /> |
| 183 | + </template> |
| 184 | +</template> |
0 commit comments