Skip to content

Commit

Permalink
Improve touch screen support (#144)
Browse files Browse the repository at this point in the history
* Dismiss dropdown when clicking off

* Better drawer animation

* Better logic

* Improve mobile drawer layout

* Better login button alignment

* Actually push images on build

* Improve collapsible logic

* Formatting

* Remove login condition

* Remove user picture link

* Better toggle logic

* Use click event

* Revert "Use click event"

This reverts commit 3a472c5.

* Close nav drawer on navigation

---------

Co-authored-by: Oscar Eriksson <oscariremma@gmail.com>
  • Loading branch information
GAsplund and Oscariremma authored Dec 8, 2024
1 parent 16c2546 commit 0bb7cd4
Show file tree
Hide file tree
Showing 15 changed files with 203 additions and 89 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ jobs:
uses: docker/setup-buildx-action@v3

- name: Login to GitHub Container Registry
if: ${{ github.ref == 'refs/heads/main' }}
uses: docker/login-action@v3
with:
registry: ghcr.io
Expand All @@ -44,7 +43,7 @@ jobs:
- name: Build Docker image (and push on main)
uses: docker/build-push-action@v6
with:
push: ${{ github.ref == 'refs/heads/main' }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
Expand Down
21 changes: 18 additions & 3 deletions src/components/ContentPane/Collapsible/Collapsible.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,25 @@
background-color: transparent;
overflow: hidden;
padding-bottom: 0.5rem;
max-height: 10rem;
}

.open {
input:checked + .content {
max-height: unset;
}

.closed {
max-height: 20rem;
input:checked ~ .button {
.open {
display: none;
}
.close {
display: block;
}
}

.button {
display: flex;
flex-direction: column;
padding: 0;
align-items: center;
width: 100%;
Expand All @@ -29,4 +37,11 @@
cursor: pointer;
border: none;
border-top: 2px solid var(--content-border-color);

.open {
display: block;
}
.close {
display: none;
}
}
26 changes: 13 additions & 13 deletions src/components/ContentPane/Collapsible/Collapsible.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
'use client';

import styles from './Collapsible.module.scss';
import { MdOutlineExpandMore, MdOutlineExpandLess } from 'react-icons/md';
import { useState } from 'react';

const Collapsible = ({ children }: { children: React.ReactNode }) => {
const [open, setOpen] = useState(false);
const Collapsible = ({
children,
id
}: {
children: React.ReactNode;
id: string;
}) => {
return (
<div className={styles.collapsible}>
<div
className={`${styles.content} ${open ? styles.open : styles.closed}`}
>
{children}
</div>
<button className={styles.button} onClick={() => setOpen(!open)}>
{open ? <MdOutlineExpandLess /> : <MdOutlineExpandMore />}
</button>
<input type="checkbox" id={id} hidden />
<div className={styles.content}>{children}</div>
<label htmlFor={id} className={styles.button}>
<MdOutlineExpandLess className={styles.close} />
<MdOutlineExpandMore className={styles.open} />
</label>
</div>
);
};
Expand Down
29 changes: 24 additions & 5 deletions src/components/Header/Header.module.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.selector {
padding: 0 1rem;
}

.header {
position: sticky;
top: 0;
Expand Down Expand Up @@ -30,19 +34,34 @@

.mobile {
display: none;
height: 4.75rem;
width: 100%;
flex-direction: row;
align-items: center;
justify-content: space-between;
}

.mobileActions {
display: flex;
flex-direction: column;
align-items: center;
gap: 1.25rem;
}

.mobileUser {
margin: 0 0 1.5rem 0.75rem !important;
}

button.mobileUser {
margin: 0 1rem 1.5rem 1rem !important;
}

@media screen and (max-width: #{$header-breakpoint}) {
.desktop {
display: none;
}
.mobile {
height: 4.75rem;
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.header {
padding: 0;
Expand Down
18 changes: 10 additions & 8 deletions src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,25 @@ import Link from 'next/link';
const Header = ({ locale }: { locale: string }) => {
return (
<header className={styles.header}>
<div className={`${styles.mobile}`}>
<div className={styles.mobile}>
<NavDrawer>
<User locale={locale} className={styles.mobileUser} />
<Navigation locale={locale} desktop={false} />
<User locale={locale} />
<ThemeSelector />
<Link href="/post/search">
<SearchIcon />
</Link>
<div className={styles.mobileActions}>
<ThemeSelector />
<Link href="/post/search">
<SearchIcon />
</Link>
</div>
</NavDrawer>
<EscapeHatch locale={locale} />
</div>
<div className={`${styles.desktop}`}>
<div className={styles.desktop}>
<SearchSwitcher
locale={locale}
nav={<Navigation locale={locale} desktop />}
>
<ThemeSelector />
<ThemeSelector className={styles.selector} />
<User locale={locale} />
</SearchSwitcher>
</div>
Expand Down
36 changes: 21 additions & 15 deletions src/components/Header/NavDrawer/NavDrawer.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
color: var(--text-color);
height: min(calc(1.5rem + 2.5vw), 2.5rem);
width: min(calc(1.5rem + 2.5vw), 2.5rem);
cursor: pointer;
}

.drawer {
position: fixed;
display: flex;
flex-direction: row;
transition: left 0.5s;
top: 0;
left: 0;
width: 100vw;
Expand All @@ -30,31 +32,23 @@
.content {
position: absolute;
background-color: var(--header-color);
max-width: 25rem;
width: 70vw;
height: 100%;
z-index: 10;
animation: slideIn 0.5s;
padding: 1.875rem 0;
display: flex;
flex-direction: column;
overflow: scroll;
}

@keyframes slideIn {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
transition: left 0.5s;
}

.overlay {
position: absolute;
background-color: rgba(0, 0, 0, 0.5);
width: 100%;
height: 100%;
animation: fadeIn 0.5s;
transition: opacity 0.5s;
}

@keyframes fadeIn {
Expand All @@ -66,10 +60,22 @@
}
}

.open {
display: block;
.checkbox + .drawer {
pointer-events: none;
.content {
left: -100%;
}
.overlay {
opacity: 0;
}
}

.closed {
display: none;
.checkbox:checked + .drawer {
pointer-events: all;
.content {
left: 0;
}
.overlay {
opacity: 1;
}
}
34 changes: 28 additions & 6 deletions src/components/Header/NavDrawer/NavDrawer.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
'use client';

import { useRef, useEffect } from 'react';
import { usePathname, useSearchParams } from 'next/navigation';
import styles from './NavDrawer.module.scss';
import { useState } from 'react';
import { FaBars } from 'react-icons/fa6';

const NavDrawer = ({ children }: { children: React.ReactNode }) => {
const [open, setOpen] = useState(false);
const pathname = usePathname();
const searchParams = useSearchParams();
const inputRef = useRef<HTMLInputElement>(null);

const handleClose = () => {
if (inputRef.current) {
inputRef.current.checked = false;
}
};

useEffect(() => {
handleClose();
}, [pathname, searchParams]);

return (
<div>
<FaBars className={styles.toggle} onClick={() => setOpen(!open)} />
<div className={`${styles.drawer} ${open ? styles.open : styles.closed}`}>
<label htmlFor="drawer-toggle">
<FaBars className={styles.toggle} />
</label>
<input
ref={inputRef}
className={styles.checkbox}
type="checkbox"
id="drawer-toggle"
hidden
/>
<div className={styles.drawer}>
<div className={styles.content}>{children}</div>
<div className={styles.overlay} onClick={() => setOpen(false)} />
<label htmlFor="drawer-toggle" className={styles.overlay} />
</div>
</div>
);
Expand Down
21 changes: 17 additions & 4 deletions src/components/Header/Navigation/Dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
'use client';

import { Poppins } from 'next/font/google';
import styles from './Dropdown.module.scss';
import { HTMLAttributes, ReactNode } from 'react';
import { HTMLAttributes, ReactNode, useRef, useState } from 'react';
import useClickOutside from '@/hooks/clickOutside';

const poppins = Poppins({ subsets: ['latin'], weight: ['500'] });

Expand All @@ -19,16 +22,26 @@ const Dropdown = ({
contentClassName,
...rest
}: Props & HTMLAttributes<HTMLDivElement>) => {
const [isDroppedDown, setIsDroppedDown] = useState(false);
const ref = useRef<HTMLDivElement>(null);
useClickOutside(ref, () => setIsDroppedDown(false));

return (
<div className={`${styles.dropdown} ${className}`} {...rest}>
<div ref={ref} className={`${styles.dropdown} ${className}`} {...rest}>
<input
type="radio"
type="checkbox"
id={id}
name="dropdown"
className={styles.dropdownInput}
checked={isDroppedDown}
readOnly
hidden
/>
<label htmlFor={id} className={styles.dropdownLabel}>
<label
htmlFor={id}
className={styles.dropdownLabel}
onClick={() => setIsDroppedDown((d) => !d)}
>
{parent}
</label>
<div className={`${styles.dropdownHitbox}`} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
font-size: 1.5rem;
line-height: 1.2rem;
color: var(--text-color);
padding: 0 1rem;
}

.loading {
Expand Down
11 changes: 7 additions & 4 deletions src/components/Header/ThemeSelector/ThemeSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { BsFillSunFill, BsFillMoonFill, BsThreeDots } from 'react-icons/bs';
import { useTheme } from 'next-themes';
import { useEffect, useState } from 'react';

const ThemeSelector = () => {
const ThemeSelector = ({ className }: { className?: string }) => {
const [mounted, setMounted] = useState(false);
const { resolvedTheme, setTheme } = useTheme();

Expand All @@ -15,8 +15,8 @@ const ThemeSelector = () => {

if (!mounted) {
return (
<div className={`${styles.icon} ${styles.loading}`}>
<BsThreeDots />
<div className={`${styles.icon} ${className}`}>
<BsThreeDots className={styles.loading} />
</div>
);
}
Expand All @@ -28,7 +28,10 @@ const ThemeSelector = () => {
};

return (
<a className={`${styles.icon} ${styles.toggle}`} onClick={toggleTheme}>
<a
className={`${styles.icon} ${styles.toggle} ${className}`}
onClick={toggleTheme}
>
{isDark ? <BsFillMoonFill /> : <BsFillSunFill />}
</a>
);
Expand Down
12 changes: 10 additions & 2 deletions src/components/Header/User/LoginButton/LoginButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@ import ActionButton from '@/components/ActionButton/ActionButton';
import i18nService from '@/services/i18nService';
import { signIn } from 'next-auth/react';

const LoginButton = ({ locale }: { locale: string }) => {
const LoginButton = ({
locale,
className
}: {
locale: string;
className?: string;
}) => {
const l = i18nService.getLocale(locale);
return (
<ActionButton onClick={() => signIn('gamma')}>{l.user.login}</ActionButton>
<ActionButton className={className} onClick={() => signIn('gamma')}>
{l.user.login}
</ActionButton>
);
};

Expand Down
Loading

0 comments on commit 0bb7cd4

Please sign in to comment.