Create sidebar layout component

This commit is contained in:
silverpill 2022-07-29 18:12:10 +00:00
parent 4876b7b439
commit b0a5fac22a
17 changed files with 171 additions and 159 deletions

View file

@ -20,7 +20,7 @@
</div> </div>
</div> </div>
</header> </header>
<router-view :key="route.fullPath" :class="{ wide: isPublicPage() }" /> <router-view :key="route.fullPath" />
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View file

@ -0,0 +1,22 @@
<template>
<div id="main" :class="{ wide: currentUser === null }">
<div class="content">
<slot name="content"></slot>
</div>
<sidebar></sidebar>
</div>
</template>
<script setup lang="ts">
import { $ } from "vue/macros"
import { useCurrentUser } from "@/store/user"
import Sidebar from "./Sidebar.vue"
const { currentUser } = $(useCurrentUser())
</script>
<style scoped lang="scss">
@import "../styles/layout";
@import "../styles/theme";
</style>

View file

@ -1,17 +1,16 @@
<template> <template>
<div id="main"> <sidebar-layout>
<div class="content about" v-if="instance"> <template #content v-if="instance">
<h1>{{ instance.title }}</h1> <h1>{{ instance.title }}</h1>
<div class="description static-text" v-html="renderMarkdown(instance.description)"></div> <div class="description static-text" v-html="renderMarkdown(instance.description)"></div>
</div> </template>
<sidebar></sidebar> </sidebar-layout>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { $ } from "vue/macros" import { $ } from "vue/macros"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import { useInstanceInfo } from "@/store/instance" import { useInstanceInfo } from "@/store/instance"
import { renderMarkdown } from "@/utils/markdown" import { renderMarkdown } from "@/utils/markdown"

View file

@ -1,5 +1,5 @@
<template> <template>
<static-page v-if="instance"> <static-page v-if="instance" class="wide">
<template #heading>{{ instance.title }}</template> <template #heading>{{ instance.title }}</template>
<template #text> <template #text>
<div v-html="renderMarkdown(instance.description)"></div> <div v-html="renderMarkdown(instance.description)"></div>

View file

@ -1,5 +1,5 @@
<template> <template>
<static-page> <static-page class="wide">
<template #heading>Ethereum</template> <template #heading>Ethereum</template>
<template #text> <template #text>
<div v-html="text"></div> <div v-html="text"></div>

View file

@ -1,11 +1,10 @@
<template> <template>
<div id="main"> <sidebar-layout>
<div class="content posts"> <template #content>
<post-editor @post-created="insertPost"></post-editor> <post-editor @post-created="insertPost"></post-editor>
<post-list :posts="posts" @load-next-page="loadNextPage"></post-list> <post-list :posts="posts" @load-next-page="loadNextPage"></post-list>
</div> </template>
<sidebar></sidebar> </sidebar-layout>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -15,7 +14,7 @@ import { $ref } from "vue/macros"
import { Post, getHomeTimeline } from "@/api/posts" import { Post, getHomeTimeline } from "@/api/posts"
import PostEditor from "@/components/PostEditor.vue" import PostEditor from "@/components/PostEditor.vue"
import PostList from "@/components/PostList.vue" import PostList from "@/components/PostList.vue"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"
const { ensureAuthToken } = useCurrentUser() const { ensureAuthToken } = useCurrentUser()

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="landing-page"> <div class="landing-page wide">
<div class="instance-group"> <div class="instance-group">
<div v-if="instance" class="instance-info"> <div v-if="instance" class="instance-info">
<h1 class="instance-title">{{ instance.title }}</h1> <h1 class="instance-title">{{ instance.title }}</h1>

View file

@ -1,6 +1,6 @@
<template> <template>
<div id="main"> <sidebar-layout>
<div class="content"> <template #content>
<div <div
class="notification" class="notification"
v-for="(notification, index) in notifications" v-for="(notification, index) in notifications"
@ -84,9 +84,8 @@
> >
Show more notifications Show more notifications
</button> </button>
</div> </template>
<sidebar></sidebar> </sidebar-layout>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -97,7 +96,7 @@ import { updateNotificationMarker } from "@/api/markers"
import { getNotifications, Notification } from "@/api/notifications" import { getNotifications, Notification } from "@/api/notifications"
import Avatar from "@/components/Avatar.vue" import Avatar from "@/components/Avatar.vue"
import Post from "@/components/Post.vue" import Post from "@/components/Post.vue"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import { useInstanceInfo } from "@/store/instance" import { useInstanceInfo } from "@/store/instance"
import { useNotifications } from "@/store/notifications" import { useNotifications } from "@/store/notifications"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"

View file

