Add header profile drawer

This commit is contained in:
mashirozx 2021-08-08 17:10:19 +08:00
parent ebf33e97fe
commit a77e7a49bc
8 changed files with 308 additions and 53 deletions

View File

@ -5,7 +5,7 @@
define('SAKURA_VERSION', wp_get_theme()->get('Version'));
define('SAKURA_TEXT_DOMAIN', wp_get_theme()->get('TextDomain'));
define('SAKURA_DEVEPLOMENT', false);
define('SAKURA_DEVEPLOMENT', true);
define('SAKURA_DEVEPLOMENT_HOST', 'http://127.0.0.1:9000');
// PHP loaders

View File

@ -8,14 +8,18 @@
:alt="$props.data.title"
placeholder="https://via.placeholder.com/1024x768"
:draggable="false"
:ratio="9 / 16"
/>
</Link>
</div>
<div class="row__wrapper--title">
<div class="row__wrapper--date">
<span><i class="far fa-clock"></i> {{ $props.data.publistTime }}</span>
</div>
<h3 class="row__wrapper--title">
<Link :url="$props.data.link">
<span>{{ $props.data.title }}</span>
</Link>
</div>
</h3>
<div class="row__wrapper--statistics">
<div class="column__wrapper--read_count">
<span><i class="fab fa-hotjar"></i> {{ $props.data.readCount }}</span>
@ -82,11 +86,21 @@ export default defineComponent({
user-select: none;
@include polyfills.flex-gap(12px, 'column nowrap');
> * {
width: calc(100% - 24px);
width: calc(100% - 48px);
}
> .row__wrapper {
&--thumbnail {
width: 100%;
width: calc(100% - 24px);
border-radius: 10px;
overflow: hidden;
.image {
object-fit: cover;
transform: scale(1);
transition: transform 0.3s ease-in-out;
&:hover {
transform: scale(1.1);
}
}
}
&--tags {
max-height: 32px;
@ -106,6 +120,10 @@ export default defineComponent({
}
}
}
&--date {
color: #888888;
font-size: 12px;
}
&--title {
line-height: 30px;
font-size: x-large; // 24

View File

@ -82,9 +82,9 @@
</template>
</Switcher>
</div>
<div class="option inform" v-tippy="{ content: messages.privacy.email.title }">
<div class="option subscribe" v-tippy="{ content: messages.privacy.subscribe.title }">
<Switcher
v-model:checked="privacyShouldInform"
v-model:checked="privacyIsSubscribe"
positiveLabel=""
negativeLabel=""
:disableRipple="true"
@ -92,13 +92,13 @@
<template #label-positive>
<span>
<i class="fas fa-bell"></i>
{{ messages.privacy.email.positive }}
{{ messages.privacy.subscribe.positive }}
</span>
</template>
<template #label-negative>
<span>
<i class="fas fa-bell-slash"></i>
{{ messages.privacy.email.negative }}
{{ messages.privacy.subscribe.negative }}
</span>
</template>
</Switcher>
@ -174,10 +174,6 @@ export default defineComponent({
setup(props, { emit }) {
const intl = useIntl()
const messages = {
markdownTips: intl.formatMessage({
id: 'posts.comment.composer.tips.markdownSupported',
defaultMessage: 'Markdown Supported',
}),
textareaLabel: intl.formatMessage({
id: 'posts.comment.composer.content.label',
defaultMessage: 'You are a surprise that I will only meet once in my life',
@ -216,7 +212,7 @@ export default defineComponent({
defaultMessage: 'Privacy settings',
}),
markdownTooltip: intl.formatMessage({
id: 'posts.comment.composer.toolkits.preview.tooltip',
id: 'posts.comment.composer.toolkits.markdown.tooltip',
defaultMessage:
'\'<a href="https://guides.github.com/features/mastering-markdown/" target="_blank">Markdown</a>\' supported',
}),
@ -243,25 +239,25 @@ export default defineComponent({
'Whether to create secret comment that only admins and peoples mentioned can see?',
}),
positive: intl.formatMessage({
id: 'posts.comment.composer.privacy.anynomous.positive',
id: 'posts.comment.composer.privacy.visibility.positive',
defaultMessage: 'Secret',
}),
negative: intl.formatMessage({
id: 'posts.comment.composer.privacy.anynomous.negative',
id: 'posts.comment.composer.privacy.visibility.negative',
defaultMessage: 'Public',
}),
},
email: {
subscribe: {
title: intl.formatMessage({
id: 'posts.comment.composer.privacy.email.title',
id: 'posts.comment.composer.privacy.subscribe.title',
defaultMessage: 'Whether to inform you with email when receiving reply?',
}),
positive: intl.formatMessage({
id: 'posts.comment.composer.privacy.email.positive',
id: 'posts.comment.composer.privacy.subscribe.positive',
defaultMessage: 'Subscribe',
}),
negative: intl.formatMessage({
id: 'posts.comment.composer.privacy.email.negative',
id: 'posts.comment.composer.privacy.subscribe.negative',
defaultMessage: 'Unsubscribe',
}),
},
@ -275,7 +271,7 @@ export default defineComponent({
const privacyIsPrivate = ref(false)
const privacyIsAnynomous = ref(false)
const privacyShouldInform = ref(true)
const privacyIsSubscribe = ref(true)
// TODO: debounce
const handleSubmitEvent = () => {
@ -365,7 +361,7 @@ export default defineComponent({
handleTogglePrivacyOptionsEvent,
privacyIsPrivate,
privacyIsAnynomous,
privacyShouldInform,
privacyIsSubscribe,
}
},
})

View File

@ -1,5 +1,5 @@
<template>
<div :class="['image__container', state]">
<div :class="['image__container', state]" :ref="setContainerRef" :style="{ height: imageHeight }">
<img
:class="['image', state]"
:src="$props.src"
@ -20,7 +20,7 @@
<script lang="ts">
import { defineComponent, computed } from 'vue'
import { useState } from '@/hooks'
import { useState, useResizeObserver, useElementRef } from '@/hooks'
import gravatar from '@/utils/gravatar'
export default defineComponent({
@ -31,6 +31,7 @@ export default defineComponent({
avatar: { type: Boolean, default: false },
alt: String,
draggable: { type: Boolean, default: false },
ratio: { type: Number, default: NaN },
},
setup(props, { emit }) {
const [state, setState] = useState('loading')
@ -53,11 +54,24 @@ export default defineComponent({
emit('load', event)
}
const [containerRef, setContainerRef] = useElementRef()
const containerSize = useResizeObserver(containerRef)
const imageHeight = computed(() => {
if (!isNaN(props.ratio) && props.ratio >= 0) {
return `${containerSize.value.width * props.ratio}px`
} else {
return '100%'
}
})
return {
placeholderImage,
handleError,
handleLoad,
state,
setContainerRef,
imageHeight,
}
},
})

View File

@ -5,9 +5,12 @@
<router-link v-else-if="to" :to="to">
<slot></slot>
</router-link>
<a v-else href="https://google.com" target="_blank">
<a v-else-if="hyperlink" href="hyperlink" target="_blank">
<slot></slot>
</a>
<span v-else>
<slot></slot>
</span>
</template>
<script lang="ts">
@ -46,7 +49,15 @@ export default defineComponent({
}
})
return { to }
const hyperlink = computed(() => {
if (props.url === '' || props.url === '#') {
return false
} else {
return props.url
}
})
return { to, hyperlink }
},
})
</script>

View File

@ -2,13 +2,19 @@
<div class="header__container mdc-elevation--z4">
<div class="header__content">
<div class="logo__wrapper">
<img
class="logo"
:src="logo"
alt="logo"
draggable="false"
@load="computeShouldHideNavItemList"
/>
<Ripple>
<Link :to="{ name: 'Home' }">
<div class="logo__container">
<img
class="logo"
:src="logo"
alt="logo"
draggable="false"
@load="computeShouldHideNavItemList"
/>
</div>
</Link>
</Ripple>
</div>
<div class="nav__wrapper" :ref="setNavBarWrapperRef" @resize="handleNavBarWrapperResizeEvent">
<div class="nav__ul nav__ul--parent" :ref="setNavBarItemRefs">
@ -67,7 +73,32 @@
</div>
</div>
<div class="profile__wrapper">
<img class="avatar" :src="avatar" alt="avatar" />
<Ripple>
<div class="image__wrapper">
<img class="avatar" :src="avatar" alt="avatar" />
</div>
</Ripple>
<div class="drop-down__wrapper">
<div class="ul mdc-elevation--z8">
<div class="content-logined" v-if="logined">logined</div>
<div class="content-unsigned" v-else>unsigned</div>
<div class="li" v-for="(item, index) in languageOptions" :key="index">
<NavItem :context="item.title" :prefix="item.icon" :url="item.url"></NavItem>
<div class="child__ul language mdc-elevation--z8" v-if="item.child.length > 0">
<div class="child__li" v-for="(child, childIndex) in item.child" :key="childIndex">
<NavItem :context="child.title" :prefix="child.icon" :url="child.url"></NavItem>
</div>
</div>
</div>
<div
class="li"
v-for="(item, index) in logined ? loginedOptions : unsignedOptions"
:key="index"
>
<NavItem :context="item.title" :prefix="item.icon" :url="item.url"></NavItem>
</div>
</div>
</div>
</div>
</div>
</div>
@ -87,9 +118,10 @@ import { init } from '@/store'
import sakuraOptions from '@/utils/sakuraOptions'
import camelcaseKeys from 'camelcase-keys'
import NavItem from '@/layouts/components/header/NavItem.vue'
import Ripple from '@/components/ripple/Ripple.vue'
export default defineComponent({
components: { NavItem },
components: { NavItem, Ripple },
setup() {
const avatar = 'https://view.moezx.cc/images/2021/06/13/d6b010a378d392d4633008b915f98ab1.md.png'
const logo = sakuraOptions['basic.site.logo'][0]?.url || 'https://v3.vuejs.org/logo.png'
@ -142,6 +174,33 @@ export default defineComponent({
return items
})
const unsignedOptions = [
{ title: 'Register', icon: 'fas fa-user-plus', url: '' },
{ title: 'Sign in', icon: 'fas fa-sign-out-alt', url: '' },
]
const loginedOptions = [
{ title: 'User Center', icon: 'fas fa-user', url: '' },
{ title: 'Sign out', icon: 'fas fa-sign-out-alt', url: '' },
]
const languageOptions = [
{
title: 'Language',
icon: 'fas fa-globe',
url: '',
child: [
{ title: '简体中文', value: 'zh-CN' },
{ title: '繁體中文', value: 'zh-HK' },
{ title: 'English', value: 'en' },
{ title: 'Español', value: 'es' },
{ title: 'Deutsch', value: 'de' },
{ title: 'Français', value: 'fr' },
{ title: 'Русский', value: 'ru' },
{ title: '日本語', value: 'ja' },
],
},
]
const logined = ref(true)
return {
navItems,
setNavBarWrapperRef,
@ -153,6 +212,10 @@ export default defineComponent({
logo,
initState,
useMDCRipple,
logined,
loginedOptions,
unsignedOptions,
languageOptions,
}
},
})
@ -168,17 +231,23 @@ export default defineComponent({
align-items: center;
background: #ffffff;
> .header__content {
width: calc(100% - 48px);
// width: calc(100% - 48px);
width: 100%;
height: 48px;
display: flex;
flex-flow: row nowrap;
> .logo__wrapper {
flex: 0 0 auto;
display: flex;
justify-content: center;
align-items: center;
> .logo {
height: 32px;
height: 100%;
.logo__container {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.logo {
height: 32px;
padding: 0 24px;
}
}
}
> .nav__wrapper {
@ -186,7 +255,7 @@ export default defineComponent({
width: 100%;
display: flex;
flex-flow: row nowrap;
padding: 0 24px;
// padding: 0 24px;
.nav__ul {
&.hide {
position: absolute;
@ -309,14 +378,85 @@ export default defineComponent({
> .profile__wrapper {
flex: 0 0 auto;
display: flex;
justify-content: center;
align-items: center;
> .avatar {
height: 32px;
width: 32px;
object-fit: cover;
border-radius: 50%;
height: 100%;
position: relative;
.image__wrapper {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
padding: 0 24px;
> .avatar {
height: 32px;
width: 32px;
object-fit: cover;
border-radius: 50%;
}
}
.drop-down__wrapper {
position: absolute;
top: 48px;
right: 0;
width: auto;
z-index: -1;
pointer-events: none;
visibility: hidden;
transform: translate(0, -100%);
// pointer-events: all;
// cursor: pointer;
// visibility: visible;
// transform: translate(0, 0%);
transition: all 0.2s ease-in-out;
.ul {
position: relative;
padding: 16px 0;
background: #ffffff;
border-radius: 0 0 5px 5px;
> .li {
height: 48px;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
position: relative;
> .child__ul {
position: absolute;
top: 0;
left: 0;
z-index: -1;
padding: 16px 0;
transform: translate(-100%, -16px) scale(0, 0);
transform-origin: right (16px + math.div(48px, 2));
background: #ffffff;
border-radius: 5px;
width: auto;
transition: all 0.2s ease-in-out;
> .child__li {
height: 48px;
display: flex;
flex-flow: row nowrap;
justify-content: flex-start;
align-items: center;
}
}
&:hover {
> .child__ul {
transform: translate(-100%, -16px) scale(1, 1);
}
}
}
}
::v-deep() {
.link__container .nav-item__container .nav-item__content {
justify-content: flex-start;
}
}
}
&:hover .drop-down__wrapper {
pointer-events: all;
cursor: pointer;
visibility: visible;
transform: translate(0, 0%);
}
}
}

View File

@ -10,7 +10,13 @@
"messages.admin.uplicateUrls": "Duplicate URLs",
"messages.comment.submit.error": "Comment post failure.",
"messages.comment.submit.success": "Comment post successfully.",
"messages.commentList.cache.updateError": "Opps! Something went wrong when updating comment list.",
"messages.commentList.cache.updateSuccess": "Comment list updated.",
"messages.commentList.cache.updating": "Updating the latest comment list...",
"messages.commentList.title.commentCount": "{commentCount, plural, =0 {Be the first one to leave a comment!} =1 {One comment} other {{commentCount, number, ::compact-short} Comments}}",
"messages.commentList.title.heading": "Comments",
"messages.commonMessages.javascriptErrorTitle": "Opps, something when wrong!",
"messages.content.status.errorLoadingComponent": "Something went wrong when loading this component.",
"messages.popup.close": "Close",
"messages.popup.dismiss": "Dismiss",
"messages.popup.showDetails": "Show details",
@ -69,8 +75,21 @@
"posts.comment.composer.authorUrl.label": "Link",
"posts.comment.composer.captcha.toggleButton": "Captcha",
"posts.comment.composer.content.label": "You are a surprise that I will only meet once in my life",
"posts.comment.composer.privacy.anynomous.negative": "Autonym",
"posts.comment.composer.privacy.anynomous.positive": "Anynomous",
"posts.comment.composer.privacy.anynomous.title": "Whether to comment as an anynomous user?",
"posts.comment.composer.privacy.subscribe.negative": "Unsubscribe",
"posts.comment.composer.privacy.subscribe.positive": "Subscribe",
"posts.comment.composer.privacy.subscribe.title": "Whether to inform you with email when receiving reply?",
"posts.comment.composer.privacy.visibility.negative": "Public",
"posts.comment.composer.privacy.visibility.positive": "Secret",
"posts.comment.composer.privacy.visibility.title": "Whether to create secret comment that only admins and peoples mentioned can see?",
"posts.comment.composer.submit.button": "Submit",
"posts.comment.composer.tips.markdownSupported": "Markdown Supported",
"posts.comment.composer.toolkits.emoji.tooltip": "Insert emoji",
"posts.comment.composer.toolkits.image.tooltip": "Attach image",
"posts.comment.composer.toolkits.markdown.tooltip": "'<a href=\"https://guides.github.com/features/mastering-markdown/\" target=\"_blank\">Markdown</a>' supported",
"posts.comment.composer.toolkits.preview.tooltip": "'<i class=\"fab fa-markdown\"></i>' Markdown preview",
"posts.comment.composer.toolkits.privacy.tooltip": "Privacy settings",
"posts.commentCount": "{commentCount, plural, =0 {No comment} =1 {One comment} other {{commentCount, number, ::compact-short} Comments}}",
"posts.postTimeOn.brief": "{publistTimeDate, date, long}",
"posts.postTimeOn.full": "Post on {publistTimeDate, date, long}",

View File

@ -32,9 +32,27 @@
"messages.comment.submit.success": {
"defaultMessage": "Comment post successfully."
},
"messages.commentList.cache.updateError": {
"defaultMessage": "Opps! Something went wrong when updating comment list."
},
"messages.commentList.cache.updateSuccess": {
"defaultMessage": "Comment list updated."
},
"messages.commentList.cache.updating": {
"defaultMessage": "Updating the latest comment list..."
},
"messages.commentList.title.commentCount": {
"defaultMessage": "{commentCount, plural, =0 {Be the first one to leave a comment!} =1 {One comment} other {{commentCount, number, ::compact-short} Comments}}"
},
"messages.commentList.title.heading": {
"defaultMessage": "Comments"
},
"messages.commonMessages.javascriptErrorTitle": {
"defaultMessage": "Opps, something when wrong!"
},
"messages.content.status.errorLoadingComponent": {
"defaultMessage": "Something went wrong when loading this component."
},
"messages.popup.close": {
"defaultMessage": "Close"
},
@ -209,11 +227,50 @@
"posts.comment.composer.content.label": {
"defaultMessage": "You are a surprise that I will only meet once in my life"
},
"posts.comment.composer.privacy.anynomous.negative": {
"defaultMessage": "Autonym"
},
"posts.comment.composer.privacy.anynomous.positive": {
"defaultMessage": "Anynomous"
},
"posts.comment.composer.privacy.anynomous.title": {
"defaultMessage": "Whether to comment as an anynomous user?"
},
"posts.comment.composer.privacy.subscribe.negative": {
"defaultMessage": "Unsubscribe"
},
"posts.comment.composer.privacy.subscribe.positive": {
"defaultMessage": "Subscribe"
},
"posts.comment.composer.privacy.subscribe.title": {
"defaultMessage": "Whether to inform you with email when receiving reply?"
},
"posts.comment.composer.privacy.visibility.negative": {
"defaultMessage": "Public"
},
"posts.comment.composer.privacy.visibility.positive": {
"defaultMessage": "Secret"
},
"posts.comment.composer.privacy.visibility.title": {
"defaultMessage": "Whether to create secret comment that only admins and peoples mentioned can see?"
},
"posts.comment.composer.submit.button": {
"defaultMessage": "Submit"
},
"posts.comment.composer.tips.markdownSupported": {
"defaultMessage": "Markdown Supported"
"posts.comment.composer.toolkits.emoji.tooltip": {
"defaultMessage": "Insert emoji"
},
"posts.comment.composer.toolkits.image.tooltip": {
"defaultMessage": "Attach image"
},
"posts.comment.composer.toolkits.markdown.tooltip": {
"defaultMessage": "'<a href=\"https://guides.github.com/features/mastering-markdown/\" target=\"_blank\">Markdown</a>' supported"
},
"posts.comment.composer.toolkits.preview.tooltip": {
"defaultMessage": "'<i class=\"fab fa-markdown\"></i>' Markdown preview"
},
"posts.comment.composer.toolkits.privacy.tooltip": {
"defaultMessage": "Privacy settings"
},
"posts.commentCount": {
"defaultMessage": "{commentCount, plural, =0 {No comment} =1 {One comment} other {{commentCount, number, ::compact-short} Comments}}"