a tool for shared writing and social publishing
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Feature/action bar (#133)

* WIP action bar

* moved action button from buttons file into action bar folder

* styling for the siedbar, no mobile yet, only in leaflet

* styled and refactored sidebar

* made it work in mobile, passed the action button as a child in the menus

* rm unnecessary props from action button

* deleted unused component, put a mobile check on sidebar is leaflets

* added new sidebar to home

* made the stuff work for home

* add use client

* unify text toolbar and footer height on mobile

* tweak padding

---------

Co-authored-by: celine <celine@hyperlink.academy>

authored by

Jared Pereira
celine
and committed by
GitHub
30bcd530 fd15cd7b

+286 -289
+47
app/[leaflet_id]/Footer.tsx
··· 1 + "use client"; 2 + import { useUIState } from "src/useUIState"; 3 + import { Footer as ActionFooter } from "components/ActionBar/Footer"; 4 + import { Media } from "components/Media"; 5 + import { ThemePopover } from "components/ThemeManager/ThemeSetter"; 6 + import { Toolbar } from "components/Toolbar"; 7 + import { ShareOptions } from "components/ShareOptions"; 8 + import { HomeButton } from "components/HomeButton"; 9 + import { useEntitySetContext } from "components/EntitySetProvider"; 10 + import { HelpPopover } from "components/HelpPopover"; 11 + import { Watermark } from "components/Watermark"; 12 + 13 + export function LeafletFooter(props: { entityID: string }) { 14 + let focusedBlock = useUIState((s) => s.focusedEntity); 15 + let entity_set = useEntitySetContext(); 16 + 17 + return ( 18 + <Media mobile className="mobileFooter w-full z-10 touch-none -mt-4 "> 19 + {focusedBlock && 20 + focusedBlock.entityType == "block" && 21 + entity_set.permissions.write ? ( 22 + <div 23 + className="w-full z-10 p-2 flex bg-bg-page pwa-padding-bottom" 24 + onMouseDown={(e) => { 25 + if (e.currentTarget === e.target) e.preventDefault(); 26 + }} 27 + > 28 + <Toolbar 29 + pageID={focusedBlock.parent} 30 + blockID={focusedBlock.entityID} 31 + /> 32 + </div> 33 + ) : entity_set.permissions.write ? ( 34 + <ActionFooter> 35 + <HomeButton /> 36 + <ShareOptions /> 37 + <HelpPopover /> 38 + <ThemePopover entityID={props.entityID} /> 39 + </ActionFooter> 40 + ) : ( 41 + <div className="pb-2 px-2 z-10 flex justify-end"> 42 + <Watermark mobile /> 43 + </div> 44 + )} 45 + </Media> 46 + ); 47 + }
+2 -2
app/[leaflet_id]/Leaflet.tsx
··· 7 7 ThemeBackgroundProvider, 8 8 ThemeProvider, 9 9 } from "components/ThemeManager/ThemeProvider"; 10 - import { MobileFooter } from "components/MobileFooter"; 10 + import { LeafletFooter } from "./Footer"; 11 11 import { EntitySetProvider } from "components/EntitySetProvider"; 12 12 import { AddLeafletToHomepage } from "components/utils/AddLeafletToHomepage"; 13 13 import { UpdateLeafletTitle } from "components/utils/UpdateLeafletTitle"; ··· 51 51 <Pages rootPage={props.leaflet_id} /> 52 52 </div> 53 53 </div> 54 - <MobileFooter entityID={props.leaflet_id} /> 54 + <LeafletFooter entityID={props.leaflet_id} /> 55 55 </ThemeBackgroundProvider> 56 56 </ThemeProvider> 57 57 </EntitySetProvider>
+19 -21
app/[leaflet_id]/Sidebar.tsx
··· 3 3 import { useEntitySetContext } from "components/EntitySetProvider"; 4 4 import { HelpPopover } from "components/HelpPopover"; 5 5 import { HomeButton } from "components/HomeButton"; 6 + import { Media } from "components/Media"; 6 7 import { usePublicationContext } from "components/Providers/PublicationContext"; 7 8 import { ShareOptions } from "components/ShareOptions"; 8 9 import { PublishToPublication } from "components/ShareOptions/PublicationOptions"; ··· 21 22 e.currentTarget === e.target && blurPage(); 22 23 }} 23 24 > 24 - <Sidebar> 25 - {entity_set.permissions.write ? ( 26 - <div className=" flex flex-col justify-center gap-2 mr-4"> 27 - {publication.publication && ( 28 - <div className="relative w-[30px] h-[76px]"> 29 - <div className="origin-top-left -rotate-90 absolute translate-y-[76px]"> 30 - <PublishToPublication /> 31 - </div> 25 + <Media mobile={false}> 26 + <div className="sidebarContainer relative flex flex-col justify-between h-full w-16 bg-bg-pge bg-opacity-50 border-bg-page"> 27 + <Sidebar> 28 + {entity_set.permissions.write ? ( 29 + <> 30 + <ShareOptions /> 31 + <ThemePopover entityID={props.leaflet_id} /> 32 + <HelpPopover /> 33 + <hr className="text-border" /> 34 + <HomeButton /> 35 + </> 36 + ) : ( 37 + <div> 38 + <HomeButton /> 32 39 </div> 33 40 )} 34 - <ShareOptions /> 35 - <ThemePopover entityID={props.leaflet_id} /> 36 - <HelpPopover /> 37 - <hr className="text-border my-3" /> 38 - <HomeButton /> 39 - </div> 40 - ) : ( 41 - <div> 42 - <HomeButton /> 43 - </div> 44 - )} 45 - <Watermark /> 46 - </Sidebar> 41 + </Sidebar> 42 + <Watermark /> 43 + </div> 44 + </Media> 47 45 </div> 48 46 ); 49 47 }
+3 -1
app/globals.css
··· 27 27 --gripperSVG2: url("/gripperPattern2.svg"); 28 28 --hatchSVG: url("/hatchPattern.svg"); 29 29 --wavySVG: (url("/RSVPBackground/wavy.svg")); 30 + 31 + --safe-padding-bottom: max(calc(env(safe-area-inset-bottom) - 8px), 16px); 30 32 } 31 33 32 34 @media (max-width: 640px) { ··· 246 248 padding-top: max(calc(env(safe-area-inset-top) - 8px)) !important; 247 249 } 248 250 .pwa-padding-bottom { 249 - padding-bottom: max(calc(env(safe-area-inset-bottom) - 14px), 8px); 251 + padding-bottom: var(--safe-padding-bottom); 250 252 }
+2 -12
app/home/AccountSettings.tsx
··· 1 1 "use client"; 2 2 3 - import { HoverButton } from "components/Buttons"; 3 + import { ActionButton } from "components/ActionBar/ActionButton"; 4 4 import { AccountSmall, LogoutSmall } from "components/Icons"; 5 5 import { Menu, MenuItem } from "components/Layout"; 6 6 import { logout } from "actions/logout"; ··· 9 9 // it was going have a popover with a log out button 10 10 export const AccountSettings = () => { 11 11 return ( 12 - <Menu 13 - trigger={ 14 - <HoverButton 15 - icon=<AccountSmall /> 16 - label="Settings" 17 - noLabelOnMobile 18 - background="bg-accent-1" 19 - text="text-accent-2" 20 - /> 21 - } 22 - > 12 + <Menu trigger={<ActionButton icon=<AccountSmall /> label="Settings" />}> 23 13 <MenuItem 24 14 onSelect={async () => { 25 15 await logout();
+6 -9
app/home/CreateNewButton.tsx
··· 2 2 3 3 import { createNewLeaflet } from "actions/createNewLeaflet"; 4 4 import { createNewLeafletFromTemplate } from "actions/createNewLeafletFromTemplate"; 5 - import { HoverButton } from "components/Buttons"; 5 + import { ActionButton } from "components/ActionBar/ActionButton"; 6 6 import { 7 7 AddTiny, 8 8 BlockCanvasPageSmall, ··· 40 40 }, 41 41 ), 42 42 ); 43 - export const CreateNewLeafletButton = (props: { 44 - noLabelOnMobile?: boolean; 45 - }) => { 43 + export const CreateNewLeafletButton = (props: {}) => { 46 44 let isMobile = useIsMobile(); 47 45 let templates = useTemplateState((s) => s.templates); 48 46 let openNewLeaflet = (id: string) => { ··· 54 52 }; 55 53 return ( 56 54 <Menu 55 + asChild 57 56 trigger={ 58 - <HoverButton 57 + <ActionButton 59 58 id="new-leaflet-button" 60 - noLabelOnMobile={props.noLabelOnMobile} 59 + primary 61 60 icon=<AddTiny className="m-1 shrink-0" /> 62 - label="New Leaflet" 63 - background="bg-accent-1" 64 - text="text-accent-2" 61 + label="New Doc" 65 62 /> 66 63 } 67 64 >
+25
app/home/HomeFooter.tsx
··· 1 + "use client"; 2 + import { Footer } from "components/ActionBar/Footer"; 3 + import { Media } from "components/Media"; 4 + import { ThemePopover } from "components/ThemeManager/ThemeSetter"; 5 + import { CreateNewLeafletButton } from "./CreateNewButton"; 6 + import { HelpPopover } from "components/HelpPopover"; 7 + import { AccountSettings } from "./AccountSettings"; 8 + import { useIdentityData } from "components/IdentityProvider"; 9 + import { useReplicache } from "src/replicache"; 10 + import { LoginActionButton } from "components/LoginButton"; 11 + 12 + export const HomeFooter = () => { 13 + let { identity } = useIdentityData(); 14 + let { rootEntity } = useReplicache(); 15 + return ( 16 + <Media mobile> 17 + <Footer> 18 + <CreateNewLeafletButton /> 19 + {identity ? <AccountSettings /> : <LoginActionButton />} 20 + <HelpPopover noShortcuts /> 21 + <ThemePopover entityID={rootEntity} home /> 22 + </Footer> 23 + </Media> 24 + ); 25 + };
+2 -10
app/home/HomeHelp.tsx
··· 1 1 "use client"; 2 2 import { HelpSmall } from "components/Icons"; 3 - import { HoverButton } from "components/Buttons"; 3 + import { ActionButton } from "components/ActionBar/ActionButton"; 4 4 import { Popover } from "components/Popover"; 5 5 6 6 export const HomeHelp = () => { 7 7 return ( 8 8 <Popover 9 9 className="max-w-sm" 10 - trigger={ 11 - <HoverButton 12 - icon={<HelpSmall />} 13 - noLabelOnMobile 14 - label="Info" 15 - background="bg-accent-1" 16 - text="text-accent-2" 17 - /> 18 - } 10 + trigger={<ActionButton icon={<HelpSmall />} label="Info" />} 19 11 > 20 12 <div className="flex flex-col gap-2"> 21 13 <p>
+23
app/home/HomeSidebar.tsx
··· 1 + "use client"; 2 + import { ThemePopover } from "components/ThemeManager/ThemeSetter"; 3 + import { CreateNewLeafletButton } from "./CreateNewButton"; 4 + import { HelpPopover } from "components/HelpPopover"; 5 + import { AccountSettings } from "./AccountSettings"; 6 + import { Sidebar } from "components/ActionBar/Sidebar"; 7 + import { useIdentityData } from "components/IdentityProvider"; 8 + import { useReplicache } from "src/replicache"; 9 + import { LoginActionButton } from "components/LoginButton"; 10 + 11 + export const HomeSidebar = () => { 12 + let { identity } = useIdentityData(); 13 + let { rootEntity } = useReplicache(); 14 + 15 + return ( 16 + <Sidebar alwaysOpen className="mt-6"> 17 + <CreateNewLeafletButton /> 18 + {identity ? <AccountSettings /> : <LoginActionButton />} 19 + <HelpPopover noShortcuts /> 20 + <ThemePopover entityID={rootEntity} home /> 21 + </Sidebar> 22 + ); 23 + };
+1 -1
app/home/LeafletList.tsx
··· 55 55 56 56 return ( 57 57 <div className="homeLeafletGrid grow w-full h-full overflow-y-scroll no-scrollbar "> 58 - <div className="grid auto-rows-max md:grid-cols-4 sm:grid-cols-3 grid-cols-2 gap-y-6 gap-x-4 sm:gap-6 grow pt-3 pb-28 sm:pt-6 sm:pb-12 sm:pl-6 sm:pr-1"> 58 + <div className="grid auto-rows-max md:grid-cols-4 sm:grid-cols-3 grid-cols-2 gap-y-4 gap-x-4 sm:gap-6 grow pt-3 pb-28 px-2 sm:pt-6 sm:pb-12 sm:pl-6 sm:pr-1"> 59 59 {leaflets.map((leaflet, index) => ( 60 60 <ReplicacheProvider 61 61 initialFactsOnly={!!identity}
+12 -30
app/home/page.tsx
··· 22 22 import { AccountSettings } from "./AccountSettings"; 23 23 import { LoggedOutWarning } from "./LoggedOutWarning"; 24 24 import { getFactsFromHomeLeaflets } from "app/api/rpc/[command]/getFactsFromHomeLeaflets"; 25 + import { Media } from "components/Media"; 26 + import { Sidebar } from "components/ActionBar/Sidebar"; 27 + import { HomeSidebar } from "./HomeSidebar"; 28 + import { HomeFooter } from "./HomeFooter"; 25 29 26 30 let supabase = createServerClient<Database>( 27 31 process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, ··· 49 53 async function setCookie() { 50 54 "use server"; 51 55 52 - (await cookies()).set("identity", identity as string, { sameSite: "strict" }); 56 + (await cookies()).set("identity", identity as string, { 57 + sameSite: "strict", 58 + }); 53 59 } 54 60 55 61 let permission_token = auth_res?.home_leaflet; ··· 99 105 set={permission_token.permission_token_rights[0].entity_set} 100 106 > 101 107 <ThemeProvider entityID={root_entity}> 102 - <div className="flex h-full bg-bg-leaflet pwa-padding"> 108 + <div className="homeWrapper flex h-full bg-bg-leaflet pwa-padding"> 103 109 <ThemeBackgroundProvider entityID={root_entity}> 104 - <div className="home relative max-w-screen-lg w-full h-full mx-auto flex sm:flex-row sm:items-stretch flex-col-reverse px-2 sm:px-6 "> 105 - {!auth_res && ( 106 - <div className="sm:hidden block"> 107 - <LoggedOutWarning /> 108 - </div> 109 - )} 110 - <div 111 - className={`homeOptions z-10 shrink-0 112 - sm:static absolute bottom-0 left-0 right-0 113 - place-self-end sm:place-self-start flex sm:flex-col flex-row-reverse sm:w-fit w-full items-center 114 - px-2 sm:px-0 pwa-padding-bottom pt-2 sm:pt-7 sm:bg-transparent 115 - bg-bg-page border-border border-t sm:border-none`} 116 - > 117 - <div className="flex sm:flex-col flex-row-reverse gap-2 shrink-0 place-self-end"> 118 - <CreateNewLeafletButton /> 119 - <ThemePopover entityID={root_entity} home /> 120 - <HelpPopover noShortcuts /> 121 - {auth_res && <AccountSettings />} 122 - </div> 123 - </div> 124 - <div 125 - className={`h-full w-full flex flex-col ${!auth_res && "sm:pb-0 pb-16"}`} 126 - > 127 - {!auth_res && ( 128 - <div className="sm:block hidden"> 129 - <LoggedOutWarning /> 130 - </div> 131 - )} 110 + <div className="home relative max-w-screen-lg w-full h-full mx-auto flex sm:flex-row flex-col sm:items-stretch sm:px-6 "> 111 + <HomeSidebar /> 112 + <div className={`h-full overflow-y-scroll`}> 132 113 <LeafletList initialFacts={home_docs_initialFacts} /> 133 114 </div> 115 + <HomeFooter /> 134 116 </div> 135 117 </ThemeBackgroundProvider> 136 118 </div>
+2 -8
app/templates/page.tsx
··· 1 1 import Link from "next/link"; 2 2 import { TemplateListExamples, TemplateListThemes } from "./TemplateList"; 3 - import { HoverButton } from "components/Buttons"; 3 + import { ActionButton } from "components/ActionBar/ActionButton"; 4 4 import { HomeSmall } from "components/Icons"; 5 5 6 6 export const metadata = { ··· 15 15 <div className="homeOptions z-10 shrink-0 sm:static absolute bottom-0 place-self-end sm:place-self-start flex sm:flex-col flex-row-reverse gap-2 sm:w-fit w-full items-center pb-2 pt-1 sm:pt-7"> 16 16 {/* NOT using <HomeButton /> b/c it does a permission check we don't need */} 17 17 <Link href="/home"> 18 - <HoverButton 19 - noLabelOnMobile 20 - icon={<HomeSmall />} 21 - label="Go Home" 22 - background="bg-accent-1" 23 - text="text-accent-2" 24 - /> 18 + <ActionButton icon={<HomeSmall />} label="Go Home" /> 25 19 </Link> 26 20 </div> 27 21 <div className="flex flex-col gap-10 py-6 pt-3 sm:pt-6 sm:pb-12 sm:pl-6 grow w-full h-full overflow-y-scroll no-scrollbar">
+49
components/ActionBar/ActionButton.tsx
··· 1 + import { useContext } from "react"; 2 + import { SidebarOpenContext } from "./Sidebar"; 3 + import React, { forwardRef, type JSX } from "react"; 4 + 5 + type ButtonProps = Omit<JSX.IntrinsicElements["button"], "content">; 6 + 7 + export const ActionButton = forwardRef< 8 + HTMLButtonElement, 9 + ButtonProps & { 10 + id?: string; 11 + icon: React.ReactNode; 12 + label: string; 13 + primary?: boolean; 14 + secondary?: boolean; 15 + } 16 + >((props, ref) => { 17 + let { id, icon, label, primary, secondary, ...buttonProps } = props; 18 + 19 + let sidebarExpanded = useContext(SidebarOpenContext); 20 + return ( 21 + <button 22 + {...buttonProps} 23 + ref={ref} 24 + id={props.id} 25 + className={` 26 + actionButton relative font-bold 27 + rounded-md border 28 + flex gap-2 items-center sm:justify-start justify-center 29 + p-1 sm:mr-0 last:mr-0 first:mr-2 30 + ${ 31 + props.primary 32 + ? "w-full bg-accent-1 border-accent-1 text-accent-2 transparent-outline sm:hover:outline-accent-contrast focus:outline-accent-1 outline-offset-1 mr-2" 33 + : props.secondary 34 + ? "sm:w-full w-max bg-bg-page border-accent-contrast text-accent-contrast transparent-outline focus:outline-accent-contrast sm:hover:outline-accent-contrast outline-offset-1 mr-2" 35 + : "sm:w-full w-max border-transparent text-accent-1 sm:hover:border-accent-1 mr-1" 36 + } 37 + `} 38 + > 39 + <div className="shrink-0">{props.icon}</div> 40 + <div 41 + className={`pr-1 w-max ${sidebarExpanded ? "block" : props.primary || props.secondary ? "sm:hidden block" : "hidden"}`} 42 + > 43 + {props.label} 44 + </div> 45 + </button> 46 + ); 47 + }); 48 + 49 + ActionButton.displayName = "ActionButton";
+18
components/ActionBar/Footer.tsx
··· 1 + import { Media } from "components/Media"; 2 + 3 + export function Footer(props: { children?: React.ReactNode }) { 4 + return ( 5 + <Media 6 + mobile 7 + className={` 8 + actionFooter touch-none 9 + w-full z-10 10 + px-2 pt-1 pwa-padding-bottom 11 + flex justify-start 12 + h-[calc(45px+var(--safe-padding-bottom))] 13 + bg-bg-page bg-opacity-50 border-top border-bg-page`} 14 + > 15 + {props.children} 16 + </Media> 17 + ); 18 + }
+31 -5
components/ActionBar/Sidebar.tsx
··· 1 + "use client"; 1 2 import { Media } from "components/Media"; 3 + import { createContext, useState } from "react"; 2 4 3 - export function Sidebar(props: { children?: React.ReactNode }) { 5 + export const SidebarOpenContext = createContext(false); 6 + 7 + export function Sidebar(props: { 8 + children?: React.ReactNode; 9 + alwaysOpen?: boolean; 10 + className?: string; 11 + }) { 12 + let [sidebarExpanded, setSidebarExpanded] = useState(false); 4 13 return ( 5 - <Media mobile={false} className="h-full"> 6 - <div className="flex flex-col h-full justify-between mt-1"> 7 - {props.children} 8 - </div> 14 + <Media mobile={false}> 15 + <SidebarOpenContext value={props.alwaysOpen ? true : sidebarExpanded}> 16 + <div 17 + className={` 18 + actionSidebar 19 + ${!props.alwaysOpen && "absolute top-0 left-0 z-10"} 20 + h-fit w-max p-[6px] 21 + flex flex-col gap-2 justify-start border 22 + rounded-md bg-bg-page ${sidebarExpanded && !props.alwaysOpen ? "border-border-light" : "bg-opacity-50 border-bg-page"} 23 + ${props.className} 24 + `} 25 + onMouseOver={() => { 26 + setSidebarExpanded(true); 27 + }} 28 + onMouseLeave={() => { 29 + !props.alwaysOpen && setSidebarExpanded(false); 30 + }} 31 + > 32 + {props.children} 33 + </div> 34 + </SidebarOpenContext> 9 35 </Media> 10 36 ); 11 37 }
+2 -34
components/Buttons.tsx
··· 37 37 bg-accent-1 outline-transparent border border-accent-1 38 38 rounded-md text-base font-bold text-accent-2 39 39 flex gap-2 items-center justify-center shrink-0 40 - transparent-outline hover:outline-accent-1 outline-offset-1 40 + transparent-outline focus:outline-accent-1 hover:outline-accent-1 outline-offset-1 41 41 disabled:bg-border-light disabled:border-border-light disabled:text-border disabled:hover:text-border 42 42 ${className} 43 43 `} ··· 75 75 bg-bg-page outline-transparent 76 76 rounded-md text-base font-bold text-accent-contrast 77 77 flex gap-2 items-center justify-center shrink-0 78 - transparent-outline hover:outline-accent-contrast outline-offset-1 78 + transparent-outline focus:outline-accent-contrast hover:outline-accent-contrast outline-offset-1 79 79 border border-accent-contrast 80 80 disabled:bg-border-light disabled:text-border disabled:hover:text-border 81 81 ${props.className} ··· 111 111 ); 112 112 }); 113 113 ButtonTertiary.displayName = "ButtonTertiary"; 114 - 115 - export const HoverButton = (props: { 116 - id?: string; 117 - icon: React.ReactNode; 118 - label: string; 119 - background: string; 120 - text: string; 121 - backgroundImage?: React.CSSProperties; 122 - noLabelOnMobile?: boolean; 123 - }) => { 124 - return ( 125 - <div className="sm:w-8 sm:h-8 relative "> 126 - <div 127 - id={props.id} 128 - className={` 129 - z-10 group/hover-button 130 - w-max h-max rounded-full p-1 flex gap-2 131 - sm:absolute top-0 left-0 132 - place-items-center justify-center 133 - ${props.background} ${props.text}`} 134 - style={props.backgroundImage} 135 - > 136 - {props.icon} 137 - <div 138 - className={`font-bold pr-[6px] sm:group-hover/hover-button:block ${props.noLabelOnMobile ? "hidden" : "sm:hidden"}`} 139 - > 140 - {props.label} 141 - </div> 142 - </div> 143 - </div> 144 - ); 145 - }; 146 114 147 115 export const TooltipButton = (props: { 148 116 onMouseDown?: (e: React.MouseEvent) => void | Promise<void>;
+3 -10
components/HelpPopover.tsx
··· 8 8 import { useEntitySetContext } from "./EntitySetProvider"; 9 9 import Link from "next/link"; 10 10 import { useState } from "react"; 11 - import { HoverButton } from "./Buttons"; 11 + import { ActionButton } from "components/ActionBar/ActionButton"; 12 12 13 13 export const HelpPopover = (props: { noShortcuts?: boolean }) => { 14 14 let entity_set = useEntitySetContext(); 15 15 return entity_set.permissions.write ? ( 16 16 <Popover 17 + asChild 17 18 className="max-w-xs w-full" 18 - trigger={ 19 - <HoverButton 20 - icon={<HelpSmall />} 21 - noLabelOnMobile 22 - label="About" 23 - background="bg-accent-1" 24 - text="text-accent-2" 25 - /> 26 - } 19 + trigger={<ActionButton icon={<HelpSmall />} label="About" />} 27 20 > 28 21 <div className="flex flex-col text-sm gap-2 text-secondary"> 29 22 {/* about leaflet */}
+9 -16
components/HomeButton.tsx
··· 1 1 import Link from "next/link"; 2 2 import { useEntitySetContext } from "./EntitySetProvider"; 3 3 import { AddToHomeSmall, HomeSmall } from "./Icons"; 4 - import { HoverButton } from "./Buttons"; 4 + import { ActionButton } from "components/ActionBar/ActionButton"; 5 5 import { useParams, useSearchParams } from "next/navigation"; 6 6 import { useIdentityData } from "./IdentityProvider"; 7 7 import { useReplicache } from "src/replicache"; ··· 15 15 if (permissions.write) 16 16 return ( 17 17 <> 18 - <Link href="/home" prefetch> 19 - <HoverButton 20 - noLabelOnMobile 21 - icon={<HomeSmall />} 22 - label="Go Home" 23 - background="bg-accent-1" 24 - text="text-accent-2" 25 - /> 18 + <Link 19 + href="/home" 20 + prefetch 21 + className="hover:no-underline first:mr-2" 22 + style={{ textDecorationLine: "none !important" }} 23 + > 24 + <ActionButton icon={<HomeSmall />} label="Go Home" /> 26 25 </Link> 27 26 <AddToHomeButton /> 28 27 </> ··· 67 66 }); 68 67 }} 69 68 > 70 - <HoverButton 71 - noLabelOnMobile 72 - icon={<AddToHomeSmall />} 73 - label="Add to Home" 74 - background="bg-accent-1" 75 - text="text-accent-2" 76 - /> 69 + <ActionButton icon={<AddToHomeSmall />} label="Add to Home" /> 77 70 </button> 78 71 ); 79 72 };
+1 -1
components/Icons.tsx
··· 1615 1615 let { arrowFill, arrowStroke, ...passDownProps } = props; 1616 1616 return ( 1617 1617 <svg 1618 - {...{ passDownProps }} 1618 + {...passDownProps} 1619 1619 width="16" 1620 1620 height="8" 1621 1621 viewBox="0 0 16 8"
+4 -1
components/Layout.tsx
··· 22 22 border?: string; 23 23 className?: string; 24 24 onOpenChange?: (o: boolean) => void; 25 + asChild?: boolean; 25 26 }) => { 26 27 return ( 27 28 <DropdownMenu.Root onOpenChange={props.onOpenChange} open={props.open}> 28 - <DropdownMenu.Trigger>{props.trigger}</DropdownMenu.Trigger> 29 + <DropdownMenu.Trigger asChild={props.asChild}> 30 + {props.trigger} 31 + </DropdownMenu.Trigger> 29 32 <DropdownMenu.Portal> 30 33 <NestedCardThemeProvider> 31 34 <DropdownMenu.Content
+17
components/LoginButton.tsx
··· 4 4 import { Popover } from "./Popover"; 5 5 import LoginForm from "app/login/LoginForm"; 6 6 import { ButtonPrimary } from "./Buttons"; 7 + import { ActionButton } from "./ActionBar/ActionButton"; 8 + import { AccountSmall } from "./Icons"; 7 9 8 10 export function LoginButton() { 9 11 let identityData = useIdentityData(); ··· 21 23 </Popover> 22 24 ); 23 25 } 26 + 27 + export function LoginActionButton() { 28 + let identityData = useIdentityData(); 29 + if (identityData.identity) return null; 30 + return ( 31 + <Popover 32 + asChild 33 + trigger={ 34 + <ActionButton secondary icon={<AccountSmall />} label="Sign In" /> 35 + } 36 + > 37 + <LoginForm /> 38 + </Popover> 39 + ); 40 + }
-52
components/MobileFooter.tsx
··· 1 - "use client"; 2 - import { useUIState } from "src/useUIState"; 3 - import { Media } from "./Media"; 4 - import { ThemePopover } from "./ThemeManager/ThemeSetter"; 5 - import { Toolbar } from "components/Toolbar"; 6 - import { ShareOptions } from "./ShareOptions"; 7 - import { HomeButton } from "./HomeButton"; 8 - import { useEntitySetContext } from "./EntitySetProvider"; 9 - import { HelpPopover } from "./HelpPopover"; 10 - import { Watermark } from "./Watermark"; 11 - import { PublishToPublication } from "./ShareOptions/PublicationOptions"; 12 - 13 - export function MobileFooter(props: { entityID: string }) { 14 - let focusedBlock = useUIState((s) => s.focusedEntity); 15 - let entity_set = useEntitySetContext(); 16 - 17 - return ( 18 - <Media mobile className="mobileFooter w-full z-10 touch-none -mt-4 "> 19 - {focusedBlock && 20 - focusedBlock.entityType == "block" && 21 - entity_set.permissions.write ? ( 22 - <div 23 - className="w-full z-10 p-2 flex bg-bg-page pwa-padding-bottom" 24 - onMouseDown={(e) => { 25 - if (e.currentTarget === e.target) e.preventDefault(); 26 - }} 27 - > 28 - <Toolbar 29 - pageID={focusedBlock.parent} 30 - blockID={focusedBlock.entityID} 31 - /> 32 - </div> 33 - ) : entity_set.permissions.write ? ( 34 - <div className="z-10 pwa-padding-bottom px-2 pt-0.5 flex justify-between"> 35 - <div className="flex flex-row gap-[6px]"> 36 - <HomeButton /> 37 - </div> 38 - <div className="flex flex-row gap-[6px] items-center "> 39 - <HelpPopover /> 40 - <ThemePopover entityID={props.entityID} /> 41 - <ShareOptions /> 42 - <PublishToPublication /> 43 - </div> 44 - </div> 45 - ) : ( 46 - <div className="pb-2 px-2 z-10 flex justify-end"> 47 - <Watermark mobile /> 48 - </div> 49 - )} 50 - </Media> 51 - ); 52 - }
+3 -9
components/ShareOptions/index.tsx
··· 5 5 import { useEntitySetContext } from "components/EntitySetProvider"; 6 6 import { useSmoker } from "components/Toast"; 7 7 import { Menu, MenuItem } from "components/Layout"; 8 - import { HoverButton } from "components/Buttons"; 8 + import { ActionButton } from "components/ActionBar/ActionButton"; 9 9 import useSWR from "swr"; 10 10 import { useTemplateState } from "app/home/CreateNewButton"; 11 11 import LoginForm from "app/login/LoginForm"; ··· 43 43 44 44 return ( 45 45 <Menu 46 + asChild 46 47 className="max-w-xs" 47 48 onOpenChange={() => { 48 49 setMenuState("default"); 49 50 }} 50 - trigger={ 51 - <HoverButton 52 - icon=<ShareSmall /> 53 - label="Share" 54 - background="bg-accent-1" 55 - text="text-accent-2" 56 - /> 57 - } 51 + trigger={<ActionButton icon=<ShareSmall /> primary label="Share" />} 58 52 > 59 53 {menuState === "login" ? ( 60 54 <div className="px-3 py-1">
+3 -13
components/ThemeManager/ThemeSetter.tsx
··· 37 37 import { useEntitySetContext } from "components/EntitySetProvider"; 38 38 import { isIOS, useViewportSize } from "@react-aria/utils"; 39 39 import { onMouseDown } from "src/utils/iosInputMouseDown"; 40 - import { HoverButton } from "components/Buttons"; 40 + import { ActionButton } from "components/ActionBar/ActionButton"; 41 41 import { useInitialPageLoad } from "components/InitialPageLoadProvider"; 42 42 43 43 export type pickers = ··· 119 119 return ( 120 120 <> 121 121 <Popover.Root> 122 - <Popover.Trigger> 123 - <HoverButton 124 - icon={<PaintSmall />} 125 - noLabelOnMobile 126 - label="Theme" 127 - background="bg-bg-page" 128 - text="text-bg-page" 129 - backgroundImage={{ 130 - backgroundColor: leafletValue.toString("hex"), 131 - backgroundImage: gradient, 132 - }} 133 - /> 122 + <Popover.Trigger asChild> 123 + <ActionButton icon={<PaintSmall />} label="Theme" /> 134 124 </Popover.Trigger> 135 125 <Popover.Portal> 136 126 <Popover.Content
+1 -1
components/Toolbar/index.tsx
··· 81 81 82 82 return ( 83 83 <Tooltip.Provider> 84 - <div className="toolbar flex gap-2 items-center justify-between w-full h-[26px]"> 84 + <div className="toolbar flex gap-2 items-center justify-between w-full h-[calc(21px+var(--safe-padding-bottom))]"> 85 85 <div className="toolbarOptions flex gap-1 sm:gap-[6px] items-center grow"> 86 86 {toolbarState === "default" ? ( 87 87 <TextToolbar
+1 -1
components/Watermark.tsx
··· 13 13 className="hover:no-underline w-fit italic" 14 14 target="_blank" 15 15 > 16 - <div className="sm:mb-2 sm:mr-4 group/watermark flex sm:flex-col gap-2 items-center justify-center "> 16 + <div className="sm:mb-2 sm:ml-4 group/watermark flex sm:flex-col gap-2 items-center justify-center "> 17 17 <div 18 18 className="sm:hidden group-hover/watermark:block sm:rotate-180 sm:py-1 sm:px-0 px-1 w-max rounded-md h-fit whitespace-nowrap text-sm text-tertiary" 19 19 style={{
-52
package-lock.json
··· 16 16 "@atproto/sync": "^0.1.17", 17 17 "@atproto/syntax": "^0.3.3", 18 18 "@atproto/xrpc": "^0.6.9", 19 - "@handlewithcare/react-prosemirror": "^2.4.0", 20 19 "@mdx-js/loader": "^3.1.0", 21 20 "@mdx-js/react": "^3.1.0", 22 - <<<<<<< HEAD 23 21 "@next/mdx": "15.3.2", 24 - "@nytimes/react-prosemirror": "^0.6.1", 25 22 "@radix-ui/react-dropdown-menu": "^2.1.14", 26 23 "@radix-ui/react-popover": "^1.1.13", 27 24 "@radix-ui/react-slider": "^1.3.4", 28 25 "@radix-ui/react-tooltip": "^1.2.6", 29 - ======= 30 - "@next/mdx": "^15.0.3", 31 - "@radix-ui/react-dropdown-menu": "^2.1.1", 32 - "@radix-ui/react-popover": "^1.0.7", 33 - "@radix-ui/react-slider": "^1.1.2", 34 - "@radix-ui/react-tooltip": "^1.1.2", 35 - >>>>>>> refactor/remove-prosemirror-react 36 26 "@react-aria/utils": "^3.24.1", 37 27 "@react-spring/web": "^10.0.0-beta.0", 38 28 "@rocicorp/undo": "^0.2.1", ··· 1769 1759 "tslib": "^2.8.0" 1770 1760 } 1771 1761 }, 1772 - "node_modules/@handlewithcare/react-prosemirror": { 1773 - "version": "2.4.0", 1774 - "resolved": "https://registry.npmjs.org/@handlewithcare/react-prosemirror/-/react-prosemirror-2.4.0.tgz", 1775 - "integrity": "sha512-Asiqb+BVEWNKZ8FS8aEdBRsdQqAEgF2GIUh/zpESfP1QUlvVHd+AOMjxHM+iCtrCnAD8Jy3vEgnWdwp5wV10gQ==", 1776 - "license": "Apache-2.0", 1777 - "dependencies": { 1778 - "classnames": "^2.3.2" 1779 - }, 1780 - "engines": { 1781 - "node": ">=16.9" 1782 - }, 1783 - "peerDependencies": { 1784 - "prosemirror-model": "^1.0.0", 1785 - "prosemirror-state": "^1.0.0", 1786 - "prosemirror-view": "1.37.1", 1787 - "react": ">=17 <=19.1.0", 1788 - "react-dom": ">=17 <=19.1.0", 1789 - "react-reconciler": "*" 1790 - } 1791 - }, 1792 1762 "node_modules/@humanwhocodes/config-array": { 1793 1763 "version": "0.11.14", 1794 1764 "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", ··· 6928 6898 "engines": { 6929 6899 "node": ">=18" 6930 6900 } 6931 - }, 6932 - "node_modules/classnames": { 6933 - "version": "2.5.1", 6934 - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", 6935 - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", 6936 - "license": "MIT" 6937 6901 }, 6938 6902 "node_modules/cli-color": { 6939 6903 "version": "2.0.4", ··· 13430 13394 "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", 13431 13395 "dev": true, 13432 13396 "license": "MIT" 13433 - }, 13434 - "node_modules/react-reconciler": { 13435 - "version": "0.32.0", 13436 - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.32.0.tgz", 13437 - "integrity": "sha512-2NPMOzgTlG0ZWdIf3qG+dcbLSoAc/uLfOwckc3ofy5sSK0pLJqnQLpUFxvGcN2rlXSjnVtGeeFLNimCQEj5gOQ==", 13438 - "license": "MIT", 13439 - "peer": true, 13440 - "dependencies": { 13441 - "scheduler": "^0.26.0" 13442 - }, 13443 - "engines": { 13444 - "node": ">=0.10.0" 13445 - }, 13446 - "peerDependencies": { 13447 - "react": "^19.1.0" 13448 - } 13449 13397 }, 13450 13398 "node_modules/react-remove-scroll": { 13451 13399 "version": "2.6.3",