Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ declare module "little-state-machine" {
register: RegisterType;
profile: ProfileType;
profileView: ProfileDisplayState;
profileActiveTab: string;
}
}

Expand Down
14 changes: 13 additions & 1 deletion src/components/AppFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import Link from "next/link";
import { Icons } from "./Icons";
import { cn } from "@/lib/client/utils";
import { usePathname } from "next/navigation";
import { useStateMachine } from "little-state-machine";
import updateStateFromAction from "@/lib/shared/updateAction";

interface RouterItem {
label: string;
Expand All @@ -13,12 +15,22 @@ interface RouterItem {
}

const TabItem = ({ label, href, icon, isActive, iconSize }: RouterItem) => {
const { actions, getState } = useStateMachine({ updateStateFromAction });
const Icon: any = icon;

const textColor = isActive ? "text-white" : "text-gray-10";

return (
<Link href={href}>
<Link
href={href}
onClick={() => {
actions.updateStateFromAction({
...getState(),
// on navigation, reset the active tab to the default
profileActiveTab: "activity-feed",
});
}}
>
<div className="flex flex-col text-center items-center justify-center gap-1">
<Icon size={iconSize || 24} className={cn("duration-200", textColor)} />
<span
Expand Down
10 changes: 8 additions & 2 deletions src/components/AppHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { clearIndexedDB } from "@/lib/client/indexedDB";
import { useStateMachine } from "little-state-machine";
import updateStateFromAction from "@/lib/shared/updateAction";
import { ProfileDisplayState } from "@/types";
import { cn } from "@/lib/client/utils";

const Title = classed.h3("block text-base text-gray-12 font-light leading-5");
const Subtitle = classed.h4("text-sm text-gray-12 leading-5");
Expand Down Expand Up @@ -214,17 +215,22 @@ const AppHeaderContent = ({
interface AppHeaderProps {
isMenuOpen: boolean;
setIsMenuOpen: (value: boolean) => void;
fixed?: boolean; // if true, the header will be fixed
}

const AppHeader = ({ isMenuOpen, setIsMenuOpen }: AppHeaderProps) => {
const AppHeader = ({ isMenuOpen, setIsMenuOpen, fixed }: AppHeaderProps) => {
const handleSignout = async () => {
await clearIndexedDB();
deleteAccountFromLocalStorage();
window.location.href = "/";
};

return (
<div className="flex w-full items-center p-3 py-3 xs:p-4 bg-black z-50">
<div
className={cn("flex w-full items-center p-3 py-3 xs:p-4 bg-black z-50", {
fixed: fixed,
})}
>
{!isMenuOpen && (
<Link href="/">
<button type="button" className="flex gap-2 items-center">
Expand Down
19 changes: 15 additions & 4 deletions src/components/Tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { Tab } from "@headlessui/react";
import { classed } from "@tw-classed/react";
import { useStateMachine } from "little-state-machine";

interface TabProps {
label: string;
id: string;
badge?: boolean;
children: React.ReactNode;
}

export interface TabsProps {
onChange?: (currentActive: string) => void;
items: TabProps[];
defaultTab?: string;
}

const TabButton = classed.div("pb-4", {
Expand All @@ -27,16 +31,23 @@ const TabBadge = classed.div(
"absolute -top-0.5 -right-2 bg-[#D40018] rounded-full text-white w-[6px] h-[6px] text-[8px]"
);

const Tabs = ({ items }: TabsProps) => {
const Tabs = ({ items, defaultTab, onChange }: TabsProps) => {
const defaultTabIndex = items.findIndex((item) => item.id === defaultTab);

return (
<Tab.Group>
<Tab.Group defaultIndex={defaultTabIndex}>
<Tab.List className="flex gap-8 relative">
{items.map(({ label, badge }, index) => {
{items.map(({ label, badge, id }, index) => {
return (
<Tab className="outline-none" key={index}>
{({ selected }) => (
<div className="relative">
<TabButton selected={selected}>
<TabButton
selected={selected}
onClick={() => {
onChange?.(id);
}}
>
<span className="relative">
{label}
{badge && <TabBadge />}
Expand Down
6 changes: 6 additions & 0 deletions src/lib/shared/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import clsx, { ClassValue } from "clsx";
import dayjs from "dayjs";
import { twMerge } from "tailwind-merge";

// This function check if nickname starts with @, if not, it adds it
export const handleNickName = (nickname?: string): string => {
Expand Down Expand Up @@ -78,3 +80,7 @@ export const twitterUsernameRegex = /^@[a-zA-Z0-9_]{1,15}$/;
export const telegramUsernameRegex = /^@[a-zA-Z0-9_]{5,32}$/;

export const farcasterUsernameRegex = /^@[a-zA-Z0-9_.]{1,20}$/;

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
13 changes: 10 additions & 3 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { FullPageBanner } from "@/components/FullPageBanner";
import { TransitionWrapper } from "@/components/Transition";
import useSettings from "@/hooks/useSettings";
import OnlyMobileLayout from "@/layouts/OnlyMobileLayout";
import { cn } from "@/lib/client/utils";
import "@/styles/globals.css";
import {
QueryCache,
Expand All @@ -12,6 +13,7 @@ import {
} from "@tanstack/react-query";
import { StateMachineProvider } from "little-state-machine";
import type { AppProps } from "next/app";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { toast, Toaster } from "sonner";

Expand All @@ -23,6 +25,7 @@ const queryClient = new QueryClient({

export default function App({ Component, pageProps }: AppProps) {
const { isIncognito } = useSettings();
const router = useRouter();
const [isMenuOpen, setIsMenuOpen] = useState(false);
const [pageHeight, setPageHeight] = useState(0);
const showFooter = pageProps?.showFooter ?? true;
Expand All @@ -41,6 +44,8 @@ export default function App({ Component, pageProps }: AppProps) {
);
}

const isHeaderFixed = pageProps?.headerFixed ?? true;

return (
<StateMachineProvider>
<QueryClientProvider client={queryClient}>
Expand All @@ -56,12 +61,14 @@ export default function App({ Component, pageProps }: AppProps) {
<AppHeader
isMenuOpen={isMenuOpen}
setIsMenuOpen={setIsMenuOpen}
fixed={isHeaderFixed}
/>
)}
<div
className={`flex flex-col grow px-4 xs:px-4 ${
footerVisible ? "mb-20" : ""
}`}
className={cn("flex flex-col grow px-4 xs:px-4", {
"mb-20": footerVisible,
"pt-[55px] xs:pt-[65px]": isHeaderFixed,
})}
>
<Component {...pageProps} />
</div>
Expand Down
26 changes: 25 additions & 1 deletion src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { formatDate } from "@/lib/shared/utils";
import { loadMessages } from "@/lib/client/jubSignalClient";
import { Spinner } from "@/components/Spinner";
import { CircleCard } from "@/components/cards/CircleCard";
import { useStateMachine } from "little-state-machine";
import updateStateFromAction from "@/lib/shared/updateAction";
import { ArtworkSnapshot } from "@/components/artwork/ArtworkSnapshot";
import useSettings from "@/hooks/useSettings";

Expand Down Expand Up @@ -195,6 +197,8 @@ export default function Social() {
const [tabsItems, setTabsItems] = useState<TabsProps["items"]>();
const [isLoading, setLoading] = useState(false);

const { actions, getState } = useStateMachine({ updateStateFromAction });

// Helper function to compute data needed to populate tabs
const computeTabsItems = (
profileData: Profile,
Expand Down Expand Up @@ -260,6 +264,7 @@ export default function Social() {

return [
{
id: "activity-feed",
label: "Activity Feed",
children: (
<div className="flex flex-col gap-4">
Expand Down Expand Up @@ -293,6 +298,7 @@ export default function Social() {
),
},
{
id: "contacts",
label: "Contacts",
children: (
<div className="flex flex-col gap-5">
Expand Down Expand Up @@ -331,6 +337,7 @@ export default function Social() {
),
},
{
id: "pending",
label: "Pending",
badge: sortedPendingUserList.length > 0,
children: (
Expand Down Expand Up @@ -425,6 +432,9 @@ export default function Social() {
}

if (!profile || !tabsItems) return null;

const currentActiveTab = getState().profileActiveTab ?? tabsItems[0].id;

return (
<>
<SnapshotModal
Expand Down Expand Up @@ -471,7 +481,21 @@ export default function Social() {
</div>
</div>
</div>
<Tabs items={tabsItems} />
<Tabs
items={tabsItems}
defaultTab={currentActiveTab}
onChange={(activeTabId) => {
actions.updateStateFromAction({
...getState(),
// keep track of the active tab
profileActiveTab: activeTabId,
});
}}
/>
</>
);
}

Social.getInitialProps = () => {
return { headerFixed: true };
};