Skip to content

Commit

Permalink
feat(collapsible-recent-threads): implement collapsible recent threads
Browse files Browse the repository at this point in the history
  • Loading branch information
akinsey committed Jan 24, 2025
1 parent 4e27de3 commit b66a2ad
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 58 deletions.
171 changes: 114 additions & 57 deletions src/components/threads/RecentThreads.vue
Original file line number Diff line number Diff line change
@@ -1,75 +1,96 @@
<template>
<!-- Recent Threads -->
<div class="dashboard-hero">
<div class="dashboard-hero" :class="{ 'is-open': collapsedCats.indexOf(recentThreadsId) < 0, 'is-closed': collapsedCats.indexOf(recentThreadsId) > -1 }">
<div class="recent-threads">
<h1 class="title">Recent Threads</h1>

<div class="centered-text" v-if="!threads">
<h5>No recently updated threads available</h5>
<div @click="toggle" class="collapse-section">
<a :class="{ 'is-open': collapsedCats.indexOf(recentThreadsId) < 0, 'is-closed': collapsedCats.indexOf(recentThreadsId) > -1 }">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 39.84 22.63" class="icon__caretDown">
<title></title>
<g id="Layer_2" data-name="Layer 2">
<polyline class="icon" points="37.92 1.92 19.92 19.92 1.92 1.92" />
</g>
</svg>
<h1 class="title">Recent Threads</h1>
</a>
</div>

<div class="threads-container" v-if="threads">
<!-- Thread listing -->
<div class="threads-data threads-recent" v-for="thread in threads" :key="thread.id">
<div class="states">
<div class="thread-state" v-if="thread.sticky || thread.latest">
<span v-if="thread.latest" data-balloon="Unread">
<svg class="is-unread" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<title></title>
<g id="icons">
<circle cx="16" cy="16" r="16" />
</g>
</svg>
</span>
<span v-if="thread.sticky" data-balloon="Sticky">
<svg class="is-sticky" viewBox="0 0 40.68 40.68" xmlns="http://www.w3.org/2000/svg">
<path d="m40 9.92-9.24-9.19a2.5 2.5 0 0 0 -3.54 3.54l9.2 9.19a2.5 2.5 0 0 0 3.58-3.54z" />
<path
d="m12 14.52a3 3 0 0 0 -4.24 4.24l5.66 5.66-11.3 11.31-2.12 4.95 5-2.12 11.26-11.31 5.66 5.66a3 3 0 0 0 4.24-4.25z" />
<path d="m17.46 9.23h16v12h-16z" transform="matrix(.70710678 -.70710678 .70710678 .70710678 -3.31 22.46)" />
</svg>
</span>
</div>
<div class="thread-status" v-if="thread.locked || thread.poll">
<span v-if="thread.locked" data-balloon="Locked">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<title></title>
<path d="M40,21H37.5V16.48a13.5,13.5,0,0,0-27,0V21H8a2,2,0,0,0-2,2V43a2,2,0,0,0,2,2H40a2,2,0,0,0,2-2V23A2,2,0,0,0,40,21ZM15.5,16.48a8.5,8.5,0,0,1,17,0V21h-17Z"/>
</svg>
</span>
<span v-if="thread.poll" data-balloon="Includes a Poll">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<path class="cls-1" d="M42,2H6A4,4,0,0,0,2,6V42a4,4,0,0,0,4,4H42a4,4,0,0,0,4-4V6A4,4,0,0,0,42,2ZM13.75,40h-6V32h6Zm9,0h-6V22h6Zm9,0h-6V27h6Zm9,0h-6V12h6Z"/>
</svg>
</span>
</div>
</div>
<div class="title">
<router-link :class="{bold: thread.latest}" class="thread-title" :title="decode(thread.title)" :to="{ name: 'Posts', params: { threadSlug: thread.slug }, query: (thread?.post?.position > 1 ? { start: thread.post.position } : undefined) }" onclick="event.stopPropagation()"><span v-html="decode(thread.title)"></span></router-link>
<transition>
<div>
<div v-if="!threads && collapsedCats.indexOf(recentThreadsId) < 0" class="centered-text">
<h5>No recently updated threads available</h5>
</div>
<div class="user">
in
<router-link v-if="thread?.board" class="thread-board" :title="decode(thread.board.name)" :to="{ name: 'Threads', params: { boardSlug: thread.board.slug } }" onclick="event.stopPropagation()"><span v-html="decode(thread.board.name)"></span></router-link>
by
<span v-if="thread.deleted">deleted</span>
<router-link onclick="event.stopPropagation()" v-if="!thread.deleted" :to="{ path: '/profile/' + thread?.user?.username.toLowerCase() }">{{thread?.user?.username}}</router-link>
</div>
<div class="last-reply">
<div>{{humanDate(thread?.post?.created_at)}}</div>
<div class="threads-container" v-if="threads && collapsedCats.indexOf(recentThreadsId) < 0">
<!-- Thread listing -->
<div class="threads-data threads-recent" v-for="thread in threads" :key="thread.id">
<div class="states">
<div class="thread-state" v-if="thread.sticky || thread.latest">
<span v-if="thread.latest" data-balloon="Unread">
<svg class="is-unread" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<title></title>
<g id="icons">
<circle cx="16" cy="16" r="16" />
</g>
</svg>
</span>
<span v-if="thread.sticky" data-balloon="Sticky">
<svg class="is-sticky" viewBox="0 0 40.68 40.68" xmlns="http://www.w3.org/2000/svg">
<path d="m40 9.92-9.24-9.19a2.5 2.5 0 0 0 -3.54 3.54l9.2 9.19a2.5 2.5 0 0 0 3.58-3.54z" />
<path
d="m12 14.52a3 3 0 0 0 -4.24 4.24l5.66 5.66-11.3 11.31-2.12 4.95 5-2.12 11.26-11.31 5.66 5.66a3 3 0 0 0 4.24-4.25z" />
<path d="m17.46 9.23h16v12h-16z" transform="matrix(.70710678 -.70710678 .70710678 .70710678 -3.31 22.46)" />
</svg>
</span>
</div>
<div class="thread-status" v-if="thread.locked || thread.poll">
<span v-if="thread.locked" data-balloon="Locked">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<title></title>
<path d="M40,21H37.5V16.48a13.5,13.5,0,0,0-27,0V21H8a2,2,0,0,0-2,2V43a2,2,0,0,0,2,2H40a2,2,0,0,0,2-2V23A2,2,0,0,0,40,21ZM15.5,16.48a8.5,8.5,0,0,1,17,0V21h-17Z"/>
</svg>
</span>
<span v-if="thread.poll" data-balloon="Includes a Poll">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<path class="cls-1" d="M42,2H6A4,4,0,0,0,2,6V42a4,4,0,0,0,4,4H42a4,4,0,0,0,4-4V6A4,4,0,0,0,42,2ZM13.75,40h-6V32h6Zm9,0h-6V22h6Zm9,0h-6V27h6Zm9,0h-6V12h6Z"/>
</svg>
</span>
</div>
</div>
<div class="title">
<router-link :class="{bold: thread.latest}" class="thread-title" :title="decode(thread.title)" :to="{ name: 'Posts', params: { threadSlug: thread.slug }, query: (thread?.post?.position > 1 ? { start: thread.post.position } : undefined) }" onclick="event.stopPropagation()"><span v-html="decode(thread.title)"></span></router-link>
</div>
<div class="user">
in
<router-link v-if="thread?.board" class="thread-board" :title="decode(thread.board.name)" :to="{ name: 'Threads', params: { boardSlug: thread.board.slug } }" onclick="event.stopPropagation()"><span v-html="decode(thread.board.name)"></span></router-link>
by
<span v-if="thread.deleted">deleted</span>
<router-link onclick="event.stopPropagation()" v-if="!thread.deleted" :to="{ path: '/profile/' + thread?.user?.username.toLowerCase() }">{{thread?.user?.username}}</router-link>
</div>
<div class="last-reply">
<div>{{humanDate(thread?.post?.created_at)}}</div>
</div>
</div>
</div>
</div>
</div>
</transition>
</div>
</div>
</template>