@ -1,9 +1,9 @@
<template> <template>
<div id="main" ref="containerRef"> <sidebar-layout>
<div v-if="!isLoading && thread.length === 0" class="content not-found"> <template #content>
Not found <div v-if="!isLoading && thread.length === 0" class="not-found">
</div> Not found
<div v-else class="content posts"> </div>
<post <post
v-for="(post, index) in thread" v-for="(post, index) in thread"
:key="post.id" :key="post.id"
@ -15,9 +15,8 @@
@comment-created="onCommentCreated(index, $event)" @comment-created="onCommentCreated(index, $event)"
@post-deleted="onPostDeleted(index)" @post-deleted="onPostDeleted(index)"
></post> ></post>
</div> </template>
<sidebar></sidebar> </sidebar-layout>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -27,7 +26,7 @@ import { useRoute } from "vue-router"
import { Post as PostObject, getPostContext } from "@/api/posts" import { Post as PostObject, getPostContext } from "@/api/posts"
import Post from "@/components/Post.vue" import Post from "@/components/Post.vue"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"
const route = useRoute() const route = useRoute()
@ -37,7 +36,6 @@ let selectedId = $ref(route.params.postId as string)
let highlightedId = $ref<string | null>(null) let highlightedId = $ref<string | null>(null)
let thread = $ref<PostObject[]>([]) let thread = $ref<PostObject[]>([])
let isLoading = $ref(true) let isLoading = $ref(true)
const containerRef = $ref<HTMLElement | null>(null)
const loader = $ref(getPostContext(authToken, selectedId)) const loader = $ref(getPostContext(authToken, selectedId))
onMounted(async () => { onMounted(async () => {
@ -58,11 +56,12 @@ onMounted(async () => {
}) })
function scrollTo(postId: string, options: any = {}) { function scrollTo(postId: string, options: any = {}) {
if (containerRef === null) { const container = document.getElementById("main")
if (!container) {
return return
} }
const containerOffset = containerRef.offsetTop // sticky header height or top margin const containerOffset = container.offsetTop // sticky header height or top margin
const postElem: HTMLElement | null = containerRef.querySelector(`div[data-post-id="${postId}"]`) const postElem: HTMLElement | null = container.querySelector(`div[data-post-id="${postId}"]`)
if (postElem === null) { if (postElem === null) {
return return
} }

View file

@ -1,5 +1,5 @@
<template> <template>
<div v-if="post && token" class="post-overlay"> <div v-if="post && token" class="post-overlay wide">
<div v-if="canGoBack()" class="back-btn-wrapper"> <div v-if="canGoBack()" class="back-btn-wrapper">
<a class="back-btn" title="Back" @click="goBack()"> <a class="back-btn" title="Back" @click="goBack()">
<img :src="require('@/assets/feather/arrow-left.svg')"> <img :src="require('@/assets/feather/arrow-left.svg')">

View file

@ -1,6 +1,6 @@
<template> <template>
<div id="main" v-if="profile"> <sidebar-layout v-if="profile">
<div class="content posts"> <template #content>
<div class="profile-block"> <div class="profile-block">
<div class="profile-header"> <div class="profile-header">
<img v-if="profile.header" :src="profile.header"> <img v-if="profile.header" :src="profile.header">
@ -180,9 +180,8 @@
:key="profile.id" :key="profile.id"
></profile-list-item> ></profile-list-item>
</template> </template>
</div> </template>
<sidebar></sidebar> </sidebar-layout>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -210,7 +209,7 @@ import {
import Avatar from "@/components/Avatar.vue" import Avatar from "@/components/Avatar.vue"
import PostList from "@/components/PostList.vue" import PostList from "@/components/PostList.vue"
import ProfileListItem from "@/components/ProfileListItem.vue" import ProfileListItem from "@/components/ProfileListItem.vue"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import { BACKEND_URL } from "@/constants" import { BACKEND_URL } from "@/constants"
import { useInstanceInfo } from "@/store/instance" import { useInstanceInfo } from "@/store/instance"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"

View file

@ -1,14 +1,16 @@
<template> <template>
<div id="main"> <sidebar-layout>
<div class="content profile-list"> <template #content>
<router-link <div class="profile-grid">
v-for="profile in profiles" <router-link
class="profile-list-item" v-for="profile in profiles"
:to="{ name: 'profile', params: { profileId: profile.id }}" class="profile-list-item"
:key="profile.id" :to="{ name: 'profile', params: { profileId: profile.id }}"
> :key="profile.id"
<profile-card :profile="profile" :compact="false"></profile-card> >
</router-link> <profile-card :profile="profile" :compact="false"></profile-card>
</router-link>
</div>
<button <button
v-if="isPageFull()" v-if="isPageFull()"
class="btn secondary next-btn" class="btn secondary next-btn"
@ -16,9 +18,8 @@
> >
Show more profiles Show more profiles
</button> </button>
</div> </template>
<sidebar></sidebar> </sidebar-layout>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -28,7 +29,7 @@ import { $ref } from "vue/macros"
import { PAGE_SIZE } from "@/api/common" import { PAGE_SIZE } from "@/api/common"
import { Profile, getProfiles } from "@/api/users" import { Profile, getProfiles } from "@/api/users"
import ProfileCard from "@/components/ProfileCard.vue" import ProfileCard from "@/components/ProfileCard.vue"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"
const { ensureAuthToken } = useCurrentUser() const { ensureAuthToken } = useCurrentUser()
@ -61,7 +62,7 @@ async function loadNextPage() {
@import "../styles/layout"; @import "../styles/layout";
@import "../styles/theme"; @import "../styles/theme";
.profile-list { .profile-grid {
display: grid; display: grid;
gap: $block-outer-padding; gap: $block-outer-padding;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));

View file

@ -1,84 +1,85 @@
<template> <template>
<div id="main"> <sidebar-layout>
<form class="content settings" @submit.prevent="save()"> <template #content>
<h1>Edit profile</h1> <form @submit.prevent="save()">
<div class="input-group"> <h1>Edit profile</h1>
<label for="display-name">Display name</label> <div class="input-group">
<input id="display-name" v-model.trim="form.display_name"> <label for="display-name">Display name</label>
</div> <input id="display-name" v-model.trim="form.display_name">
<div class="input-group"> </div>
<label for="bio">Bio</label> <div class="input-group">
<textarea <label for="bio">Bio</label>
id="bio" <textarea
ref="bioInputRef" id="bio"
:value="form.note_source || ''" ref="bioInputRef"
@input="onBioUpdate($event)" :value="form.note_source || ''"
></textarea> @input="onBioUpdate($event)"
</div> ></textarea>
<div class="image-upload-group"> </div>
<profile-card :profile="profilePreview" :compact="true"></profile-card> <div class="image-upload-group">
<div class="image-upload-inputs"> <profile-card :profile="profilePreview" :compact="true"></profile-card>
<div class="input-group"> <div class="image-upload-inputs">
<label for="avatar">Avatar</label> <div class="input-group">
<input <label for="avatar">Avatar</label>
type="file" <input
id="avatar" type="file"
accept="image/*" id="avatar"
@change="onFilePicked('avatar', $event)" accept="image/*"
> @change="onFilePicked('avatar', $event)"
</div> >
<div class="input-group"> </div>
<label for="banner">Banner</label> <div class="input-group">
<input <label for="banner">Banner</label>
type="file" <input
id="banner" type="file"
accept="image/*" id="banner"
@change="onFilePicked('header', $event)" accept="image/*"
> @change="onFilePicked('header', $event)"
>
</div>
</div> </div>
</div> </div>
</div> <div class="extra-fields input-group">
<div class="extra-fields input-group"> <label>
<label> Additional info
Additional info <div class="sub-label">You can have up to {{ extraFieldMaxCount }} items displayed as a table on your profile</div>
<div class="sub-label">You can have up to {{ extraFieldMaxCount }} items displayed as a table on your profile</div> </label>
</label> <div
<div v-for="(field, index) in form.fields_attributes"
v-for="(field, index) in form.fields_attributes" :key="index"
:key="index" class="extra-field"
class="extra-field" :class="{'error': !isValidExtraField(index)}"
:class="{'error': !isValidExtraField(index)}"
>
<input v-model.trim="field.name" placeholder="Label">
<input
:value="field.value_source"
@input="onExtraFieldUpdate(field, $event)"
placeholder="Content"
> >
<a <input v-model.trim="field.name" placeholder="Label">
class="remove-extra-field" <input
title="Remove item" :value="field.value_source"
@click="removeExtraField(index)" @input="onExtraFieldUpdate(field, $event)"
placeholder="Content"
>
<a
class="remove-extra-field"
title="Remove item"
@click="removeExtraField(index)"
>
<img :src="require('@/assets/feather/x-circle.svg')">
</a>
</div>
<button
v-if="form.fields_attributes.length <= extraFieldMaxCount"
type="button"
class="add-extra-field"
@click="addExtraField()"
> >
<img :src="require('@/assets/feather/x-circle.svg')"> <img :src="require('@/assets/feather/plus-circle.svg')">
</a> Add new item
</button>
</div> </div>
<button <button type="submit" class="btn" :disabled="!isFormValid()">
v-if="form.fields_attributes.length <= extraFieldMaxCount" Save
type="button"
class="add-extra-field"
@click="addExtraField()"
>
<img :src="require('@/assets/feather/plus-circle.svg')">
Add new item
</button> </button>
</div> </form>
<button type="submit" class="btn" :disabled="!isFormValid()"> </template>
Save </sidebar-layout>
</button>
</form>
<sidebar></sidebar>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -93,7 +94,7 @@ import {
updateProfile, updateProfile,
} from "@/api/users" } from "@/api/users"
import ProfileCard from "@/components/ProfileCard.vue" import ProfileCard from "@/components/ProfileCard.vue"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"
import { setupAutoResize } from "@/utils/autoresize" import { setupAutoResize } from "@/utils/autoresize"
import { renderMarkdownLite } from "@/utils/markdown" import { renderMarkdownLite } from "@/utils/markdown"

View file

@ -1,10 +1,9 @@
<template> <template>
<div id="main"> <sidebar-layout>
<div class="content posts"> <template #content>
<post-list :posts="posts" @load-next-page="loadNextPage"></post-list> <post-list :posts="posts" @load-next-page="loadNextPage"></post-list>
</div> </template>
<sidebar></sidebar> </sidebar-layout>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -13,7 +12,7 @@ import { $ref } from "vue/macros"
import { Post, getPublicTimeline } from "@/api/posts" import { Post, getPublicTimeline } from "@/api/posts"
import PostList from "@/components/PostList.vue" import PostList from "@/components/PostList.vue"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"
const { ensureAuthToken } = useCurrentUser() const { ensureAuthToken } = useCurrentUser()
@ -30,6 +29,3 @@ async function loadNextPage(maxId: string) {
posts.push(...nextPage) posts.push(...nextPage)
} }
</script> </script>
<style scoped lang="scss">
</style>

View file

@ -1,6 +1,6 @@
<template> <template>
<div id="main"> <sidebar-layout>
<div class="content search-result-group"> <template #content>
<loader v-if="isLoading"></loader> <loader v-if="isLoading"></loader>
<div v-if="!isLoading" class="search-message"> <div v-if="!isLoading" class="search-message">
<template v-if="errorMessage">{{ errorMessage }}</template> <template v-if="errorMessage">{{ errorMessage }}</template>
@ -20,9 +20,8 @@
:key="post.id" :key="post.id"
></post> ></post>
</div> </div>
</div> </template>
<sidebar></sidebar> </sidebar-layout>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -36,7 +35,7 @@ import { Profile } from "@/api/users"
import Loader from "@/components/Loader.vue" import Loader from "@/components/Loader.vue"
import Post from "@/components/Post.vue" import Post from "@/components/Post.vue"
import ProfileListItem from "@/components/ProfileListItem.vue" import ProfileListItem from "@/components/ProfileListItem.vue"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"
const route = useRoute() const route = useRoute()

View file

@ -1,13 +1,12 @@
<template> <template>
<div id="main" v-if="profile && isLocalUser()"> <sidebar-layout v-if="profile && isLocalUser()">
<div class="content"> <template #content>
<component <component
:is="isCurrentUser() ? SubscriptionSetup : Subscription" :is="isCurrentUser() ? SubscriptionSetup : Subscription"
:profile="profile" :profile="profile"
></component> ></component>
</div> </template>
<sidebar></sidebar> </sidebar-layout>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -16,7 +15,7 @@ import { $, $ref } from "vue/macros"
import { useRoute } from "vue-router" import { useRoute } from "vue-router"
import { getProfile, Profile } from "@/api/users" import { getProfile, Profile } from "@/api/users"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import Subscription from "@/components/Subscription.vue" import Subscription from "@/components/Subscription.vue"
import SubscriptionSetup from "@/components/SubscriptionSetup.vue" import SubscriptionSetup from "@/components/SubscriptionSetup.vue"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"

View file

@ -1,13 +1,12 @@
<template> <template>
<div id="main"> <sidebar-layout>
<div class="content posts"> <template #content>
<post-list <post-list
:posts="posts" :posts="posts"
@load-next-page="loadNextPage" @load-next-page="loadNextPage"
></post-list> ></post-list>
</div> </template>
<sidebar></sidebar> </sidebar-layout>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@ -16,7 +15,7 @@ import { useRoute } from "vue-router"
import { Post, getTagTimeline } from "@/api/posts" import { Post, getTagTimeline } from "@/api/posts"
import PostList from "@/components/PostList.vue" import PostList from "@/components/PostList.vue"
import Sidebar from "@/components/Sidebar.vue" import SidebarLayout from "@/components/SidebarLayout.vue"
import { useCurrentUser } from "@/store/user" import { useCurrentUser } from "@/store/user"
const route = useRoute() const route = useRoute()