Added visibility toggle to stash tile. Collapsed stash page directory structure.
This commit is contained in:
parent
f6b50cc732
commit
ce4b9e7d40
|
@ -1,14 +1,16 @@
|
|||
<template>
|
||||
<div v-if="is404">
|
||||
<h1>404 Page Not Found</h1>
|
||||
<div class="page">
|
||||
<div v-if="is404">
|
||||
<h1>404 Not Found</h1>
|
||||
|
||||
<p v-if="abortReason">{{ abortReason }}</p>
|
||||
<p v-else>This page could not be found.</p>
|
||||
</div>
|
||||
<p v-if="abortReason">{{ abortReason }}</p>
|
||||
<p v-else>This page could not be found.</p>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<h1>500 Internal Error</h1>
|
||||
<p>Something went wrong.</p>
|
||||
<div v-else>
|
||||
<h1>500 Internal Error</h1>
|
||||
<p>Something went wrong.</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -25,3 +27,10 @@ defineProps({
|
|||
const pageContext = inject('pageContext');
|
||||
const { abortReason } = pageContext;
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -16,18 +16,34 @@
|
|||
:key="`stash-${stash.id}`"
|
||||
>
|
||||
<div class="stash">
|
||||
<a
|
||||
:href="`/stash/${profile.username}/${stash.slug}`"
|
||||
class="stash-name nolink"
|
||||
>
|
||||
{{ stash.name }}
|
||||
<div class="stash-header">
|
||||
<a
|
||||
:href="`/stash/${profile.username}/${stash.slug}`"
|
||||
class="stash-name ellipsis nolink"
|
||||
>
|
||||
<span class="ellipsis">{{ stash.name }}</span>
|
||||
|
||||
<Icon
|
||||
v-if="stash.primary"
|
||||
icon="heart7"
|
||||
class="primary"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<Icon
|
||||
v-if="stash.primary"
|
||||
icon="heart7"
|
||||
class="primary"
|
||||
v-if="profile.id === user?.id && stash.public"
|
||||
icon="eye"
|
||||
class="public noselect"
|
||||
@click="setStashPublic(stash, false)"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<Icon
|
||||
v-else-if="profile.id === user?.id"
|
||||
icon="eye-blocked"
|
||||
class="public noselect"
|
||||
@click="setStashPublic(stash, true)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="stash-counts">
|
||||
<a
|
||||
|
@ -52,14 +68,48 @@
|
|||
</template>
|
||||
|
||||
<script setup>
|
||||
import { inject } from 'vue';
|
||||
import { ref, inject } from 'vue';
|
||||
|
||||
import { get, patch } from '#/src/api.js';
|
||||
import events from '#/src/events.js';
|
||||
|
||||
const pageContext = inject('pageContext');
|
||||
const profile = pageContext.pageProps.profile;
|
||||
const profile = ref(pageContext.pageProps.profile);
|
||||
const user = pageContext.user;
|
||||
const done = ref(true);
|
||||
|
||||
function abbreviateNumber(number) {
|
||||
return number?.toLocaleString('en-US', { notation: 'compact' }) || 0;
|
||||
}
|
||||
|
||||
async function setStashPublic(stash, isPublic) {
|
||||
if (done.value === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
done.value = false;
|
||||
|
||||
await patch(`/stashes/${stash.id}`, { public: isPublic });
|
||||
profile.value = await get(`/users/${profile.value.id}`);
|
||||
|
||||
events.emit('feedback', {
|
||||
type: isPublic ? 'success' : 'remove',
|
||||
message: isPublic
|
||||
? `Stash '${stash.name}' is public`
|
||||
: `Stash '${stash.name}' is private`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
events.emit('feedback', {
|
||||
type: 'error',
|
||||
message: 'Failed to update stash',
|
||||
});
|
||||
}
|
||||
|
||||
done.value = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -73,11 +123,12 @@ function abbreviateNumber(number) {
|
|||
|
||||
.username {
|
||||
margin: 0;
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: .25rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
@ -99,11 +150,30 @@ function abbreviateNumber(number) {
|
|||
}
|
||||
}
|
||||
|
||||
.stash-name {
|
||||
.stash-header {
|
||||
display: flex;
|
||||
padding: .5rem;
|
||||
align-items: stretch;
|
||||
border-bottom: solid 1px var(--shadow-weak-30);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.icon.public {
|
||||
display: flex;
|
||||
height: auto;
|
||||
padding: 0 .75rem;
|
||||
fill: var(--shadow);
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
fill: var(--shadow-strong-30);
|
||||
}
|
||||
}
|
||||
|
||||
.stash-name {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
padding: .5rem;
|
||||
overflow: hidden;
|
||||
|
||||
.icon {
|
||||
margin-left: .75rem;
|
||||
|
@ -111,6 +181,7 @@ function abbreviateNumber(number) {
|
|||
|
||||
.icon.primary {
|
||||
fill: var(--primary);
|
||||
transform: translateY(1px);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { render } from 'vike/abort'; /* eslint-disable-line import/extensions */
|
|||
import { fetchUser } from '#/src/users.js';
|
||||
|
||||
export async function onBeforeRender(pageContext) {
|
||||
const profile = await fetchUser(pageContext.routeParams.username);
|
||||
const profile = await fetchUser(pageContext.routeParams.username, {}, pageContext.user);
|
||||
|
||||
if (!profile) {
|
||||
throw render(404, `Cannot find user '${pageContext.routeParams.username}'.`);
|
||||
|
|
17
src/users.js
17
src/users.js
|
@ -25,20 +25,20 @@ export function curateUser(user, assets = {}) {
|
|||
}
|
||||
|
||||
function whereUser(builder, userId, options = {}) {
|
||||
if (typeof userId === 'number') {
|
||||
builder.where('users.id', userId);
|
||||
}
|
||||
|
||||
if (typeof userId === 'string') {
|
||||
if (Number.isNaN(Number(userId))) {
|
||||
builder.where(knex.raw('lower(users.username)'), userId.toLowerCase());
|
||||
|
||||
if (options.email) {
|
||||
builder.orWhere(knex.raw('lower(users.email)'), userId.toLowerCase());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
builder.where('users.id', Number(userId));
|
||||
}
|
||||
|
||||
export async function fetchUser(userId, options = {}) {
|
||||
export async function fetchUser(userId, options = {}, reqUser) {
|
||||
const user = await knex('users')
|
||||
.select(knex.raw('users.*, users_roles.abilities as role_abilities'))
|
||||
.modify((builder) => whereUser(builder, userId, options))
|
||||
|
@ -52,6 +52,11 @@ export async function fetchUser(userId, options = {}) {
|
|||
|
||||
const stashes = await knex('stashes')
|
||||
.where('user_id', user.id)
|
||||
.modify((builder) => {
|
||||
if (reqUser?.id !== user.id) {
|
||||
builder.where('public', true);
|
||||
}
|
||||
})
|
||||
.leftJoin('stashes_meta', 'stashes_meta.stash_id', 'stashes.id');
|
||||
|
||||
if (options.raw) {
|
||||
|
|
|
@ -24,6 +24,10 @@ import {
|
|||
signupApi,
|
||||
} from './auth.js';
|
||||
|
||||
import {
|
||||
fetchUserApi
|
||||
} from './users.js';
|
||||
|
||||
import {
|
||||
createStashApi,
|
||||
removeStashApi,
|
||||
|
@ -96,6 +100,7 @@ export default async function initServer() {
|
|||
router.delete('/api/session', logoutApi);
|
||||
|
||||
// USERS
|
||||
router.get('/api/users/:userId', fetchUserApi);
|
||||
router.post('/api/users', signupApi);
|
||||
|
||||
// STASHES
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import { fetchUser } from '../users.js';
|
||||
|
||||
export async function fetchUserApi(req, res) {
|
||||
const user = await fetchUser(req.params.userId, {}, req.user);
|
||||
|
||||
res.send(user);
|
||||
}
|
Loading…
Reference in New Issue