refactoring, horizonalAnchor prop added to Popup
This commit is contained in:
parent
0eda49ed5d
commit
54a74fa2ee
|
@ -338,7 +338,6 @@
|
|||
|
||||
.control {
|
||||
cursor: pointer;
|
||||
margin-left: 1.6rem;
|
||||
border: 0;
|
||||
|
||||
.icon {
|
||||
|
@ -356,7 +355,128 @@
|
|||
}
|
||||
}
|
||||
|
||||
.control + .control {
|
||||
margin-left: 1.6rem;
|
||||
}
|
||||
|
||||
img {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.userControl {
|
||||
align-items: baseline;
|
||||
display: flex;
|
||||
|
||||
@include font-size(1.7rem);
|
||||
|
||||
justify-content: flex-end;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
padding: divide($container-padding-x, 2);
|
||||
}
|
||||
|
||||
.userpic {
|
||||
margin-right: 0;
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.userControlItem {
|
||||
align-items: center;
|
||||
border: 2px solid #f6f6f6;
|
||||
border-radius: 100%;
|
||||
display: flex;
|
||||
height: 2.4em;
|
||||
justify-content: center;
|
||||
margin-left: divide($container-padding-x, 2);
|
||||
position: relative;
|
||||
width: 2.4em;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin-left: 1.2rem;
|
||||
}
|
||||
|
||||
.circlewrap {
|
||||
height: 23px;
|
||||
min-width: 23px;
|
||||
width: 23px;
|
||||
}
|
||||
|
||||
.button,
|
||||
a {
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
background: none;
|
||||
|
||||
&::before {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
img {
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
filter: invert(0);
|
||||
transition: filter 0.3s;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-color: #fff;
|
||||
border-radius: 100%;
|
||||
content: '';
|
||||
height: 100%;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
transition: background-color 0.3s;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
height: 20px;
|
||||
vertical-align: middle;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.textLabel {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.userControlItemInbox,
|
||||
.userControlItemSearch {
|
||||
@include media-breakpoint-down(sm) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.userControlItemWritePost {
|
||||
width: auto;
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
.icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.textLabel {
|
||||
display: inline;
|
||||
padding: 0 1.2rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&,
|
||||
a::before {
|
||||
border-radius: 1.2em;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { For, Show, createSignal, createMemo, createEffect, onMount, onCleanup } from 'solid-js'
|
||||
import Private from './Private'
|
||||
import Notifications from './Notifications'
|
||||
import { Icon } from './Icon'
|
||||
import { Modal } from './Modal'
|
||||
|
@ -9,11 +8,13 @@ import { useModalStore, showModal, useWarningsStore } from '../../stores/ui'
|
|||
import { useAuthStore } from '../../stores/auth'
|
||||
import { handleClientRouteLinkClick, router, Routes, useRouter } from '../../stores/router'
|
||||
import styles from './Header.module.scss'
|
||||
import privateStyles from './Private.module.scss'
|
||||
import { getPagePath } from '@nanostores/router'
|
||||
import { getLogger } from '../../utils/logger'
|
||||
import { clsx } from 'clsx'
|
||||
import { SharePopup } from '../Article/SharePopup'
|
||||
import { ProfilePopup } from './ProfilePopup'
|
||||
import Userpic from '../Author/Userpic'
|
||||
import type { Author } from '../../graphql/types.gen'
|
||||
|
||||
const log = getLogger('header')
|
||||
|
||||
|
@ -35,6 +36,8 @@ export const Header = (props: Props) => {
|
|||
const [fixed, setFixed] = createSignal(false)
|
||||
const [visibleWarnings, setVisibleWarnings] = createSignal(false)
|
||||
const [isSharePopupVisible, setIsSharePopupVisible] = createSignal(false)
|
||||
const [isProfilePopupVisible, setIsProfilePopupVisible] = createSignal(false)
|
||||
|
||||
// stores
|
||||
const { warnings } = useWarningsStore()
|
||||
const { session } = useAuthStore()
|
||||
|
@ -86,7 +89,8 @@ export const Header = (props: Props) => {
|
|||
classList={{
|
||||
[styles.headerFixed]: props.isHeaderFixed,
|
||||
[styles.headerScrolledTop]: !getIsScrollingBottom() && getIsScrolled(),
|
||||
[styles.headerScrolledBottom]: (getIsScrollingBottom() && getIsScrolled()) || isSharePopupVisible(),
|
||||
[styles.headerScrolledBottom]:
|
||||
(getIsScrollingBottom() && getIsScrolled() && !isProfilePopupVisible()) || isSharePopupVisible(),
|
||||
[styles.headerWithTitle]: Boolean(props.title)
|
||||
}}
|
||||
>
|
||||
|
@ -128,8 +132,15 @@ export const Header = (props: Props) => {
|
|||
</ul>
|
||||
</div>
|
||||
<div class={styles.usernav}>
|
||||
<div class={clsx(privateStyles.userControl, styles.userControl, 'col')}>
|
||||
<div class={privateStyles.userControlItem}>
|
||||
<div class={clsx(styles.userControl, styles.userControl, 'col')}>
|
||||
<div class={clsx(styles.userControlItem, styles.userControlItemWritePost)}>
|
||||
<a href="/create">
|
||||
<span class={styles.textLabel}>{t('Create post')}</span>
|
||||
<Icon name="pencil" class={styles.icon} />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class={styles.userControlItem}>
|
||||
<a href="#" onClick={handleBellIconClick}>
|
||||
<div>
|
||||
<Icon name="bell-white" counter={authorized() ? warnings().length : 1} />
|
||||
|
@ -138,7 +149,7 @@ export const Header = (props: Props) => {
|
|||
</div>
|
||||
|
||||
<Show when={visibleWarnings()}>
|
||||
<div class={clsx(privateStyles.userControlItem, 'notifications')}>
|
||||
<div class={clsx(styles.userControlItem, 'notifications')}>
|
||||
<Notifications />
|
||||
</div>
|
||||
</Show>
|
||||
|
@ -146,21 +157,42 @@ export const Header = (props: Props) => {
|
|||
<Show
|
||||
when={authorized()}
|
||||
fallback={
|
||||
<div class={clsx(privateStyles.userControlItem, 'loginbtn')}>
|
||||
<div class={clsx(styles.userControlItem, 'loginbtn')}>
|
||||
<a href="?modal=auth&mode=login" onClick={handleClientRouteLinkClick}>
|
||||
<Icon name="user-anonymous" />
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Private />
|
||||
<div class={clsx(styles.userControlItem, styles.userControlItemInbox)}>
|
||||
<a href="/inbox">
|
||||
{/*FIXME: replace with route*/}
|
||||
<div classList={{ entered: page().path === '/inbox' }}>
|
||||
<Icon name="inbox-white" counter={session()?.news?.unread || 0} />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<ProfilePopup
|
||||
onVisibilityChange={(isVisible) => {
|
||||
setIsProfilePopupVisible(isVisible)
|
||||
}}
|
||||
containerCssClass={styles.control}
|
||||
trigger={
|
||||
<div class={styles.userControlItem}>
|
||||
<button class={styles.button}>
|
||||
<div classList={{ entered: page().path === `/${session().user?.slug}` }}>
|
||||
<Userpic user={session().user as Author} class={styles.userpic} />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</Show>
|
||||
</div>
|
||||
<Show when={props.title}>
|
||||
<div class={styles.articleControls}>
|
||||
<SharePopup
|
||||
onVisibilityChange={(isVisible) => {
|
||||
console.log({ isVisible })
|
||||
setIsSharePopupVisible(isVisible)
|
||||
}}
|
||||
containerCssClass={styles.control}
|
||||
|
|
|
@ -6,9 +6,17 @@
|
|||
background: #fff;
|
||||
border: 2px solid #000;
|
||||
top: calc(100% + 8px);
|
||||
transform: translateX(-50%);
|
||||
opacity: 1;
|
||||
|
||||
&.horizontalAnchorCenter {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
&.horizontalAnchorRight {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@include font-size(1.6rem);
|
||||
|
||||
padding: 2.4rem;
|
||||
|
|
|
@ -2,15 +2,19 @@ import { createEffect, createSignal, JSX, onCleanup, onMount, Show } from 'solid
|
|||
import styles from './Popup.module.scss'
|
||||
import { clsx } from 'clsx'
|
||||
|
||||
type HorizontalAnchor = 'center' | 'right'
|
||||
|
||||
export type PopupProps = {
|
||||
containerCssClass?: string
|
||||
trigger: JSX.Element
|
||||
children: JSX.Element
|
||||
onVisibilityChange?: (isVisible) => void
|
||||
horizontalAnchor?: HorizontalAnchor
|
||||
}
|
||||
|
||||
export const Popup = (props: PopupProps) => {
|
||||
const [isVisible, setIsVisible] = createSignal(false)
|
||||
const horizontalAnchor: HorizontalAnchor = props.horizontalAnchor || 'center'
|
||||
|
||||
createEffect(() => {
|
||||
if (props.onVisibilityChange) {
|
||||
|
@ -38,12 +42,19 @@ export const Popup = (props: PopupProps) => {
|
|||
})
|
||||
|
||||
const toggle = () => setIsVisible((oldVisible) => !oldVisible)
|
||||
// class={clsx(styles.popupShare, stylesPopup.popupShare)}
|
||||
|
||||
return (
|
||||
<span class={clsx(styles.container, props.containerCssClass)} ref={container}>
|
||||
<span onClick={toggle}>{props.trigger}</span>
|
||||
<Show when={isVisible()}>
|
||||
<div class={clsx(styles.popup)}>{props.children}</div>
|
||||
<div
|
||||
class={clsx(styles.popup, {
|
||||
[styles.horizontalAnchorCenter]: horizontalAnchor === 'center',
|
||||
[styles.horizontalAnchorRight]: horizontalAnchor === 'right'
|
||||
})}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
</Show>
|
||||
</span>
|
||||
)
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
.userControl {
|
||||
align-items: baseline;
|
||||
display: flex;
|
||||
|
||||
@include font-size(1.7rem);
|
||||
|
||||
justify-content: flex-end;
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
padding: divide($container-padding-x, 2);
|
||||
}
|
||||
|
||||
.userpic {
|
||||
margin-right: 0;
|
||||
|
||||
img {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.userControlItem {
|
||||
align-items: center;
|
||||
border: 2px solid #f6f6f6;
|
||||
border-radius: 100%;
|
||||
display: flex;
|
||||
height: 2.4em;
|
||||
justify-content: center;
|
||||
margin-left: divide($container-padding-x, 2);
|
||||
position: relative;
|
||||
width: 2.4em;
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin-left: 1.2rem;
|
||||
}
|
||||
|
||||
.circlewrap {
|
||||
height: 23px;
|
||||
min-width: 23px;
|
||||
width: 23px;
|
||||
}
|
||||
|
||||
.button,
|
||||
a {
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
background: none;
|
||||
|
||||
&::before {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
img {
|
||||
filter: invert(1);
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
filter: invert(0);
|
||||
transition: filter 0.3s;
|
||||
}
|
||||
|
||||
&::before {
|
||||
background-color: #fff;
|
||||
border-radius: 100%;
|
||||
content: '';
|
||||
height: 100%;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
transition: background-color 0.3s;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
height: 20px;
|
||||
vertical-align: middle;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.textLabel {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.userControlItemWritePost {
|
||||
width: auto;
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
.icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.textLabel {
|
||||
display: inline;
|
||||
padding: 0 1.2rem;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
&,
|
||||
a::before {
|
||||
border-radius: 1.2em;
|
||||
}
|
||||
}
|
||||
|
||||
.userControlItemInbox,
|
||||
.userControlItemSearch {
|
||||
@include media-breakpoint-down(sm) {
|
||||
display: none;
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
import type { Author } from '../../graphql/types.gen'
|
||||
import Userpic from '../Author/Userpic'
|
||||
import { ProfilePopup } from './ProfilePopup'
|
||||
import { Icon } from './Icon'
|
||||
import styles from './Private.module.scss'
|
||||
import { useAuthStore } from '../../stores/auth'
|
||||
import { useRouter } from '../../stores/router'
|
||||
import { clsx } from 'clsx'
|
||||
import { createSignal } from 'solid-js'
|
||||
|
||||
export default () => {
|
||||
const { session } = useAuthStore()
|
||||
const { page } = useRouter()
|
||||
const [isProfilePopupVisible, setIsProfilePopupVisible] = createSignal(false)
|
||||
|
||||
return (
|
||||
<div class={clsx(styles.userControl, 'col')}>
|
||||
<div class={clsx(styles.userControlItem, styles.userControlItemWritePost)}>
|
||||
<a href="/create">
|
||||
<span class={styles.textLabel}>опубликовать материал</span>
|
||||
<Icon name="pencil" class={styles.icon} />
|
||||
</a>
|
||||
</div>
|
||||
<div class={clsx(styles.userControlItem, styles.userControlItemInbox)}>
|
||||
<a href="/inbox">
|
||||
{/*FIXME: replace with route*/}
|
||||
<div classList={{ entered: page().path === '/inbox' }}>
|
||||
<Icon name="inbox-white" counter={session()?.news?.unread || 0} />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<ProfilePopup
|
||||
onVisibilityChange={(isVisible) => {
|
||||
setIsProfilePopupVisible(isVisible)
|
||||
}}
|
||||
containerCssClass={styles.control}
|
||||
trigger={
|
||||
<div class={styles.userControlItem}>
|
||||
<button class={styles.button}>
|
||||
<div classList={{ entered: page().path === `/${session().user?.slug}` }}>
|
||||
<Userpic user={session().user as Author} class={styles.userpic} />
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
import styles from './Popup.module.scss'
|
||||
import { Popup, PopupProps } from './Popup'
|
||||
import { useAuthStore } from '../../stores/auth'
|
||||
import { signOut, useAuthStore } from '../../stores/auth'
|
||||
|
||||
type ProfilePopupProps = Omit<PopupProps, 'children'>
|
||||
|
||||
|
@ -8,7 +7,7 @@ export const ProfilePopup = (props: ProfilePopupProps) => {
|
|||
const { session } = useAuthStore()
|
||||
|
||||
return (
|
||||
<Popup {...props}>
|
||||
<Popup {...props} horizontalAnchor="right">
|
||||
<ul class="nodash">
|
||||
<li>
|
||||
<a href={`/${session().user?.slug}`}>Профиль</a>
|
||||
|
@ -29,7 +28,15 @@ export const ProfilePopup = (props: ProfilePopupProps) => {
|
|||
<a href="#">Настройки</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">Выйти из аккаунта</a>
|
||||
<a
|
||||
href="#"
|
||||
onClick={(event) => {
|
||||
event.preventDefault()
|
||||
signOut()
|
||||
}}
|
||||
>
|
||||
Выйти из аккаунта
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</Popup>
|
||||
|
|
|
@ -164,5 +164,6 @@
|
|||
"Almost done! Check your email.": "Почти готово! Осталось подтвердить вашу почту.",
|
||||
"We've sent you a message with a link to enter our website.": "Мы выслали вам письмо с ссылкой на почту. Перейдите по ссылке в письме, чтобы войти на сайт.",
|
||||
"Send link again": "Прислать ссылку ещё раз",
|
||||
"Link sent, check your email": "Ссылка отправлена, проверьте почту"
|
||||
"Link sent, check your email": "Ссылка отправлена, проверьте почту",
|
||||
"Create post": "Создать публикацию"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user