diff --git a/components/AccountModal/index.scss b/components/AccountModal/index.scss new file mode 100644 index 00000000..81371cce --- /dev/null +++ b/components/AccountModal/index.scss @@ -0,0 +1,160 @@ +.Account.Dialog { + display: flex; + flex-direction: column; + gap: $unit * 2; + width: $unit * 60; + + form { + display: flex; + flex-direction: column; + gap: $unit * 2; + + .Switch { + $height: 34px; + background: $grey-70; + border-radius: $height / 2; + border: none; + position: relative; + width: 58px; + height: $height; + + &:focus { + box-shadow: 0 0 0 2px $grey-00; + } + + &[data-state="checked"] { + background: $grey-00; + } + } + + .Thumb { + background: white; + border-radius: 13px; + display: block; + height: 26px; + width: 26px; + transition: transform 100ms; + transform: translateX(-1px); + + &:hover { + cursor: pointer; + } + + &[data-state="checked"] { + background: white; + transform: translateX(21px); + } + } + + .Button { + font-size: $font-regular; + padding: ($unit * 1.5) ($unit * 2); + margin-top: $unit * 2; + width: 100%; + + &.btn-disabled { + background: $grey-90; + color: $grey-70; + cursor: not-allowed; + } + + &:not(.btn-disabled) { + background: $grey-90; + color: $grey-40; + + &:hover { + background: $grey-80; + } + } + } + + .field { + align-items: center; + display: flex; + flex-direction: row; + gap: $unit * 2; + + select { + background: no-repeat url('/icons/ArrowDark.svg'), $grey-90; + background-position-y: center; + background-position-x: 95%; + margin: 0; + width: 240px; + } + + .left { + display: flex; + flex-direction: column; + flex-grow: 1; + gap: $unit / 2; + + label { + color: $grey-00; + font-size: $font-regular; + } + + p { + color: $grey-60; + font-size: $font-small; + line-height: 1.1; + max-width: 300px; + } + } + + .preview { + $diameter: 48px; + background-color: $grey-90; + border-radius: 999px; + height: $diameter; + width: $diameter; + + img { + height: $diameter; + width: $diameter; + } + + &.fire { + background: $fire-bg-light; + } + + &.water { + background: $water-bg-light; + } + + &.wind { + background: $wind-bg-light; + } + + &.earth { + background: $earth-bg-light; + } + + &.dark { + background: $dark-bg-light; + } + + &.light { + background: $light-bg-light; + } + } + } + + section { + margin-bottom: $unit; + + h2 { + margin-bottom: $unit * 3; + } + } + } + + .DialogDescription { + font-size: $font-regular; + line-height: 1.24; + margin-bottom: $unit; + + &:last-of-type { + margin-bottom: 0; + } + } +} diff --git a/components/AccountModal/index.tsx b/components/AccountModal/index.tsx new file mode 100644 index 00000000..3d13c347 --- /dev/null +++ b/components/AccountModal/index.tsx @@ -0,0 +1,158 @@ +import React, { useEffect, useState } from 'react' +import { useCookies } from 'react-cookie' +import { useSnapshot } from 'valtio' + +import * as Dialog from '@radix-ui/react-dialog' +import * as Switch from '@radix-ui/react-switch' + +import api from '~utils/api' +import { accountState } from '~utils/accountState' +import { pictureData } from '~utils/pictureData' + +import Button from '~components/Button' + +import CrossIcon from '~public/icons/Cross.svg' +import './index.scss' + +const AccountModal = () => { + const { account } = useSnapshot(accountState) + + // Cookies + const [cookies] = useCookies(['user']) + const headers = (cookies.user != null) ? { + headers: { + 'Authorization': `Bearer ${cookies.user.access_token}` + } + } : {} + + // State + const [open, setOpen] = useState(false) + const [picture, setPicture] = useState('') + const [language, setLanguage] = useState('') + const [privateProfile, setPrivateProfile] = useState(false) + + // Refs + const pictureSelect = React.createRef() + const languageSelect = React.createRef() + const privateSelect = React.createRef() + + useEffect(() => { + if (cookies.user) setPicture(cookies.user.picture) + if (cookies.user) setLanguage(cookies.user.language) + }, [cookies]) + + const pictureOptions = ( + pictureData.sort((a, b) => (a.name.en > b.name.en) ? 1 : -1).map((item, i) => { + return ( + + ) + }) + ) + + function handlePictureChange(event: React.ChangeEvent) { + if (pictureSelect.current) + setPicture(pictureSelect.current.value) + } + + function handleLanguageChange(event: React.ChangeEvent) { + if (languageSelect.current) + setLanguage(languageSelect.current.value) + } + + function handlePrivateChange(checked: boolean) { + setPrivateProfile(checked) + } + + function update(event: React.FormEvent) { + event.preventDefault() + + const object = { + user: { + picture: picture, + element: pictureData.find(i => i.filename === picture)?.element, + language: language, + private: privateProfile + } + } + + api.endpoints.users.update(cookies.user.user_id, object, headers) + .then(response => { + setOpen(false) + }) + } + + function openChange(open: boolean) { + setOpen(open) + } + + return ( + + +
  • + Settings +
  • +
    + + event.preventDefault() }> +
    +
    + Account Settings + @{account.user?.username} +
    + + + + + +
    + +
    +
    +
    + +
    + +
    i.filename === picture)?.element}`}> + Profile preview +
    + + +
    +
    +
    + +
    + + +
    +
    +
    + +

    Hide your profile and prevent your grids from showing up in collections

    +
    + + + + +
    + + +
    +
    + +
    +
    + ) +} + +export default AccountModal diff --git a/components/GridRep/index.tsx b/components/GridRep/index.tsx index 8268104f..86fef4b7 100644 --- a/components/GridRep/index.tsx +++ b/components/GridRep/index.tsx @@ -83,11 +83,12 @@ const GridRep = (props: Props) => { if (props.user) return ( Gran + alt={props.user.picture.picture} + className={`profile ${props.user.picture.element}`} + srcSet={`/profile/${props.user.picture.picture}.png, + /profile/${props.user.picture.picture}@2x.png 2x`} + src={`/profile/${props.user.picture.picture}.png`} + /> ) else return (
    ) diff --git a/components/HeaderMenu/index.scss b/components/HeaderMenu/index.scss index bda86d8c..c12e4b75 100644 --- a/components/HeaderMenu/index.scss +++ b/components/HeaderMenu/index.scss @@ -12,7 +12,7 @@ color: $grey-40; font-weight: $normal; - &:hover { + &:hover:not(.disabled) { background: $grey-100; color: $grey-00; cursor: pointer; @@ -22,13 +22,42 @@ } } + &.profile > div { + padding: 6px 12px; + } + a { color: $grey-40; } - a, span { + & > a, & > span { display: block; - padding: 12px; + padding: 12px 12px; + } + + & > div { + align-items: center; + display: flex; + flex-direction: row; + padding: 10px 12px; + + &:hover { + i.tag { + background: $grey-60; + color: white; + } + } + + span { + flex-grow: 1; + } + + img { + $diameter: 32px; + border-radius: $diameter / 2; + height: $diameter; + width: $diameter; + } } } diff --git a/components/HeaderMenu/index.tsx b/components/HeaderMenu/index.tsx index 7a72a754..23fcbe99 100644 --- a/components/HeaderMenu/index.tsx +++ b/components/HeaderMenu/index.tsx @@ -1,14 +1,11 @@ import React from 'react' import Link from 'next/link' - -import LoginModal from '~components/LoginModal' -import SignupModal from '~components/SignupModal' - -import { useModal as useSignupModal } from '~utils/useModal' -import { useModal as useLoginModal } from '~utils/useModal' -import { useModal as useAboutModal } from '~utils/useModal' +import { useCookies } from 'react-cookie' import AboutModal from '~components/AboutModal' +import AccountModal from '~components/AccountModal' +import LoginModal from '~components/LoginModal' +import SignupModal from '~components/SignupModal' import './index.scss' @@ -19,13 +16,27 @@ interface Props { } const HeaderMenu = (props: Props) => { + + const [cookies] = useCookies() + function authItems() { return (