Add scafford for project index + info component

This commit is contained in:
MD 2022-03-22 22:07:34 +00:00
parent 3d324eea81
commit 9cffe0f5d6
7 changed files with 189 additions and 13 deletions

View File

@ -0,0 +1,27 @@
<script setup lang="ts">
import { Menu, MenuButton, MenuItems } from "@headlessui/vue";
import IconMdiMenuDown from "~icons/mdi/menu-down";
import IconMdiMenuUp from "~icons/mdi/menu-up";
const props = withDefaults(
defineProps<{
name?: string;
}>(),
{
name: "Dropdown",
}
);
</script>
<template>
<Menu v-slot="{ open }">
<MenuButton class="px-4 py-2 rounded bg-primary-100 text-white font-semibold inline-flex items-center">
<span class="mx-1">{{ props.name }}</span>
<IconMdiMenuUp v-if="open" class="text-lg"></IconMdiMenuUp>
<IconMdiMenuDown v-else class="text-lg"></IconMdiMenuDown>
</MenuButton>
<MenuItems class="absolute flex flex-col mt-1 z-10 py-1 rounded border-t-2 border-primary-100 bg-background-light-0 dark:bg-background-dark-80 shadow-soft">
<slot></slot>
</MenuItems>
</Menu>
</template>

View File

@ -0,0 +1,46 @@
<script setup lang="ts">
import { computed } from "vue";
import { MenuItem } from "@headlessui/vue";
const props = withDefaults(
defineProps<{
to?: string;
href?: string;
disabled?: boolean;
}>(),
{
to: undefined,
href: undefined,
disabled: false,
}
);
const type = computed(() => {
if (props.disabled) {
return "p";
}
if (props.to) {
return "router-link";
} else if (props.href) {
return "a";
} else {
return "p";
}
});
</script>
<template>
<MenuItem>
<component
:is="type"
:class="
'px-4 py-2 font-semibold hover:(bg-background-light-10 dark:bg-background-dark-90) ' +
(disabled ? 'cursor-not-allowed text-opacity-50' : 'cursor-pointer')
"
:href="href"
:to="to"
>
<slot></slot>
</component>
</MenuItem>
</template>

View File

@ -0,0 +1,81 @@
<script setup lang="ts">
import { computed, PropType } from "vue";
import { Project } from "hangar-api";
import { useI18n } from "vue-i18n";
import { forumUrl } from "~/composables/useUrlHelper";
import Card from "~/components/design/Card.vue";
import Link from "~/components/design/Link.vue";
import DropdownButton from "~/components/design/DropdownButton.vue";
import DropdownItem from "~/components/design/DropdownItem.vue";
import { hasPerms } from "~/composables/usePerm";
import { NamedPermission } from "~/types/enums";
const props = defineProps({
project: {
type: Object as PropType<Project>,
required: true,
},
});
const i18n = useI18n();
const slug = computed(() => props.project.namespace.owner + "/" + props.project.name);
</script>
<template>
<Card>
<template #header>{{ i18n.t("project.info.title") }}</template>
<template #default>
<table class="w-full">
<tbody>
<tr>
<th class="text-left">{{ i18n.t("project.category.info") }}</th>
<td class="text-right">{{ i18n.t("project.category." + project.category) }}</td>
</tr>
<tr>
<th class="text-left">{{ i18n.t("project.info.publishDate") }}</th>
<td class="text-right">{{ i18n.d(project.createdAt) }}</td>
</tr>
<tr>
<th class="text-left">{{ i18n.t("project.info.views", 0) }}</th>
<td class="text-right">{{ project.stats.views }}</td>
</tr>
<tr>
<th class="text-left">{{ i18n.t("project.info.totalDownloads", 0) }}</th>
<td class="text-right">{{ project.stats.downloads }}</td>
</tr>
<tr>
<th class="text-left">
<Link :to="`/${slug}/stars`">
{{ i18n.t("project.info.stars", 0) }}
</Link>
</th>
<td class="text-right">{{ project.stats.stars }}</td>
</tr>
<tr>
<th class="text-left">
<Link :to="`/${slug}/watchers`">
{{ i18n.t("project.info.watchers", 0) }}
</Link>
</th>
<td class="text-right">{{ project.stats.watchers }}</td>
</tr>
</tbody>
</table>
</template>
<template #footer>
<DropdownButton v-if="hasPerms(NamedPermission.IS_STAFF)" :name="i18n.t('project.actions.adminActions')">
<DropdownItem :to="`/${slug}/flags`">
{{ i18n.t("project.actions.flagHistory" /* , [project.info.flagCount] */) }}
</DropdownItem>
<DropdownItem :to="`/${slug}/notes`">
{{ i18n.t("project.actions.staffNotes" /* , [project.info.noteCount] */) }}
</DropdownItem>
<DropdownItem :to="`/admin/log/?projectFilter=/${slug}`">
{{ i18n.t("project.actions.userActionLogs") }}
</DropdownItem>
<DropdownItem v-if="project.topicId" :href="forumUrl(project.topicId)">
{{ i18n.t("project.actions.forum") }}
</DropdownItem>
</DropdownButton>
</template>
</Card>
</template>

