feat: add support for pointer cursor (#517)
* feat: add support for pointer cursor (cherry picked from commit dcabf91d843f2487ad32ceacfdd2d1b9d7c2a5bf) * fix: correct useEffect update (cherry picked from commit cbf0a821cd5a9b72b14b63c317d88e68fbd6783d) * feat: remove default values * feat: pointer cursor Signed-off-by: Innei <i@innei.in> * fix: remove select content animation when position is `item-aligned` Signed-off-by: Innei <i@innei.in> * update hover Signed-off-by: Innei <i@innei.in> --------- Signed-off-by: Innei <i@innei.in> Co-authored-by: Innei <i@innei.in>
This commit is contained in:
parent
4dadd3119a
commit
b6ff6fb48f
|
|
@ -19,6 +19,7 @@ export const createDefaultSettings = (): UISettings => ({
|
|||
modalDraggable: true,
|
||||
modalOpaque: true,
|
||||
reduceMotion: false,
|
||||
usePointerCursor: false,
|
||||
|
||||
// Font
|
||||
uiFontFamily: "SN Pro",
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ export const ShadowDOM: FC<PropsWithChildren<React.HTMLProps<HTMLElement>>> & {
|
|||
|
||||
const uiFont = useUISettingKey("uiFontFamily")
|
||||
const reduceMotion = useReduceMotion()
|
||||
const usePointerCursor = useUISettingKey("usePointerCursor")
|
||||
|
||||
return (
|
||||
<root.div {...rest}>
|
||||
|
|
@ -111,8 +112,9 @@ export const ShadowDOM: FC<PropsWithChildren<React.HTMLProps<HTMLElement>>> & {
|
|||
style={useMemo(
|
||||
() => ({
|
||||
fontFamily: `${uiFont},"SN Pro", system-ui, sans-serif`,
|
||||
"--pointer": usePointerCursor ? "pointer" : "default",
|
||||
}),
|
||||
[uiFont],
|
||||
[uiFont, usePointerCursor],
|
||||
)}
|
||||
id="shadow-html"
|
||||
data-motion-reduce={reduceMotion}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import { cn } from "~/lib/utils"
|
|||
|
||||
export const styledButtonVariant = cva(
|
||||
[
|
||||
"inline-flex cursor-default select-none items-center justify-center gap-2 outline-offset-2 transition active:transition-none disabled:cursor-not-allowed",
|
||||
"inline-flex cursor-button select-none items-center justify-center gap-2 outline-offset-2 transition active:transition-none disabled:cursor-not-allowed",
|
||||
"ring-accent/20 duration-200 disabled:ring-0",
|
||||
"align-middle",
|
||||
],
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ const ContextMenuSubTrigger = React.forwardRef<
|
|||
<ContextMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-theme-item-hover focus:text-theme-foreground data-[state=open]:bg-theme-item-hover data-[state=open]:text-theme-foreground",
|
||||
"flex cursor-menu select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-theme-item-hover focus:text-theme-foreground data-[state=open]:bg-theme-item-hover data-[state=open]:text-theme-foreground",
|
||||
inset && "pl-8",
|
||||
"center gap-2",
|
||||
className,
|
||||
|
|
@ -81,7 +81,7 @@ const ContextMenuItem = React.forwardRef<
|
|||
<ContextMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-theme-item-hover focus:text-theme-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex cursor-menu select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-theme-item-hover focus:text-theme-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"focus-within:outline-transparent data-[highlighted]:bg-theme-item-hover dark:data-[highlighted]:bg-neutral-800",
|
||||
inset && "pl-8",
|
||||
className,
|
||||
|
|
@ -98,7 +98,7 @@ const ContextMenuCheckboxItem = React.forwardRef<
|
|||
<ContextMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-theme-item-hover focus:text-theme-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex cursor-checkbox select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-theme-item-hover focus:text-theme-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"focus-within:outline-transparent",
|
||||
className,
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
|
|||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-theme-item-hover data-[state=open]:bg-theme-item-active",
|
||||
"flex cursor-menu select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-theme-item-hover data-[state=open]:bg-theme-item-active",
|
||||
inset && "pl-8",
|
||||
className,
|
||||
)}
|
||||
|
|
@ -80,7 +80,7 @@ const DropdownMenuItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-theme-item-hover data-[disabled]:pointer-events-none data-[state=open]:bg-theme-item-active data-[disabled]:opacity-50",
|
||||
"relative flex cursor-menu select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-theme-item-hover data-[disabled]:pointer-events-none data-[state=open]:bg-theme-item-active data-[disabled]:opacity-50",
|
||||
inset && "pl-8",
|
||||
"focus-within:!outline-transparent",
|
||||
className,
|
||||
|
|
@ -104,7 +104,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
|
|||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-theme-item-hover data-[disabled]:pointer-events-none data-[state=open]:bg-theme-item-active data-[disabled]:opacity-50",
|
||||
"relative flex cursor-menu select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-theme-item-hover data-[disabled]:pointer-events-none data-[state=open]:bg-theme-item-active data-[disabled]:opacity-50",
|
||||
className,
|
||||
)}
|
||||
checked={checked}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ const MediaImpl: FC<MediaProps> = ({
|
|||
onError={errorHandle}
|
||||
className={cn(
|
||||
!(props.width || props.height) && "size-full",
|
||||
"bg-gray-200 object-cover duration-200 dark:bg-neutral-800",
|
||||
"cursor-card bg-gray-200 object-cover duration-200 dark:bg-neutral-800",
|
||||
popper && "cursor-zoom-in",
|
||||
mediaLoadState === "loaded" ? "opacity-100" : "opacity-0",
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ const MediaImpl: FC<MediaProps> = ({
|
|||
className={cn(
|
||||
"center",
|
||||
!(props.width || props.height) && "size-full",
|
||||
"relative bg-stone-100 object-cover",
|
||||
"relative cursor-card bg-stone-100 object-cover",
|
||||
mediaContainerClassName,
|
||||
)}
|
||||
onClick={handleClick}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export function SwipeMedia({
|
|||
<div
|
||||
ref={hoverRef}
|
||||
className={cn(
|
||||
"relative flex w-full items-center overflow-hidden",
|
||||
"relative flex w-full items-center overflow-hidden ",
|
||||
styles["swipe-wrapper"],
|
||||
className,
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ const SelectTrigger = React.forwardRef<
|
|||
"ring-accent/20 duration-200 focus:border-accent/80 focus:outline-none focus:ring-2",
|
||||
"border border-border",
|
||||
size === "sm" ? "h-7 p-2 text-sm" : "h-9 px-3 py-2 text-sm",
|
||||
"hover:border-accent/80",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
@ -40,7 +41,7 @@ const SelectScrollUpButton = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
ref={ref}
|
||||
className={cn("flex cursor-default items-center justify-center py-1", className)}
|
||||
className={cn("flex cursor-select items-center justify-center py-1", className)}
|
||||
{...props}
|
||||
>
|
||||
<i className="i-mingcute-up-line" />
|
||||
|
|
@ -54,7 +55,7 @@ const SelectScrollDownButton = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
ref={ref}
|
||||
className={cn("flex cursor-default items-center justify-center py-1", className)}
|
||||
className={cn("flex cursor-select items-center justify-center py-1", className)}
|
||||
{...props}
|
||||
>
|
||||
<i className="i-mingcute-down-line" />
|
||||
|
|
@ -70,9 +71,11 @@ const SelectContent = React.forwardRef<
|
|||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"shadow-perfect relative z-[1000] max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
position === "popper" &&
|
||||
"shadow-perfect relative z-[1000] max-h-96 min-w-32 overflow-hidden rounded-md border bg-popover text-popover-foreground",
|
||||
position === "popper" && [
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
],
|
||||
className,
|
||||
)}
|
||||
position={position}
|
||||
|
|
@ -113,7 +116,7 @@ const SelectItem = React.forwardRef<
|
|||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"pointer-events-auto relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-theme-item-active focus:text-theme-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"pointer-events-auto relative flex w-full cursor-select items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-theme-item-active focus:text-theme-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -9,14 +9,17 @@ const Switch = React.forwardRef<
|
|||
>(({ className, ...props }, ref) => (
|
||||
<SwitchPrimitives.Root
|
||||
className={cn(
|
||||
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"peer inline-flex h-5 w-9 shrink-0 cursor-switch items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"duration-200 data-[state=checked]:bg-accent data-[state=unchecked]:bg-theme-inactive dark:data-[state=unchecked]:bg-theme-accent-100/10",
|
||||
"hover:data-[state=unchecked]:bg-theme-inactive/80 dark:hover:data-[state=unchecked]:bg-theme-accent-100/15",
|
||||
"hover:data-[state=checked]:bg-accent/80 dark:hover:data-[state=checked]:bg-accent",
|
||||
"group",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
>
|
||||
<SwitchPrimitives.Thumb className="pointer-events-none block size-4 rounded-full bg-background ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0" />
|
||||
<SwitchPrimitives.Thumb className="pointer-events-none block size-4 rounded-full bg-background ring-0 transition-transform duration-200 data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0 group-hover:dark:data-[state=checked]:!bg-black/80" />
|
||||
</SwitchPrimitives.Root>
|
||||
))
|
||||
Switch.displayName = SwitchPrimitives.Root.displayName
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import duration from "dayjs/plugin/duration"
|
|||
import localizedFormat from "dayjs/plugin/localizedFormat"
|
||||
import relativeTime from "dayjs/plugin/relativeTime"
|
||||
import { enableMapSet } from "immer"
|
||||
import React from "react"
|
||||
import ReactDOM from "react-dom"
|
||||
import { toast } from "sonner"
|
||||
|
||||
import { getUISettings } from "~/atoms/settings/ui"
|
||||
|
|
@ -119,6 +121,10 @@ export const initializeApp = async () => {
|
|||
data_hydrated_time: dataHydratedTime,
|
||||
version: APP_VERSION,
|
||||
})
|
||||
|
||||
// expose `React` `ReactDOM` to global, it's easier for developers to make plugins
|
||||
window.React = React
|
||||
window.ReactDOM = ReactDOM
|
||||
}
|
||||
|
||||
import.meta.hot?.dispose(cleanup)
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export const DailyReportTitle = ({
|
|||
<div className="font-medium">{t("ai_daily.title", { title })}</div>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<i className="i-mgc-question-cute-re translate-y-px text-sm" />
|
||||
<i className="i-mgc-question-cute-re text-sm" />
|
||||
</TooltipTrigger>
|
||||
<TooltipPortal>
|
||||
<TooltipContent>
|
||||
|
|
|
|||
|
|
@ -25,20 +25,21 @@ export const RecommendationCard: FC<RecommendationCardProps> = memo(({ data, rou
|
|||
<CardContent className="p-5 pt-0">
|
||||
<ul className="space-y-1 text-sm text-muted-foreground">
|
||||
{Object.keys(data.routes).map((route) => (
|
||||
<li
|
||||
key={route}
|
||||
className="duration-200 hover:text-theme-foreground-hover"
|
||||
onClick={() => {
|
||||
present({
|
||||
content: () => (
|
||||
<RecommendationContent routePrefix={routePrefix} route={data.routes[route]} />
|
||||
),
|
||||
icon: <FeedIcon className="size-4" size={16} siteUrl={`https://${data.url}`} />,
|
||||
title: `${data.name} - ${data.routes[route].name}`,
|
||||
})
|
||||
}}
|
||||
>
|
||||
{data.routes[route].name}
|
||||
<li key={route} className="duration-200 hover:text-theme-foreground-hover">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
present({
|
||||
content: () => (
|
||||
<RecommendationContent routePrefix={routePrefix} route={data.routes[route]} />
|
||||
),
|
||||
icon: <FeedIcon className="size-4" size={16} siteUrl={`https://${data.url}`} />,
|
||||
title: `${data.name} - ${data.routes[route].name}`,
|
||||
})
|
||||
}}
|
||||
>
|
||||
{data.routes[route].name}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ export function VideoItem({ entryId, entryPreview, translation }: UniversalItemP
|
|||
return (
|
||||
<GridItem entryId={entryId} entryPreview={entryPreview} translation={translation}>
|
||||
<div
|
||||
className="w-full"
|
||||
className="w-full cursor-card"
|
||||
onClick={() => {
|
||||
if (iframeSrc) {
|
||||
modalStack.present({
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export function ListItem({
|
|||
onMouseEnter={handlePrefetchEntry}
|
||||
onMouseLeave={handlePrefetchEntry.cancel}
|
||||
className={cn(
|
||||
"group relative flex py-4 pl-3 pr-2",
|
||||
"group relative flex cursor-menu py-4 pl-3 pr-2",
|
||||
!asRead &&
|
||||
"before:absolute before:-left-0.5 before:top-[1.4375rem] before:block before:size-2 before:rounded-full before:bg-accent",
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ export const EntryContentRender: Component<{ entryId: string }> = ({ entryId, cl
|
|||
<a
|
||||
href={populatedFullHref || void 0}
|
||||
target="_blank"
|
||||
className="-mx-6 block cursor-default rounded-lg p-6 transition-colors hover:bg-theme-item-hover focus-visible:bg-theme-item-hover focus-visible:!outline-none @sm:-mx-3 @sm:p-3"
|
||||
className="-mx-6 block cursor-button rounded-lg p-6 transition-colors hover:bg-theme-item-hover focus-visible:bg-theme-item-hover focus-visible:!outline-none @sm:-mx-3 @sm:p-3"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<div className="select-text break-words text-3xl font-bold">
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ function FeedCategoryImpl({
|
|||
{!!showCollapse && (
|
||||
<div
|
||||
className={cn(
|
||||
"flex w-full items-center justify-between rounded-md px-2.5 transition-colors",
|
||||
"flex w-full cursor-menu items-center justify-between rounded-md px-2.5 transition-colors",
|
||||
(isActive || isContextMenuOpen) && "bg-native-active",
|
||||
)}
|
||||
onClick={(e) => {
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ const LogoContextMenu: FC<PropsWithChildren> = ({ children }) => {
|
|||
toast.success(t.common("app.copied_to_clipboard"))
|
||||
}}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-1 py-0.5 text-sm outline-none",
|
||||
"relative flex cursor-menu select-none items-center rounded-sm px-1 py-0.5 text-sm outline-none",
|
||||
"focus-within:outline-transparent hover:bg-theme-item-hover dark:hover:bg-neutral-800",
|
||||
"gap-2 text-foreground/80 [&_svg]:size-3",
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ const FeedItemImpl = ({ view, feedId, className, showUnreadCount = true }: FeedI
|
|||
<div
|
||||
data-feed-id={feedId}
|
||||
className={cn(
|
||||
"flex w-full items-center justify-between rounded-md py-[2px] pr-2.5 text-sm font-medium leading-loose",
|
||||
"flex w-full cursor-menu items-center justify-between rounded-md py-[2px] pr-2.5 text-sm font-medium leading-loose",
|
||||
(isActive || isContextMenuOpen) && "bg-native-active",
|
||||
|
||||
className,
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ function FeedListImpl({ className, view }: { className?: string; view: number })
|
|||
<ScrollArea.ScrollArea mask={false} flex viewportClassName="!px-3" rootClassName="h-full">
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-8 w-full shrink-0 items-center rounded-md px-2.5 transition-colors",
|
||||
"flex h-8 w-full shrink-0 cursor-menu items-center rounded-md px-2.5 transition-colors",
|
||||
feedId === FEED_COLLECTION_LIST && "bg-native-active",
|
||||
)}
|
||||
onClick={(e) => {
|
||||
|
|
@ -140,7 +140,7 @@ function FeedListImpl({ className, view }: { className?: string; view: number })
|
|||
<div className="flex h-full flex-1 items-center font-normal text-zinc-500">
|
||||
<Link
|
||||
to="/discover"
|
||||
className="absolute inset-0 mt-[-3.75rem] flex h-full flex-1 cursor-default flex-col items-center justify-center gap-2"
|
||||
className="absolute inset-0 mt-[-3.75rem] flex h-full flex-1 cursor-menu flex-col items-center justify-center gap-2"
|
||||
onClick={stopPropagation}
|
||||
>
|
||||
<i className="i-mgc-add-cute-re text-3xl" />
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ const SubscriptionItem: FC<{
|
|||
data-feed-id={subscription.feedId}
|
||||
>
|
||||
<a
|
||||
className="flex flex-1 cursor-default items-center"
|
||||
className="flex flex-1 cursor-menu items-center"
|
||||
href={subscription.feeds.siteUrl!}
|
||||
target="_blank"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export const SettingSwitch: Component<{
|
|||
return (
|
||||
<div className={cn("mb-3 flex items-center justify-between gap-4", className)}>
|
||||
<Label htmlFor={id}>{label}</Label>
|
||||
<Switch id={id} checked={checked} onCheckedChange={onCheckedChange} className="cursor-auto" />
|
||||
<Switch id={id} checked={checked} onCheckedChange={onCheckedChange} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,6 +93,10 @@ export const SettingAppearance = () => {
|
|||
label: t("appearance.reduce_motion.label"),
|
||||
description: t("appearance.reduce_motion.description"),
|
||||
}),
|
||||
defineItem("usePointerCursor", {
|
||||
label: t("appearance.use_pointer_cursor.label"),
|
||||
description: t("appearance.use_pointer_cursor.description"),
|
||||
}),
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ const UserRenderer = ({
|
|||
onClick={() => {
|
||||
if (user?.id) presentUserModal(user.id)
|
||||
}}
|
||||
className={cn("flex items-center", user?.id ? "cursor-pointer" : "cursor-default")}
|
||||
className="flex cursor-button items-center"
|
||||
>
|
||||
{name === APP_NAME ? (
|
||||
<Logo className="aspect-square size-4" />
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ export function Component() {
|
|||
{subscriptions.data?.[category].map((subscription) => (
|
||||
<div key={subscription.feedId} className="group relative border-b py-5">
|
||||
<a
|
||||
className="flex flex-1 cursor-default"
|
||||
className="flex flex-1 cursor-button"
|
||||
href={`/feed/${subscription.feedId}`}
|
||||
target="_blank"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ const FooterInfo = () => {
|
|||
onClick={() => {
|
||||
window.open(`${repository.url}/releases`)
|
||||
}}
|
||||
className="center cursor-pointer rounded-full border bg-background p-1.5 shadow-sm"
|
||||
className="center rounded-full border bg-background p-1.5 shadow-sm"
|
||||
>
|
||||
<i className="i-mgc-download-2-cute-re size-3.5 opacity-80" />
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ function Layout() {
|
|||
{settings.map((t) => (
|
||||
<Link
|
||||
key={t.path}
|
||||
className={`my-1 flex cursor-default items-center rounded-md px-2.5 py-0.5 leading-loose text-theme-foreground/70 transition-colors dark:text-theme-foreground/90 ${
|
||||
className={`my-1 flex cursor-menu items-center rounded-md px-2.5 py-0.5 leading-loose text-theme-foreground/70 transition-colors dark:text-theme-foreground/90 ${
|
||||
tab === t.path ? "bg-native-active text-theme-foreground/90" : ""
|
||||
}`}
|
||||
to={`/settings/${t.path}`}
|
||||
|
|
|
|||
|
|
@ -27,10 +27,11 @@ const useUISettingSync = () => {
|
|||
fontFamily: fontCss,
|
||||
})
|
||||
root.style.cssText += `\n--fo-font-family: ${fontCss}`
|
||||
root.style.cssText += `\n--pointer: ${setting.usePointerCursor ? "pointer" : "default"}`
|
||||
Object.assign(document.body.style, {
|
||||
fontFamily: fontCss,
|
||||
})
|
||||
}, [setting.uiFontFamily])
|
||||
}, [setting.uiFontFamily, setting.usePointerCursor])
|
||||
|
||||
useEffect(() => {
|
||||
if (setting.showDockBadge) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ body,
|
|||
}
|
||||
|
||||
button {
|
||||
@apply cursor-default;
|
||||
cursor: var(--pointer);
|
||||
}
|
||||
|
||||
.prose a {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
html,
|
||||
#shadow-html {
|
||||
--cursor-button: var(--pointer);
|
||||
--cursor-select: var(--pointer);
|
||||
--cursor-checkbox: var(--pointer);
|
||||
--cursor-link: var(--pointer);
|
||||
--cursor-menu: default;
|
||||
--cursor-radio: var(--pointer);
|
||||
--cursor-switch: var(--pointer);
|
||||
--cursor-card: var(--pointer);
|
||||
}
|
||||
|
|
@ -4,3 +4,4 @@
|
|||
@import "./colors.css";
|
||||
@import "./additional.css";
|
||||
@import "./scrollbar.css";
|
||||
@import "./cursor.css";
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@
|
|||
"appearance.title": "Appearance",
|
||||
"appearance.ui_font": "UI Font",
|
||||
"appearance.unread_count": "Unread count",
|
||||
"appearance.use_pointer_cursor.description": "Change the cursor to a pointer when hovering over any interactive element.",
|
||||
"appearance.use_pointer_cursor.label": "Use pointer cursors",
|
||||
"common.give_star": "<HeartIcon />Love our product? <Link>Give us a star on GitHub!</Link>",
|
||||
"feeds.claimTips": "To claim your feeds and receive tips, right-click on the feed in your subscription list and select Claim.",
|
||||
"feeds.noFeeds": "No claimed feeds",
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@
|
|||
"appearance.title": "外观",
|
||||
"appearance.ui_font": "界面字体",
|
||||
"appearance.unread_count": "未读数",
|
||||
"appearance.use_pointer_cursor.description": "悬停在任何可交互元素上时将光标更改为指针。",
|
||||
"appearance.use_pointer_cursor.label": "使用指针光标",
|
||||
"common.give_star": "<HeartIcon />喜欢我们的产品吗? <Link>在 GitHub 上给我们 star 吧!</Link>",
|
||||
"feeds.claimTips": "要认证你的订阅源并接收打赏,请在订阅列表中右键点击订阅源并选择“认证”。",
|
||||
"feeds.noFeeds": "没有已认证的订阅源",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export interface UISettings {
|
|||
modalDraggable: boolean
|
||||
modalOpaque: boolean
|
||||
reduceMotion: boolean
|
||||
usePointerCursor: boolean | null
|
||||
uiFontFamily: string
|
||||
readerFontFamily: string
|
||||
readerRenderInlineStyle: boolean
|
||||
|
|
|
|||
|
|
@ -27,6 +27,16 @@ export default resolveConfig({
|
|||
theme: "var(--fo-font-family)",
|
||||
default: "SN pro, sans-serif, system-ui",
|
||||
},
|
||||
cursor: {
|
||||
button: "var(--cursor-button)",
|
||||
select: "var(--cursor-select)",
|
||||
checkbox: "var(--cursor-checkbox)",
|
||||
link: "var(--cursor-link)",
|
||||
menu: "var(--cursor-menu)",
|
||||
radio: "var(--cursor-radio)",
|
||||
switch: "var(--cursor-switch)",
|
||||
card: "var(--cursor-card)",
|
||||
},
|
||||
colors: {
|
||||
border: "hsl(var(--border) / <alpha-value>)",
|
||||
background: "hsl(var(--background) / <alpha-value>)",
|
||||
|
|
|
|||
Loading…
Reference in New Issue