<script>
import humanDate from '@/composables/filters/humanDate'
import decode from '@/composables/filters/decode'
import { reactive, toRefs } from 'vue'
export default {
props: ['threads'],
setup() { return { humanDate, decode } }
props: ['threads', 'collapsedCats'],
emits: ['toggle'],
setup(props, { emit }) {
const toggle = () => emit('toggle', { id: v.recentThreadsId })
/* View Data */
const v = reactive({
recentThreadsId: 'recent-threads-00'
})
return { ...toRefs(v), toggle, humanDate, decode }
}
}
</script>

Expand All @@ -86,6 +107,8 @@ export default {
margin-left: -50vw;
margin-right: -50vw;
&.is-closed { padding-bottom: 1rem; }
.recent-threads {
max-width: $view-maxWidth;
margin: 0 auto;
Expand Down Expand Up @@ -170,6 +193,40 @@ export default {
}
}
@include break-mobile-sm { padding: 1.5rem 1rem 0; }
.collapse-section {
@include no-select;
cursor: pointer;
a { margin-left: -1rem; }
.title { display: inline-block; margin-left: .5rem; }
.is-open {
.icon__caretDown {
transform: rotateZ(0deg);
transition: all ease-in-out 150ms;
}
}
.is-closed {
.icon__caretDown {
transform: rotateZ(-90deg);
transition: all ease-in-out 150ms;
}
}
.icon__caretDown {
margin-bottom: 3px;
width: 8px;
polyline {
fill: none;
stroke: $secondary-font-color;
stroke-linecap: round;
stroke-miterlimit: 10;
stroke-width: 7px;
}
}
}
@include break-mobile-sm {
padding: 1.5rem 2.5rem 0;
margin-top: -4.5rem;
&.is-closed { padding-bottom: 0; }
&.is-open { padding-bottom: 1rem; }
}
}
</style>
2 changes: 1 addition & 1 deletion src/views/Boards.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div class="main">
<recent-threads v-if="boardData && boardData.data && boardData.data.threads" :threads="boardData.data.threads"></recent-threads>
<recent-threads v-if="boardData && boardData.data && boardData.data.threads" :threads="boardData.data.threads" :collapsed-cats="collapsedCats" @toggle="toggleCategory"></recent-threads>

<div v-if="!loggedIn" class="dashboard-actions">
<a href="" class="button" @click.prevent="showRegister = true">Create an Account</a>
Expand Down

0 comments on commit b66a2ad

Please sign in to comment.