View File

@ -22,7 +22,7 @@ function childRoute(route = ""): string {
</script>
<template>
<nav class="pt-4 pb-2 flex flex-wrap space-x-4">
<nav class="px-2 py-4 flex flex-wrap">
<ProjectNavItem :to="childRoute()">
{{ i18n.t("project.tabs.docs") }}
</ProjectNavItem>

View File

@ -16,18 +16,20 @@ const selected = computed(() => {
});
const clazz = computed(() => {
return "p-2 pb-1 rounded-sm border-b-3 flex items-center " + (selected.value ? "border-[#004ee9] font-semibold" : "border-neutral-400");
return "py-1 rounded-sm border-b-3 " + (selected.value ? "border-[#004ee9] font-semibold " : "border-neutral-200 dark:border-neutral-700");
});
</script>
<template>
<router-link v-if="to" :to="to" :class="clazz">
<slot></slot>
</router-link>
<a v-if="href" :href="props.href" :class="clazz" target="_blank">
<span class="mx-1">
<div class="my-2 mr-5">
<router-link v-if="to" :to="to" :class="clazz">
<slot></slot>
</span>
<IconMdiOpenInNew class="text-xs" />
</a>
</router-link>
<a v-if="href" :href="props.href" :class="clazz" target="_blank">
<span class="mx-1">
<slot></slot>
</span>
<IconMdiOpenInNew class="text-xs" />
</a>
</div>
</template>

View File

@ -1,3 +1,7 @@
export function projectIconUrl(owner: string, projectName: string) {
return `/api/internal/projects/project/${owner}/${projectName}/icon`;
}
export function forumUrl(topicId: number) {
return `https://forums.papermc.io/threads/` + topicId;
}

View File

@ -1,6 +1,9 @@
<script lang="ts" setup>
import { PropType } from "vue";
import { Project, User } from "hangar-api";
import Card from "~/components/design/Card.vue";
import { useI18n } from "vue-i18n";
import ProjectInfo from "~/components/projects/ProjectInfo.vue";
defineProps({
user: {
@ -12,11 +15,24 @@ defineProps({
required: true,
},
});
const i18n = useI18n();
</script>
<template>
<div>
Project child
{{ project }}
<div class="flex flex-col <lg:space-y-4 lg:flex-row lg:space-x-4">
<section class="flex-grow">
<Card>
Project readme
<br />
{{ project }}
</Card>
</section>
<section class="min-w-[320px] space-y-4">
<ProjectInfo :project="project"></ProjectInfo>
<Card>
<template #header>Promoted versions</template>
<template #default>Promoted versions go here</template>
</Card>
</section>
</div>
</template>