🎨
This commit is contained in:
parent
9e5278d276
commit
d0bbeeee52
3 changed files with 90 additions and 72 deletions
|
@ -69,6 +69,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||||
|
|
||||||
return await Promise.all(assigns.map(async assign => ({
|
return await Promise.all(assigns.map(async assign => ({
|
||||||
id: assign.id,
|
id: assign.id,
|
||||||
|
createdAt: assign.createdAt,
|
||||||
user: await this.userEntityService.pack(assign.user!, me, { detail: true }),
|
user: await this.userEntityService.pack(assign.user!, me, { detail: true }),
|
||||||
expiresAt: assign.expiresAt,
|
expiresAt: assign.expiresAt,
|
||||||
})));
|
})));
|
||||||
|
|
|
@ -30,13 +30,20 @@
|
||||||
|
|
||||||
<template #default="{ items }">
|
<template #default="{ items }">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<div v-for="item in items" :key="item.user.id" :class="$style.userItem">
|
<div v-for="item in items" :key="item.user.id" :class="[$style.userItem, { [$style.userItemOpend]: expandedItems.includes(item.id) }]">
|
||||||
<MkA :class="$style.user" :to="`/user-info/${item.user.id}`">
|
<div :class="$style.userItemMain">
|
||||||
|
<MkA :class="$style.userItemMainBody" :to="`/user-info/${item.user.id}`">
|
||||||
<MkUserCardMini :user="item.user"/>
|
<MkUserCardMini :user="item.user"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
<button v-if="item.expiresAt != null" class="_button" :class="$style.expiresAt" @click="showExpireInfo(item, $event)"><i class="ti ti-clock-hour-3"></i></button>
|
<button class="_button" :class="$style.userToggle" @click="toggleItem(item)"><i :class="$style.chevron" class="ti ti-chevron-down"></i></button>
|
||||||
<button class="_button" :class="$style.unassign" @click="unassign(item.user, $event)"><i class="ti ti-x"></i></button>
|
<button class="_button" :class="$style.unassign" @click="unassign(item.user, $event)"><i class="ti ti-x"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="expandedItems.includes(item.id)" :class="$style.userItemSub">
|
||||||
|
<div>Assigned: <MkTime :time="item.createdAt" mode="detail"/></div>
|
||||||
|
<div v-if="item.expiresAt">Period: {{ item.expiresAt.toLocaleString() }}</div>
|
||||||
|
<div v-else>Period: {{ i18n.ts.indefinitely }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
|
@ -77,6 +84,8 @@ const usersPagination = {
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let expandedItems = $ref([]);
|
||||||
|
|
||||||
const role = reactive(await os.api('admin/roles/show', {
|
const role = reactive(await os.api('admin/roles/show', {
|
||||||
roleId: props.id,
|
roleId: props.id,
|
||||||
}));
|
}));
|
||||||
|
@ -129,7 +138,7 @@ async function assign() {
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
await os.apiWithDialog('admin/roles/assign', { roleId: role.id, userId: user.id, expiresAt });
|
await os.apiWithDialog('admin/roles/assign', { roleId: role.id, userId: user.id, expiresAt });
|
||||||
role.users.push(user);
|
//role.users.push(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unassign(user, ev) {
|
async function unassign(user, ev) {
|
||||||
|
@ -139,16 +148,17 @@ async function unassign(user, ev) {
|
||||||
danger: true,
|
danger: true,
|
||||||
action: async () => {
|
action: async () => {
|
||||||
await os.apiWithDialog('admin/roles/unassign', { roleId: role.id, userId: user.id });
|
await os.apiWithDialog('admin/roles/unassign', { roleId: role.id, userId: user.id });
|
||||||
role.users = role.users.filter(u => u.id !== user.id);
|
//role.users = role.users.filter(u => u.id !== user.id);
|
||||||
},
|
},
|
||||||
}], ev.currentTarget ?? ev.target);
|
}], ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function showExpireInfo(assignment) {
|
async function toggleItem(item) {
|
||||||
os.alert({
|
if (expandedItems.includes(item.id)) {
|
||||||
type: 'info',
|
expandedItems = expandedItems.filter(x => x !== item.id);
|
||||||
text: assignment.expiresAt.toLocaleString(),
|
} else {
|
||||||
});
|
expandedItems.push(item.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerActions = $computed(() => []);
|
const headerActions = $computed(() => []);
|
||||||
|
@ -162,24 +172,41 @@ definePageMetadata(computed(() => ({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
.userItem {
|
.userItemMain {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user {
|
.userItemSub {
|
||||||
flex: 1;
|
padding: 6px 12px;
|
||||||
min-width: 0;
|
font-size: 85%;
|
||||||
|
color: var(--fgTransparentWeak);
|
||||||
}
|
}
|
||||||
|
|
||||||
.expiresAt,
|
.userItemMainBody {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.userToggle,
|
||||||
.unassign {
|
.unassign {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
margin-left: 8px;
|
|
||||||
align-self: center;
|
align-self: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expiresAt + .unassign {
|
.chevron {
|
||||||
margin-left: 0;
|
display: block;
|
||||||
|
transition: transform 0.1s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.userItem.userItemOpend {
|
||||||
|
.chevron {
|
||||||
|
transform: rotateX(180deg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
<MkStickyContainer>
|
<MkStickyContainer>
|
||||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
<MkSpacer :content-max="700">
|
<MkSpacer :content-max="700">
|
||||||
<div class="mk-list-page">
|
<div>
|
||||||
<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
|
<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
|
||||||
<div v-if="list" class="">
|
<div v-if="list" class="">
|
||||||
<div class="">
|
<div class="_buttons">
|
||||||
<MkButton inline @click="addUser()">{{ i18n.ts.addUser }}</MkButton>
|
<MkButton inline @click="addUser()">{{ i18n.ts.addUser }}</MkButton>
|
||||||
<MkButton inline @click="renameList()">{{ i18n.ts.rename }}</MkButton>
|
<MkButton inline @click="renameList()">{{ i18n.ts.rename }}</MkButton>
|
||||||
<MkButton inline @click="deleteList()">{{ i18n.ts.delete }}</MkButton>
|
<MkButton inline danger @click="deleteList()">{{ i18n.ts.delete }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
@ -16,18 +16,12 @@
|
||||||
<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
|
<Transition :name="$store.state.animation ? '_transition_zoom' : ''" mode="out-in">
|
||||||
<div v-if="list" class="members _margin">
|
<div v-if="list" class="members _margin">
|
||||||
<div class="">{{ i18n.ts.members }}</div>
|
<div class="">{{ i18n.ts.members }}</div>
|
||||||
<div class="">
|
<div class="_gaps_s">
|
||||||
<div class="users">
|
<div v-for="user in users" :key="user.id" :class="$style.userItem">
|
||||||
<div v-for="user in users" :key="user.id" class="user _panel">
|
<MkA :class="$style.userItemBody" :to="`${userPage(user)}`">
|
||||||
<MkAvatar :user="user" class="avatar" indicator link preview/>
|
<MkUserCardMini :user="user"/>
|
||||||
<div class="body">
|
</MkA>
|
||||||
<MkUserName :user="user" class="name"/>
|
<button class="_button" :class="$style.remove" @click="removeUser(user, $event)"><i class="ti ti-x"></i></button>
|
||||||
<MkAcct :user="user" class="acct"/>
|
|
||||||
</div>
|
|
||||||
<div class="action">
|
|
||||||
<button class="_button" @click="removeUser(user)"><i class="ti ti-x"></i></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,6 +38,8 @@ import * as os from '@/os';
|
||||||
import { mainRouter } from '@/router';
|
import { mainRouter } from '@/router';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
import { userPage } from '@/filters/user';
|
||||||
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
listId: string;
|
listId: string;
|
||||||
|
@ -76,13 +72,20 @@ function addUser() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeUser(user) {
|
async function removeUser(user, ev) {
|
||||||
|
os.popupMenu([{
|
||||||
|
text: i18n.ts.remove,
|
||||||
|
icon: 'ti ti-x',
|
||||||
|
danger: true,
|
||||||
|
action: async () => {
|
||||||
os.api('users/lists/pull', {
|
os.api('users/lists/pull', {
|
||||||
listId: list.id,
|
listId: list.id,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
users = users.filter(x => x.id !== user.id);
|
users = users.filter(x => x.id !== user.id);
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
}], ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function renameList() {
|
async function renameList() {
|
||||||
|
@ -126,37 +129,24 @@ definePageMetadata(computed(() => list ? {
|
||||||
} : null));
|
} : null));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.mk-list-page {
|
.userItem {
|
||||||
> .members {
|
|
||||||
> ._content {
|
|
||||||
> .users {
|
|
||||||
> .user {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
> .avatar {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> .body {
|
.userItemBody {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 8px;
|
min-width: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
> .name {
|
&:hover {
|
||||||
display: block;
|
text-decoration: none;
|
||||||
font-weight: bold;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .acct {
|
.remove {
|
||||||
opacity: 0.5;
|
width: 32px;
|
||||||
}
|
height: 32px;
|
||||||
}
|
align-self: center;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue