improved mobile pwa user experience
This commit is contained in:
parent
d4f59d7f32
commit
4e47a6bffb
|
@ -0,0 +1,113 @@
|
|||
import { dropdownTriggerer } from "@/lib/client/utils";
|
||||
import React from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import NewLinkModal from "./ModalContent/NewLinkModal";
|
||||
import NewCollectionModal from "./ModalContent/NewCollectionModal";
|
||||
import UploadFileModal from "./ModalContent/UploadFileModal";
|
||||
import MobileNavigationButton from "./MobileNavigationButton";
|
||||
|
||||
type Props = {};
|
||||
|
||||
export default function MobileNavigation({}: Props) {
|
||||
const [hasScrolled, setHasScrolled] = useState(false);
|
||||
const [newLinkModal, setNewLinkModal] = useState(false);
|
||||
const [newCollectionModal, setNewCollectionModal] = useState(false);
|
||||
const [uploadFileModal, setUploadFileModal] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
if (window.scrollY > 0) {
|
||||
setHasScrolled(true);
|
||||
} else {
|
||||
setHasScrolled(false);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`fixed bottom-0 left-0 right-0 z-30 duration-200 sm:hidden ${
|
||||
hasScrolled ? "opacity-80" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="dropdown dropdown-end dropdown-top absolute -top-20 right-5">
|
||||
<div
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
onMouseDown={dropdownTriggerer}
|
||||
className={`flex items-center btn btn-accent dark:border-violet-400 text-white btn-circle btn-lg px-2 relative`}
|
||||
>
|
||||
<span>
|
||||
<i className="bi-plus text-5xl pointer-events-none"></i>
|
||||
</span>
|
||||
</div>
|
||||
<ul className="dropdown-content z-[1] menu shadow bg-base-200 border border-neutral-content rounded-box w-40 mb-1">
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
(document?.activeElement as HTMLElement)?.blur();
|
||||
setNewLinkModal(true);
|
||||
}}
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
>
|
||||
New Link
|
||||
</div>
|
||||
</li>
|
||||
{/* <li>
|
||||
<div
|
||||
onClick={() => {
|
||||
(document?.activeElement as HTMLElement)?.blur();
|
||||
setUploadFileModal(true);
|
||||
}}
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
>
|
||||
Upload File
|
||||
</div>
|
||||
</li> */}
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
(document?.activeElement as HTMLElement)?.blur();
|
||||
setNewCollectionModal(true);
|
||||
}}
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
>
|
||||
New Collection
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="w-full flex bg-base-100 pb-5 border-solid border-t-neutral-content border-t">
|
||||
<MobileNavigationButton href={`/dashboard`} icon={"bi-house"} />
|
||||
<MobileNavigationButton
|
||||
href={`/links/pinned`}
|
||||
icon={"bi-pin-angle"}
|
||||
/>
|
||||
<MobileNavigationButton href={`/links`} icon={"bi-link-45deg"} />
|
||||
<MobileNavigationButton href={`/collections`} icon={"bi-folder"} />
|
||||
<MobileNavigationButton href={`/tags`} icon={"bi-hash"} />
|
||||
</div>
|
||||
</div>
|
||||
{newLinkModal ? (
|
||||
<NewLinkModal onClose={() => setNewLinkModal(false)} />
|
||||
) : undefined}
|
||||
{newCollectionModal ? (
|
||||
<NewCollectionModal onClose={() => setNewCollectionModal(false)} />
|
||||
) : undefined}
|
||||
{uploadFileModal ? (
|
||||
<UploadFileModal onClose={() => setUploadFileModal(false)} />
|
||||
) : undefined}
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function MobileNavigationButton({
|
||||
href,
|
||||
icon,
|
||||
}: {
|
||||
href: string;
|
||||
icon: string;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const [active, setActive] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setActive(href === router.asPath);
|
||||
}, [router]);
|
||||
|
||||
return (
|
||||
<Link href={href} className="w-full">
|
||||
<div
|
||||
className={`py-2 cursor-pointer gap-2 w-full rounded-full capitalize flex items-center justify-center`}
|
||||
>
|
||||
<i
|
||||
className={`${icon} text-primary text-3xl drop-shadow duration-200 rounded-full w-14 h-14 text-center pt-[0.65rem] ${
|
||||
active || false ? "bg-primary/20" : ""
|
||||
}`}
|
||||
></i>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
|
@ -14,7 +14,7 @@ import NewCollectionModal from "./ModalContent/NewCollectionModal";
|
|||
import Link from "next/link";
|
||||
import UploadFileModal from "./ModalContent/UploadFileModal";
|
||||
import { dropdownTriggerer } from "@/lib/client/utils";
|
||||
import NewButtonMobile from "./NewButtonMobile";
|
||||
import MobileNavigation from "./MobileNavigation";
|
||||
|
||||
export default function Navbar() {
|
||||
const { settings, updateSettings } = useLocalSettingsStore();
|
||||
|
@ -56,7 +56,7 @@ export default function Navbar() {
|
|||
setSidebar(true);
|
||||
document.body.style.overflow = "hidden";
|
||||
}}
|
||||
className="text-neutral btn btn-square btn-sm btn-ghost lg:hidden"
|
||||
className="text-neutral btn btn-square btn-sm btn-ghost lg:hidden hidden sm:inline-flex"
|
||||
>
|
||||
<i className="bi-list text-2xl leading-none"></i>
|
||||
</div>
|
||||
|
@ -171,7 +171,7 @@ export default function Navbar() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<NewButtonMobile />
|
||||
<MobileNavigation />
|
||||
|
||||
{sidebar ? (
|
||||
<div className="fixed top-0 bottom-0 right-0 left-0 bg-black bg-opacity-10 backdrop-blur-sm flex items-center fade-in z-40">
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
import { dropdownTriggerer } from "@/lib/client/utils";
|
||||
import React from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import NewLinkModal from "./ModalContent/NewLinkModal";
|
||||
import NewCollectionModal from "./ModalContent/NewCollectionModal";
|
||||
import UploadFileModal from "./ModalContent/UploadFileModal";
|
||||
|
||||
type Props = {};
|
||||
|
||||
export default function NewButtonMobile({}: Props) {
|
||||
const [hasScrolled, setHasScrolled] = useState(false);
|
||||
const [newLinkModal, setNewLinkModal] = useState(false);
|
||||
const [newCollectionModal, setNewCollectionModal] = useState(false);
|
||||
const [uploadFileModal, setUploadFileModal] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
if (window.scrollY > 0) {
|
||||
setHasScrolled(true);
|
||||
} else {
|
||||
setHasScrolled(false);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("scroll", handleScroll);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="dropdown dropdown-end dropdown-top sm:hidden fixed bottom-10 right-10 z-30">
|
||||
<div
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
onMouseDown={dropdownTriggerer}
|
||||
className={`flex items-center btn btn-accent dark:border-violet-400 text-white btn-circle btn-lg px-2 relative ${
|
||||
hasScrolled ? "opacity-50" : ""
|
||||
}`}
|
||||
>
|
||||
<span>
|
||||
<i className="bi-plus text-5xl pointer-events-none"></i>
|
||||
</span>
|
||||
</div>
|
||||
<ul className="dropdown-content z-[1] menu shadow bg-base-200 border border-neutral-content rounded-box w-40 mb-1">
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
(document?.activeElement as HTMLElement)?.blur();
|
||||
setNewLinkModal(true);
|
||||
}}
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
>
|
||||
New Link
|
||||
</div>
|
||||
</li>
|
||||
{/* <li>
|
||||
<div
|
||||
onClick={() => {
|
||||
(document?.activeElement as HTMLElement)?.blur();
|
||||
setUploadFileModal(true);
|
||||
}}
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
>
|
||||
Upload File
|
||||
</div>
|
||||
</li> */}
|
||||
<li>
|
||||
<div
|
||||
onClick={() => {
|
||||
(document?.activeElement as HTMLElement)?.blur();
|
||||
setNewCollectionModal(true);
|
||||
}}
|
||||
tabIndex={0}
|
||||
role="button"
|
||||
>
|
||||
New Collection
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{newLinkModal ? (
|
||||
<NewLinkModal onClose={() => setNewLinkModal(false)} />
|
||||
) : undefined}
|
||||
{newCollectionModal ? (
|
||||
<NewCollectionModal onClose={() => setNewCollectionModal(false)} />
|
||||
) : undefined}
|
||||
{uploadFileModal ? (
|
||||
<UploadFileModal onClose={() => setUploadFileModal(false)} />
|
||||
) : undefined}
|
||||
</>
|
||||
);
|
||||
}
|
Ŝarĝante…
Reference in New Issue