diff --git a/frontend/app/block/block.less b/frontend/app/block/block.less index b214012f..7151084a 100644 --- a/frontend/app/block/block.less +++ b/frontend/app/block/block.less @@ -133,21 +133,6 @@ } } - .iconbutton { - cursor: pointer; - opacity: 0.7; - align-items: center; - - &:hover { - opacity: 1; - } - - &.disabled { - cursor: default; - opacity: 0.45 !important; - } - } - .connection-button { display: flex; align-items: center; diff --git a/frontend/app/block/blockframe.tsx b/frontend/app/block/blockframe.tsx index f5f0bcc8..40ba0c94 100644 --- a/frontend/app/block/blockframe.tsx +++ b/frontend/app/block/blockframe.tsx @@ -8,7 +8,6 @@ import { ConnectionButton, ControllerStatusIcon, getBlockHeaderIcon, - IconButton, Input, } from "@/app/block/blockutil"; import { Button } from "@/app/element/button"; @@ -29,6 +28,7 @@ import { } from "@/app/store/global"; import * as services from "@/app/store/services"; import { WshServer } from "@/app/store/wshserver"; +import { IconButton } from "@/element/iconbutton"; import { MagnifyIcon } from "@/element/magnify"; import { NodeModel } from "@/layout/index"; import * as keyutil from "@/util/keyutil"; @@ -88,7 +88,7 @@ function handleHeaderContextMenu( ContextMenuModel.showContextMenu(menu, e); } -function getViewIconElem(viewIconUnion: string | HeaderIconButton, blockData: Block): JSX.Element { +function getViewIconElem(viewIconUnion: string | IconButtonDecl, blockData: Block): JSX.Element { if (viewIconUnion == null || typeof viewIconUnion === "string") { const viewIcon = viewIconUnion as string; return
{getBlockHeaderIcon(viewIcon, blockData)}
; @@ -99,7 +99,7 @@ function getViewIconElem(viewIconUnion: string | HeaderIconButton, blockData: Bl const OptMagnifyButton = React.memo( ({ magnified, toggleMagnify, disabled }: { magnified: boolean; toggleMagnify: () => void; disabled: boolean }) => { - const magnifyDecl: HeaderIconButton = { + const magnifyDecl: IconButtonDecl = { elemtype: "iconbutton", icon: , title: magnified ? "Minimize" : "Magnify", @@ -124,7 +124,7 @@ function computeEndIcons( if (endIconButtons && endIconButtons.length > 0) { endIconsElem.push(...endIconButtons.map((button, idx) => )); } - const settingsDecl: HeaderIconButton = { + const settingsDecl: IconButtonDecl = { elemtype: "iconbutton", icon: "cog", title: "Settings", @@ -139,7 +139,7 @@ function computeEndIcons( disabled={magnifyDisabled} /> ); - const closeDecl: HeaderIconButton = { + const closeDecl: IconButtonDecl = { elemtype: "iconbutton", icon: "xmark-large", title: "Close", diff --git a/frontend/app/block/blockutil.tsx b/frontend/app/block/blockutil.tsx index 17ae041d..06ce5664 100644 --- a/frontend/app/block/blockutil.tsx +++ b/frontend/app/block/blockutil.tsx @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 import { NumActiveConnColors } from "@/app/block/blockframe"; -import { useLongClick } from "@/app/hook/useLongClick"; import { getConnStatusAtom, waveEventSubscribe, WOS } from "@/app/store/global"; import * as services from "@/app/store/services"; import { makeORef } from "@/app/store/wos"; @@ -139,20 +138,6 @@ export function getBlockHeaderIcon(blockIcon: string, blockData: Block): React.R return blockIconElem; } -export const IconButton = React.memo(({ decl, className }: { decl: HeaderIconButton; className?: string }) => { - const buttonRef = React.useRef(null); - useLongClick(buttonRef, decl.click, decl.longClick, decl.disabled); - return ( -
- {typeof decl.icon === "string" ? : decl.icon} -
- ); -}); - interface ConnectionButtonProps { connection: string; changeConnModalAtom: jotai.PrimitiveAtom; diff --git a/frontend/app/element/copybutton.less b/frontend/app/element/copybutton.less index db485579..1689a0f9 100644 --- a/frontend/app/element/copybutton.less +++ b/frontend/app/element/copybutton.less @@ -2,15 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 .copy-button { - padding: 5px 5px !important; - opacity: 0.5; - - &:hover { - opacity: 1; - } - &.copied { opacity: 1; - color: var(--success-color); + i { + color: var(--success-color); + } } } diff --git a/frontend/app/element/copybutton.tsx b/frontend/app/element/copybutton.tsx index 0fbe3090..a5e26bc5 100644 --- a/frontend/app/element/copybutton.tsx +++ b/frontend/app/element/copybutton.tsx @@ -3,8 +3,8 @@ import { clsx } from "clsx"; import { useEffect, useRef, useState } from "react"; -import { Button } from "./button"; import "./copybutton.less"; +import { IconButton } from "./iconbutton"; type CopyButtonProps = { title: string; @@ -43,13 +43,16 @@ const CopyButton = ({ title, className, onClick }: CopyButtonProps) => { }, []); return ( - + ); }; diff --git a/frontend/app/element/iconbutton.less b/frontend/app/element/iconbutton.less new file mode 100644 index 00000000..bf1a3f6a --- /dev/null +++ b/frontend/app/element/iconbutton.less @@ -0,0 +1,14 @@ +.iconbutton { + cursor: pointer; + opacity: 0.7; + align-items: center; + + &:hover { + opacity: 1; + } + + &.disabled { + cursor: default; + opacity: 0.45 !important; + } +} diff --git a/frontend/app/element/iconbutton.tsx b/frontend/app/element/iconbutton.tsx new file mode 100644 index 00000000..88a13013 --- /dev/null +++ b/frontend/app/element/iconbutton.tsx @@ -0,0 +1,19 @@ +import { useLongClick } from "@/app/hook/useLongClick"; +import { makeIconClass } from "@/util/util"; +import clsx from "clsx"; +import { memo, useRef } from "react"; +import "./iconbutton.less"; + +export const IconButton = memo(({ decl, className }: { decl: IconButtonDecl; className?: string }) => { + const buttonRef = useRef(null); + useLongClick(buttonRef, decl.click, decl.longClick, decl.disabled); + return ( +
+ {typeof decl.icon === "string" ? : decl.icon} +
+ ); +}); diff --git a/frontend/app/element/markdown.less b/frontend/app/element/markdown.less index 0b448bc7..5d2e55c0 100644 --- a/frontend/app/element/markdown.less +++ b/frontend/app/element/markdown.less @@ -85,29 +85,12 @@ top: 0; right: 0; border-radius: 4px; + backdrop-filter: blur(8px); + margin: 2px 2px; + padding: 4px 4px; align-items: center; justify-content: flex-end; - - i { - color: var(--line-actions-inactive-color); - margin-left: 4px; - - &:first-child { - margin-left: 0px; - } - - &:hover { - color: var(--line-actions-active-color); - } - - &.fa-check { - color: var(--success-color); - } - - &.fa-square-terminal { - cursor: pointer; - } - } + gap: 4px; } &:hover .codeblock-actions { diff --git a/frontend/app/element/markdown.tsx b/frontend/app/element/markdown.tsx index 288ffb9c..86f2f836 100644 --- a/frontend/app/element/markdown.tsx +++ b/frontend/app/element/markdown.tsx @@ -17,6 +17,7 @@ import rehypeSlug from "rehype-slug"; import RemarkFlexibleToc, { TocItem } from "remark-flexible-toc"; import remarkGfm from "remark-gfm"; import { openLink } from "../store/global"; +import { IconButton } from "./iconbutton"; import "./markdown.less"; const Link = ({ @@ -90,7 +91,16 @@ const CodeBlock = ({ children, onClickExecute }: CodeBlockProps) => { {children}
- {onClickExecute && } + {onClickExecute && ( + + )}
); diff --git a/frontend/app/view/helpview/helpview.tsx b/frontend/app/view/helpview/helpview.tsx index 42859c5c..3f72ff85 100644 --- a/frontend/app/view/helpview/helpview.tsx +++ b/frontend/app/view/helpview/helpview.tsx @@ -183,7 +183,7 @@ Other useful metadata values to override block titles, icons, colors, themes, et class HelpViewModel implements ViewModel { viewType: string; showTocAtom: PrimitiveAtom; - endIconButtons: Atom; + endIconButtons: Atom; constructor() { this.viewType = "help"; @@ -195,7 +195,7 @@ class HelpViewModel implements ViewModel { title: "Table of Contents", click: () => this.showTocToggle(), }, - ] as HeaderIconButton[]); + ] as IconButtonDecl[]); } showTocToggle() { diff --git a/frontend/app/view/preview/preview.tsx b/frontend/app/view/preview/preview.tsx index 149288de..a106f0c1 100644 --- a/frontend/app/view/preview/preview.tsx +++ b/frontend/app/view/preview/preview.tsx @@ -80,11 +80,11 @@ export class PreviewModel implements ViewModel { blockId: string; nodeModel: NodeModel; blockAtom: jotai.Atom; - viewIcon: jotai.Atom; + viewIcon: jotai.Atom; viewName: jotai.Atom; viewText: jotai.Atom; - preIconButton: jotai.Atom; - endIconButtons: jotai.Atom; + preIconButton: jotai.Atom; + endIconButtons: jotai.Atom; previewTextRef: React.RefObject; editMode: jotai.Atom; canPreview: jotai.PrimitiveAtom; @@ -294,7 +294,7 @@ export class PreviewModel implements ViewModel { icon: "arrows-rotate", click: () => this.refreshCallback?.(), }, - ] as HeaderIconButton[]; + ] as IconButtonDecl[]; } else if (!isCeView && mimeType.startsWith("text/markdown")) { return [ { @@ -303,7 +303,7 @@ export class PreviewModel implements ViewModel { title: "Table of Contents", click: () => this.markdownShowTocToggle(), }, - ] as HeaderIconButton[]; + ] as IconButtonDecl[]; } return null; }); diff --git a/frontend/app/view/waveai/waveai.tsx b/frontend/app/view/waveai/waveai.tsx index caad06a5..348f540b 100644 --- a/frontend/app/view/waveai/waveai.tsx +++ b/frontend/app/view/waveai/waveai.tsx @@ -44,11 +44,11 @@ export class WaveAiModel implements ViewModel { viewType: string; blockId: string; blockAtom: Atom; - viewIcon?: Atom; + viewIcon?: Atom; viewName?: Atom; viewText?: Atom; - preIconButton?: Atom; - endIconButtons?: Atom; + preIconButton?: Atom; + endIconButtons?: Atom; messagesAtom: PrimitiveAtom>; addMessageAtom: WritableAtom; updateLastMessageAtom: WritableAtom; diff --git a/frontend/app/view/webview/webview.tsx b/frontend/app/view/webview/webview.tsx index ff61dda5..4a7a85b3 100644 --- a/frontend/app/view/webview/webview.tsx +++ b/frontend/app/view/webview/webview.tsx @@ -18,7 +18,7 @@ export class WebViewModel implements ViewModel { viewType: string; blockId: string; blockAtom: jotai.Atom; - viewIcon: jotai.Atom; + viewIcon: jotai.Atom; viewName: jotai.Atom; viewText: jotai.Atom; url: jotai.PrimitiveAtom; diff --git a/frontend/types/custom.d.ts b/frontend/types/custom.d.ts index 5281d3b8..9f7916d7 100644 --- a/frontend/types/custom.d.ts +++ b/frontend/types/custom.d.ts @@ -148,9 +148,9 @@ declare global { type SubjectWithRef = rxjs.Subject & { refCount: number; release: () => void }; - type HeaderElem = HeaderIconButton | HeaderText | HeaderInput | HeaderDiv | HeaderTextButton | ConnectionButton; + type HeaderElem = IconButtonDecl | HeaderText | HeaderInput | HeaderDiv | HeaderTextButton | ConnectionButton; - type HeaderIconButton = { + type IconButtonDecl = { elemtype: "iconbutton"; icon: string | React.ReactNode; className?: string; @@ -207,11 +207,11 @@ declare global { interface ViewModel { viewType: string; - viewIcon?: jotai.Atom; + viewIcon?: jotai.Atom; viewName?: jotai.Atom; viewText?: jotai.Atom; - preIconButton?: jotai.Atom; - endIconButtons?: jotai.Atom; + preIconButton?: jotai.Atom; + endIconButtons?: jotai.Atom; blockBg?: jotai.Atom; manageConnection?: jotai.Atom;