mirror of
https://github.com/logseq/logseq.git
synced 2026-04-24 14:14:55 +00:00
enhance(ui): refactor mobile UI components for improved readability and maintainability
This commit is contained in:
@@ -6,7 +6,7 @@ import React, {
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
} from 'react'
|
||||
import {
|
||||
Sheet,
|
||||
SheetStack,
|
||||
@@ -15,14 +15,14 @@ import {
|
||||
usePageScrollData,
|
||||
SheetViewProps,
|
||||
createComponentId,
|
||||
} from "@silk-hq/components";
|
||||
import "./SheetWithDepth.css";
|
||||
} from '@silk-hq/components'
|
||||
import './SheetWithDepth.css'
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Id
|
||||
// ================================================================================================
|
||||
|
||||
const sheetWithDepthStackId = createComponentId();
|
||||
const sheetWithDepthStackId = createComponentId()
|
||||
|
||||
// ================================================================================================
|
||||
// StackRoot Context
|
||||
@@ -37,16 +37,16 @@ type SheetWithDepthStackRootContextValue = {
|
||||
|
||||
const SheetWithDepthStackRootContext = createContext<SheetWithDepthStackRootContextValue | null>(
|
||||
null
|
||||
);
|
||||
)
|
||||
const useSheetWithDepthStackRootContext = () => {
|
||||
const context = useContext(SheetWithDepthStackRootContext);
|
||||
const context = useContext(SheetWithDepthStackRootContext)
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useSheetWithDepthStackRootContext must be used within a SheetWithDepthStackRootContext"
|
||||
);
|
||||
'useSheetWithDepthStackRootContext must be used within a SheetWithDepthStackRootContext'
|
||||
)
|
||||
}
|
||||
return context;
|
||||
};
|
||||
return context
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
// View Context
|
||||
@@ -54,14 +54,14 @@ const useSheetWithDepthStackRootContext = () => {
|
||||
|
||||
const SheetWithDepthViewContext = createContext<{
|
||||
indexInStack: number;
|
||||
} | null>(null);
|
||||
} | null>(null)
|
||||
const useSheetWithDepthViewContext = () => {
|
||||
const context = useContext(SheetWithDepthViewContext);
|
||||
const context = useContext(SheetWithDepthViewContext)
|
||||
if (!context) {
|
||||
throw new Error("useSheetWithDepthViewContext must be used within a SheetWithDepthViewContext");
|
||||
throw new Error('useSheetWithDepthViewContext must be used within a SheetWithDepthViewContext')
|
||||
}
|
||||
return context;
|
||||
};
|
||||
return context
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
// StackRoot
|
||||
@@ -71,10 +71,10 @@ const SheetWithDepthStackRoot = React.forwardRef<
|
||||
React.ElementRef<typeof SheetStack.Root>,
|
||||
React.ComponentProps<typeof SheetStack.Root>
|
||||
>(({ children, ...restProps }, ref) => {
|
||||
const stackBackgroundRef = useRef<HTMLDivElement | null>(null);
|
||||
const stackFirstSheetBackdropRef = useRef<HTMLDivElement | null>(null);
|
||||
const stackBackgroundRef = useRef<HTMLDivElement | null>(null)
|
||||
const stackFirstSheetBackdropRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
const [stackingCount, setStackingCount] = useState(0);
|
||||
const [stackingCount, setStackingCount] = useState(0)
|
||||
|
||||
const contextValue = useMemo(
|
||||
() => ({
|
||||
@@ -84,7 +84,7 @@ const SheetWithDepthStackRoot = React.forwardRef<
|
||||
setStackingCount,
|
||||
}),
|
||||
[stackingCount]
|
||||
);
|
||||
)
|
||||
|
||||
return (
|
||||
<SheetWithDepthStackRootContext.Provider value={contextValue}>
|
||||
@@ -92,9 +92,9 @@ const SheetWithDepthStackRoot = React.forwardRef<
|
||||
{children}
|
||||
</SheetStack.Root>
|
||||
</SheetWithDepthStackRootContext.Provider>
|
||||
);
|
||||
});
|
||||
SheetWithDepthStackRoot.displayName = "SheetWithDepthStack.Root";
|
||||
)
|
||||
})
|
||||
SheetWithDepthStackRoot.displayName = 'SheetWithDepthStack.Root'
|
||||
|
||||
// ================================================================================================
|
||||
// StackSceneryOutlets
|
||||
@@ -103,27 +103,27 @@ SheetWithDepthStackRoot.displayName = "SheetWithDepthStack.Root";
|
||||
// The SheetStack outlets that define the scenery of the stack
|
||||
// (i.e. the content underneath) for the depth effect.
|
||||
|
||||
const initialTopOffset = "max(env(safe-area-inset-top), 1.3vh)";
|
||||
const initialTopOffset = 'max(env(safe-area-inset-top), 1.3vh)'
|
||||
|
||||
const SheetWithDepthStackSceneryOutlets = React.forwardRef<
|
||||
React.ElementRef<typeof SheetStack.Outlet>,
|
||||
Omit<React.ComponentProps<typeof SheetStack.Outlet>, "asChild">
|
||||
Omit<React.ComponentProps<typeof SheetStack.Outlet>, 'asChild'>
|
||||
>(({ children, className, stackingAnimation: stackingAnimationFromProps, ...restProps }, ref) => {
|
||||
const { stackBackgroundRef, stackFirstSheetBackdropRef } = useSheetWithDepthStackRootContext();
|
||||
const { stackBackgroundRef, stackFirstSheetBackdropRef } = useSheetWithDepthStackRootContext()
|
||||
|
||||
const { nativePageScrollReplaced } = usePageScrollData();
|
||||
const { nativePageScrollReplaced } = usePageScrollData()
|
||||
|
||||
const [iOSStandalone, setiOSStandalone] = useState(false);
|
||||
const [iOSStandalone, setiOSStandalone] = useState(false)
|
||||
useEffect(() => {
|
||||
setiOSStandalone(
|
||||
// @ts-ignore
|
||||
window.navigator.standalone && window.navigator.userAgent?.match(/iPhone|iPad/i)
|
||||
);
|
||||
}, []);
|
||||
)
|
||||
}, [])
|
||||
|
||||
const stackingAnimation: React.ComponentPropsWithoutRef<
|
||||
typeof Sheet.Outlet
|
||||
>["stackingAnimation"] = {
|
||||
>['stackingAnimation'] = {
|
||||
// Clipping & border-radius. We have a different animation
|
||||
// when the native page scroll is replaced, and in iOS
|
||||
// standalone mode.
|
||||
@@ -133,39 +133,39 @@ const SheetWithDepthStackSceneryOutlets = React.forwardRef<
|
||||
// border-radius because the corners are hidden by the
|
||||
// screen corners. So we just set the border-radius to
|
||||
// the needed value.
|
||||
{
|
||||
overflow: "clip",
|
||||
borderRadius: "24px",
|
||||
transformOrigin: "50% 0",
|
||||
}
|
||||
{
|
||||
overflow: 'clip',
|
||||
borderRadius: '24px',
|
||||
transformOrigin: '50% 0',
|
||||
}
|
||||
: // Outside of iOS standalone mode we do animate
|
||||
// the border-radius because the scenery is a visible
|
||||
// rectangle.
|
||||
{
|
||||
overflow: "clip",
|
||||
borderRadius: ({ progress }: any) => Math.min(progress * 24, 24) + "px",
|
||||
transformOrigin: "50% 0",
|
||||
}
|
||||
{
|
||||
overflow: 'clip',
|
||||
borderRadius: ({ progress }: any) => Math.min(progress * 24, 24) + 'px',
|
||||
transformOrigin: '50% 0',
|
||||
}
|
||||
: // When the native page scroll is not replaced we
|
||||
// need to use the Silk's special clip properties to cut
|
||||
// off the rest of the page.
|
||||
{
|
||||
clipBoundary: "layout-viewport",
|
||||
clipBorderRadius: "24px",
|
||||
clipTransformOrigin: "50% 0",
|
||||
}),
|
||||
{
|
||||
clipBoundary: 'layout-viewport',
|
||||
clipBorderRadius: '24px',
|
||||
clipTransformOrigin: '50% 0',
|
||||
}),
|
||||
|
||||
// Translate & scale
|
||||
translateY: ({ progress }) =>
|
||||
progress <= 1
|
||||
? "calc(" + progress + " * " + initialTopOffset + ")"
|
||||
? 'calc(' + progress + ' * ' + initialTopOffset + ')'
|
||||
: // prettier-ignore
|
||||
"calc(" + initialTopOffset + " + 0.65vh * " + (progress - 1) + ")",
|
||||
'calc(' + initialTopOffset + ' + 0.65vh * ' + (progress - 1) + ')',
|
||||
scale: [1, 0.91],
|
||||
|
||||
// We merge animations coming from the props
|
||||
...stackingAnimationFromProps,
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -176,7 +176,7 @@ const SheetWithDepthStackSceneryOutlets = React.forwardRef<
|
||||
/>
|
||||
{/* Element used as a container for the content under the stack. */}
|
||||
<SheetStack.Outlet
|
||||
className={`SheetWithDepth-stackSceneryContainer ${className ?? ""}`.trim()}
|
||||
className={`SheetWithDepth-stackSceneryContainer ${className ?? ''}`.trim()}
|
||||
forComponent={sheetWithDepthStackId}
|
||||
stackingAnimation={stackingAnimation}
|
||||
{...restProps}
|
||||
@@ -190,17 +190,17 @@ const SheetWithDepthStackSceneryOutlets = React.forwardRef<
|
||||
/>
|
||||
</SheetStack.Outlet>
|
||||
</>
|
||||
);
|
||||
});
|
||||
SheetWithDepthStackSceneryOutlets.displayName = "SheetWithDepthStack.SceneryOutlets";
|
||||
)
|
||||
})
|
||||
SheetWithDepthStackSceneryOutlets.displayName = 'SheetWithDepthStack.SceneryOutlets'
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type SheetWithDepthRootProps = Omit<SheetRootProps, "license"> & {
|
||||
license?: SheetRootProps["license"];
|
||||
type SheetWithDepthRootProps = Omit<SheetRootProps, 'license'> & {
|
||||
license?: SheetRootProps['license'];
|
||||
};
|
||||
|
||||
const SheetWithDepthRoot = React.forwardRef<
|
||||
@@ -208,10 +208,10 @@ const SheetWithDepthRoot = React.forwardRef<
|
||||
SheetWithDepthRootProps
|
||||
>((props, ref) => {
|
||||
return (
|
||||
<Sheet.Root license="commercial" forComponent={sheetWithDepthStackId} {...props} ref={ref} />
|
||||
);
|
||||
});
|
||||
SheetWithDepthRoot.displayName = "SheetWithDepth.Root";
|
||||
<Sheet.Root license="commercial" forComponent={sheetWithDepthStackId} {...props} ref={ref}/>
|
||||
)
|
||||
})
|
||||
SheetWithDepthRoot.displayName = 'SheetWithDepth.Root'
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
@@ -237,58 +237,58 @@ const SheetWithDepthView = React.forwardRef<
|
||||
|
||||
stackBackgroundRef,
|
||||
stackFirstSheetBackdropRef,
|
||||
} = useSheetWithDepthStackRootContext();
|
||||
} = useSheetWithDepthStackRootContext()
|
||||
|
||||
const [indexInStack, setIndexInStack] = useState(0);
|
||||
const [travelStatus, setTravelStatus] = useState("idleOutside");
|
||||
const [indexInStack, setIndexInStack] = useState(0)
|
||||
const [travelStatus, setTravelStatus] = useState('idleOutside')
|
||||
|
||||
//
|
||||
// Define a dimming overlay
|
||||
|
||||
const { setDimmingOverlayOpacity, animateDimmingOverlayOpacity } = useThemeColorDimmingOverlay({
|
||||
elementRef: stackBackgroundRef,
|
||||
dimmingColor: "rgb(0, 0, 0)",
|
||||
});
|
||||
dimmingColor: 'rgb(0, 0, 0)',
|
||||
})
|
||||
|
||||
//
|
||||
// travelStatusChangeHandler
|
||||
|
||||
const travelStatusChangeHandler = useCallback<
|
||||
NonNullable<SheetViewProps["onTravelStatusChange"]>
|
||||
NonNullable<SheetViewProps['onTravelStatusChange']>
|
||||
>(
|
||||
(newTravelStatus) => {
|
||||
// Set indexInStack & stackingCount
|
||||
if (travelStatus !== "stepping" && newTravelStatus === "idleInside") {
|
||||
setStackingCount((prevStackingCount: number) => prevStackingCount + 1);
|
||||
if (travelStatus !== 'stepping' && newTravelStatus === 'idleInside') {
|
||||
setStackingCount((prevStackingCount: number) => prevStackingCount + 1)
|
||||
if (indexInStack === 0) {
|
||||
setIndexInStack(stackingCount + 1);
|
||||
setIndexInStack(stackingCount + 1)
|
||||
}
|
||||
}
|
||||
//
|
||||
else if (newTravelStatus === "idleOutside") {
|
||||
setStackingCount((prevStackingCount: number) => prevStackingCount - 1);
|
||||
setIndexInStack(0);
|
||||
else if (newTravelStatus === 'idleOutside') {
|
||||
setStackingCount((prevStackingCount: number) => prevStackingCount - 1)
|
||||
setIndexInStack(0)
|
||||
}
|
||||
|
||||
// Animate on entering
|
||||
if (newTravelStatus === "entering" && stackingCount === 0) {
|
||||
animateDimmingOverlayOpacity({ keyframes: [0, 1] });
|
||||
if (newTravelStatus === 'entering' && stackingCount === 0) {
|
||||
animateDimmingOverlayOpacity({ keyframes: [0, 1] })
|
||||
animate(stackFirstSheetBackdropRef.current as HTMLElement, {
|
||||
opacity: [0, 0.33],
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
// Animate on exiting
|
||||
if (newTravelStatus === "exiting" && stackingCount === 1) {
|
||||
animateDimmingOverlayOpacity({ keyframes: [1, 0] });
|
||||
if (newTravelStatus === 'exiting' && stackingCount === 1) {
|
||||
animateDimmingOverlayOpacity({ keyframes: [1, 0] })
|
||||
animate(stackFirstSheetBackdropRef.current as HTMLElement, {
|
||||
opacity: [0.33, 0],
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
// Set the state
|
||||
onTravelStatusChange?.(newTravelStatus);
|
||||
setTravelStatus(newTravelStatus);
|
||||
onTravelStatusChange?.(newTravelStatus)
|
||||
setTravelStatus(newTravelStatus)
|
||||
},
|
||||
[
|
||||
travelStatus,
|
||||
@@ -299,26 +299,26 @@ const SheetWithDepthView = React.forwardRef<
|
||||
animateDimmingOverlayOpacity,
|
||||
onTravelStatusChange,
|
||||
]
|
||||
);
|
||||
)
|
||||
|
||||
//
|
||||
// travelHandler
|
||||
|
||||
const travelHandler = useMemo(() => {
|
||||
if (indexInStack === 1 && travelStatus !== "entering" && travelStatus !== "exiting") {
|
||||
const handler: NonNullable<SheetViewProps["onTravel"]> = ({ progress, ...rest }) => {
|
||||
setDimmingOverlayOpacity(progress);
|
||||
if (indexInStack === 1 && travelStatus !== 'entering' && travelStatus !== 'exiting') {
|
||||
const handler: NonNullable<SheetViewProps['onTravel']> = ({ progress, ...rest }) => {
|
||||
setDimmingOverlayOpacity(progress)
|
||||
stackFirstSheetBackdropRef.current?.style.setProperty(
|
||||
"opacity",
|
||||
'opacity',
|
||||
(progress * 0.33) as unknown as string
|
||||
);
|
||||
travelHandlerFromProps?.({ progress, ...rest });
|
||||
};
|
||||
return handler;
|
||||
)
|
||||
travelHandlerFromProps?.({ progress, ...rest })
|
||||
}
|
||||
return handler
|
||||
} else {
|
||||
return travelHandlerFromProps;
|
||||
return travelHandlerFromProps
|
||||
}
|
||||
}, [indexInStack, travelStatus, stackFirstSheetBackdropRef, setDimmingOverlayOpacity]);
|
||||
}, [indexInStack, travelStatus, stackFirstSheetBackdropRef, setDimmingOverlayOpacity])
|
||||
|
||||
//
|
||||
// Return
|
||||
@@ -326,7 +326,7 @@ const SheetWithDepthView = React.forwardRef<
|
||||
return (
|
||||
<SheetWithDepthViewContext.Provider value={{ indexInStack }}>
|
||||
<Sheet.View
|
||||
className={`SheetWithDepth-view ${className ?? ""}`.trim()}
|
||||
className={`SheetWithDepth-view ${className ?? ''}`.trim()}
|
||||
contentPlacement="bottom"
|
||||
onTravelStatusChange={travelStatusChangeHandler}
|
||||
onTravel={travelHandler}
|
||||
@@ -337,10 +337,10 @@ const SheetWithDepthView = React.forwardRef<
|
||||
{children}
|
||||
</Sheet.View>
|
||||
</SheetWithDepthViewContext.Provider>
|
||||
);
|
||||
)
|
||||
}
|
||||
);
|
||||
SheetWithDepthView.displayName = "SheetWithDepth.View";
|
||||
)
|
||||
SheetWithDepthView.displayName = 'SheetWithDepth.View'
|
||||
|
||||
// ================================================================================================
|
||||
// Backdrop
|
||||
@@ -351,8 +351,8 @@ const SheetWithDepthBackdrop = React.forwardRef<
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Backdrop>
|
||||
// @ts-ignore
|
||||
>(({ className, ...restProps }, ref) => {
|
||||
const { stackingCount } = useSheetWithDepthStackRootContext();
|
||||
const { indexInStack } = useSheetWithDepthViewContext();
|
||||
const { stackingCount } = useSheetWithDepthStackRootContext()
|
||||
const { indexInStack } = useSheetWithDepthViewContext()
|
||||
|
||||
return (
|
||||
// We don't render the Backdrop for the first sheet in the
|
||||
@@ -361,15 +361,15 @@ const SheetWithDepthBackdrop = React.forwardRef<
|
||||
stackingCount > 0 &&
|
||||
indexInStack !== 1 && (
|
||||
<Sheet.Backdrop
|
||||
className={`SheetWithDepth-backdrop ${className ?? ""}`.trim()}
|
||||
className={`SheetWithDepth-backdrop ${className ?? ''}`.trim()}
|
||||
travelAnimation={{ opacity: [0, 0.33] }}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
);
|
||||
});
|
||||
SheetWithDepthBackdrop.displayName = "SheetWithDepth.Backdrop";
|
||||
)
|
||||
})
|
||||
SheetWithDepthBackdrop.displayName = 'SheetWithDepth.Backdrop'
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
@@ -381,42 +381,42 @@ const SheetWithDepthContent = React.forwardRef<
|
||||
>(({ children, className, stackingAnimation, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Content
|
||||
className={`SheetWithDepth-content ${className ?? ""}`.trim()}
|
||||
className={`SheetWithDepth-content ${className ?? ''}`.trim()}
|
||||
stackingAnimation={{
|
||||
translateY: ({ progress }) =>
|
||||
progress <= 1
|
||||
? progress * -1.3 + "vh"
|
||||
? progress * -1.3 + 'vh'
|
||||
: // prettier-ignore
|
||||
"calc(-1.3vh + 0.65vh * " + (progress - 1) + ")",
|
||||
'calc(-1.3vh + 0.65vh * ' + (progress - 1) + ')',
|
||||
scale: [1, 0.91],
|
||||
transformOrigin: "50% 0",
|
||||
transformOrigin: '50% 0',
|
||||
...stackingAnimation,
|
||||
}}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
<Sheet.BleedingBackground className="SheetWithDepth-bleedingBackground" />
|
||||
<Sheet.BleedingBackground className="SheetWithDepth-bleedingBackground"/>
|
||||
{children}
|
||||
</Sheet.Content>
|
||||
);
|
||||
});
|
||||
SheetWithDepthContent.displayName = "SheetWithDepth.Content";
|
||||
)
|
||||
})
|
||||
SheetWithDepthContent.displayName = 'SheetWithDepth.Content'
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged components
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDepthPortal = Sheet.Portal;
|
||||
const SheetWithDepthTrigger = Sheet.Trigger;
|
||||
const SheetWithDepthHandle = Sheet.Handle;
|
||||
const SheetWithDepthOutlet = Sheet.Outlet;
|
||||
const SheetWithDepthTitle = Sheet.Title;
|
||||
const SheetWithDepthDescription = Sheet.Description;
|
||||
const SheetWithDepthPortal = Sheet.Portal
|
||||
const SheetWithDepthTrigger = Sheet.Trigger
|
||||
const SheetWithDepthHandle = Sheet.Handle
|
||||
const SheetWithDepthOutlet = Sheet.Outlet
|
||||
const SheetWithDepthTitle = Sheet.Title
|
||||
const SheetWithDepthDescription = Sheet.Description
|
||||
|
||||
export const SheetWithDepthStack = {
|
||||
Root: SheetWithDepthStackRoot,
|
||||
SceneryOutlets: SheetWithDepthStackSceneryOutlets,
|
||||
};
|
||||
}
|
||||
|
||||
export const SheetWithDepth = {
|
||||
Root: SheetWithDepthRoot,
|
||||
@@ -429,4 +429,4 @@ export const SheetWithDepth = {
|
||||
Outlet: SheetWithDepthOutlet,
|
||||
Title: SheetWithDepthTitle,
|
||||
Description: SheetWithDepthDescription,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
:root {
|
||||
--ls-page-title-size: 26px;
|
||||
--silk-topbar-height: 48px;
|
||||
--silk-topbar-inner-height: 32px;
|
||||
--silk-tabbar-bottom-paddding: 12px;
|
||||
}
|
||||
|
||||
@@ -14,11 +14,20 @@ html.is-native-ios {
|
||||
}
|
||||
|
||||
html.is-native-android {
|
||||
--silk-topbar-inner-padding-top: 10px;
|
||||
--silk-topbar-inner-height: 40px;
|
||||
--silk-topbar-inner-padding-bottom: 6px;
|
||||
|
||||
.app-silk-topbar {}
|
||||
}
|
||||
|
||||
#mobile-editor-toolbar {
|
||||
}
|
||||
|
||||
#main-container {
|
||||
overflow-y: visible;
|
||||
}
|
||||
|
||||
html.has-mobile-keyboard {
|
||||
body {
|
||||
@apply overflow-hidden
|
||||
@@ -140,9 +149,7 @@ a, button {
|
||||
}
|
||||
}
|
||||
|
||||
.app-silk-sheet-scroll-content {
|
||||
height: 92vh;
|
||||
}
|
||||
.app-silk-depth-sheet-content {}
|
||||
}
|
||||
|
||||
.block-content-or-editor-inner {
|
||||
@@ -293,8 +300,8 @@ a, button {
|
||||
@apply bg-gray-01 min-h-[100svh] overflow-x-hidden;
|
||||
}
|
||||
|
||||
.app-silk-sheet-scroll-content {
|
||||
@apply flex flex-col items-center;
|
||||
.app-silk-depth-sheet-content {
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.BottomSheet-bleedingBackground,
|
||||
@@ -315,7 +322,6 @@ a, button {
|
||||
overflow: hidden;
|
||||
overflow: clip;
|
||||
position: relative;
|
||||
display: grid;
|
||||
}
|
||||
|
||||
html[data-silk-native-page-scroll-replaced=false] .app-silk-index-scroll-view {
|
||||
@@ -329,11 +335,15 @@ html[data-silk-native-page-scroll-replaced=false] .app-silk-index-scroll-view {
|
||||
@apply p-4 flex flex-col gap-3 bg-gray-01;
|
||||
|
||||
&[data-tab=search] {
|
||||
--silk-topbar-height: 2px;
|
||||
--silk-topbar-inner-height: 2px;
|
||||
}
|
||||
|
||||
padding-top: calc(env(safe-area-inset-top, 0px) + var(--silk-topbar-height) + 10px);
|
||||
padding-top: calc(env(safe-area-inset-top, 0px) + var(--silk-topbar-inner-height) + 22px);
|
||||
padding-bottom: 120px;
|
||||
|
||||
#journals {
|
||||
@apply -mt-4 px-1;
|
||||
}
|
||||
}
|
||||
|
||||
.app-silk-topbar {
|
||||
@@ -348,9 +358,10 @@ html[data-silk-native-page-scroll-replaced=false] .app-silk-index-scroll-view {
|
||||
}
|
||||
}
|
||||
|
||||
padding-top: calc(env(safe-area-inset-top, 0px) + 2px);
|
||||
padding-bottom: 8px;
|
||||
height: 32px;
|
||||
padding-top: calc(env(safe-area-inset-top, 0px) + var(--silk-topbar-inner-padding-top, 2px));
|
||||
height: var(--silk-topbar-inner-height, 32px);
|
||||
|
||||
padding-bottom: var(--silk-topbar-inner-padding-bottom, 8px);
|
||||
box-sizing: content-box;
|
||||
|
||||
&.search {
|
||||
|
||||
@@ -30,79 +30,85 @@
|
||||
(set-favorited! (page-handler/favorited? (str (:block/uuid block)))))
|
||||
[block])
|
||||
|
||||
(when open?
|
||||
(state/clear-edit!)
|
||||
(init/keyboard-hide))
|
||||
(hooks/use-effect!
|
||||
(fn []
|
||||
(when open?
|
||||
(state/clear-edit!)
|
||||
(init/keyboard-hide)))
|
||||
[open?])
|
||||
|
||||
(silkhq/bottom-sheet
|
||||
{:presented (boolean open?)
|
||||
:onPresentedChange (fn [v?]
|
||||
(when (false? v?)
|
||||
(mobile-state/set-singleton-modal! nil)
|
||||
(state/clear-edit!)
|
||||
(state/pub-event! [:mobile/keyboard-will-hide])))}
|
||||
(silkhq/bottom-sheet-portal
|
||||
(silkhq/bottom-sheet-view
|
||||
{:class "block-modal-page"
|
||||
:inertOutside false}
|
||||
(silkhq/bottom-sheet-backdrop)
|
||||
(silkhq/bottom-sheet-content
|
||||
{:class "app-silk-sheet-scroll-content"}
|
||||
(silkhq/scroll {:as-child true}
|
||||
(silkhq/scroll-view
|
||||
{:class "app-silk-scroll-view"}
|
||||
(silkhq/scroll-content
|
||||
{:class "app-silk-scroll-content"}
|
||||
[:div.app-silk-scroll-content-inner
|
||||
[:div.flex.justify-between.items-center.block-modal-page-header
|
||||
[:a.opacity-40.active:opacity-60.px-2
|
||||
{:on-pointer-down close!}
|
||||
(shui/tabler-icon "chevron-down" {:size 18 :stroke 3})]
|
||||
(silkhq/depth-sheet
|
||||
{:presented (boolean open?)
|
||||
:onPresentedChange (fn [v?]
|
||||
(when (false? v?)
|
||||
(mobile-state/set-singleton-modal! nil)
|
||||
(state/clear-edit!)
|
||||
(state/pub-event! [:mobile/keyboard-will-hide])))}
|
||||
(silkhq/depth-sheet-portal
|
||||
(silkhq/depth-sheet-view
|
||||
{:class "block-modal-page"
|
||||
:inertOutside false}
|
||||
(silkhq/depth-sheet-backdrop)
|
||||
(silkhq/depth-sheet-content
|
||||
{:class "app-silk-depth-sheet-content"}
|
||||
(silkhq/scroll {:as-child true}
|
||||
(silkhq/scroll-view
|
||||
{:class "app-silk-scroll-view"
|
||||
:scrollGestureTrap {:yEnd true}}
|
||||
(silkhq/scroll-content
|
||||
{:class "app-silk-scroll-content"}
|
||||
|
||||
[:span.flex.items-center.gap-2
|
||||
(when-let [block-id-str (str (:block/uuid block))]
|
||||
[:a.active:opacity-80.pr-1
|
||||
{:class (if favorited? "opacity-80 !text-yellow-800" "opacity-40")
|
||||
:on-click #(-> (if favorited?
|
||||
(page-handler/<unfavorite-page! block-id-str)
|
||||
(page-handler/<favorite-page! block-id-str))
|
||||
(p/then (fn [] (set-favorited! (not favorited?)))))}
|
||||
(shui/tabler-icon (if favorited? "star-filled" "star") {:size 18 :stroke 2})])
|
||||
[:a.opacity-40.active:opacity-60.pr-1
|
||||
{:on-pointer-down (fn []
|
||||
(mobile-ui/open-popup!
|
||||
(fn []
|
||||
[:div.-mx-2
|
||||
(ui/menu-link
|
||||
{:on-click #(mobile-ui/close-popup!)}
|
||||
[:span.text-lg.flex.gap-2.items-center
|
||||
(shui/tabler-icon "copy" {:class "opacity-80" :size 22})
|
||||
"Copy"])
|
||||
[:div.app-silk-scroll-content-inner
|
||||
[:div.flex.justify-between.items-center.block-modal-page-header
|
||||
[:a.opacity-40.active:opacity-60.px-2
|
||||
{:on-pointer-down close!}
|
||||
(shui/tabler-icon "chevron-down" {:size 18 :stroke 3})]
|
||||
|
||||
(ui/menu-link
|
||||
{:on-click #(-> (shui/dialog-confirm!
|
||||
(str "⚠️ Are you sure you want to delete this "
|
||||
(if (entity-util/page? block) "page" "block")
|
||||
"?"))
|
||||
(p/then
|
||||
(fn []
|
||||
(mobile-ui/close-popup!)
|
||||
(some->
|
||||
(:block/uuid block)
|
||||
(page-handler/<delete!
|
||||
(fn [] (close!))
|
||||
{:error-handler
|
||||
(fn [{:keys [msg]}]
|
||||
(notification/show! msg :warning))})))))}
|
||||
[:span.text-lg.flex.gap-2.items-center.text-red-700
|
||||
(shui/tabler-icon "trash" {:class "opacity-80" :size 22})
|
||||
"Delete"])])
|
||||
{:title "Actions"
|
||||
:type :action-sheet}))}
|
||||
(shui/tabler-icon "dots-vertical" {:size 18 :stroke 2})]]]
|
||||
[:span.flex.items-center.gap-2
|
||||
(when-let [block-id-str (str (:block/uuid block))]
|
||||
[:a.active:opacity-80.pr-1
|
||||
{:class (if favorited? "opacity-80 !text-yellow-800" "opacity-40")
|
||||
:on-click #(-> (if favorited?
|
||||
(page-handler/<unfavorite-page! block-id-str)
|
||||
(page-handler/<favorite-page! block-id-str))
|
||||
(p/then (fn [] (set-favorited! (not favorited?)))))}
|
||||
(shui/tabler-icon (if favorited? "star-filled" "star") {:size 18 :stroke 2})])
|
||||
[:a.opacity-40.active:opacity-60.pr-1
|
||||
{:on-pointer-down (fn []
|
||||
(mobile-ui/open-popup!
|
||||
(fn []
|
||||
[:div.-mx-2
|
||||
(ui/menu-link
|
||||
{:on-click #(mobile-ui/close-popup!)}
|
||||
[:span.text-lg.flex.gap-2.items-center
|
||||
(shui/tabler-icon "copy" {:class "opacity-80" :size 22})
|
||||
"Copy"])
|
||||
|
||||
;; block page content
|
||||
[:div.block-modal-page-content
|
||||
(when open?
|
||||
(mobile-ui/classic-app-container-wrap
|
||||
(page/page-cp (db/entity [:block/uuid (:block/uuid block)]))))]])))))))))
|
||||
(ui/menu-link
|
||||
{:on-click #(-> (shui/dialog-confirm!
|
||||
(str "⚠️ Are you sure you want to delete this "
|
||||
(if (entity-util/page? block) "page" "block")
|
||||
"?"))
|
||||
(p/then
|
||||
(fn []
|
||||
(mobile-ui/close-popup!)
|
||||
(some->
|
||||
(:block/uuid block)
|
||||
(page-handler/<delete!
|
||||
(fn [] (close!))
|
||||
{:error-handler
|
||||
(fn [{:keys [msg]}]
|
||||
(notification/show! msg :warning))})))))}
|
||||
[:span.text-lg.flex.gap-2.items-center.text-red-700
|
||||
(shui/tabler-icon "trash" {:class "opacity-80" :size 22})
|
||||
"Delete"])])
|
||||
{:title "Actions"
|
||||
:type :action-sheet}))}
|
||||
(shui/tabler-icon "dots-vertical" {:size 18 :stroke 2})]]]
|
||||
|
||||
;; block page content
|
||||
[:div.block-modal-page-content
|
||||
(when open?
|
||||
(mobile-ui/classic-app-container-wrap
|
||||
(page/page-cp (db/entity [:block/uuid (:block/uuid block)]))))]])))
|
||||
))))))
|
||||
|
||||
Reference in New Issue
Block a user