mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-04 18:59:08 +01:00
testing new default header
This commit is contained in:
parent
a382d5d41e
commit
15cc681b4b
@ -11,6 +11,8 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
|
|
||||||
.block-frame-icon {
|
.block-frame-icon {
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
@ -53,6 +55,88 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.block-frame-default {
|
||||||
|
border: 2px solid transparent;
|
||||||
|
|
||||||
|
&.block-focused {
|
||||||
|
border: 2px solid var(--accent-color);
|
||||||
|
|
||||||
|
&.block-no-highlight,
|
||||||
|
&.block-preview {
|
||||||
|
border: 2px solid transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-frame-default-header {
|
||||||
|
display: flex;
|
||||||
|
height: 26px;
|
||||||
|
padding-left: 6px;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
align-self: stretch;
|
||||||
|
font: var(--header-font);
|
||||||
|
background-color: #262626;
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
|
||||||
|
.block-frame-default-header-iconview {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
color: var(--main-text-color);
|
||||||
|
|
||||||
|
.block-frame-view-icon {
|
||||||
|
font-size: var(--header-icon-size);
|
||||||
|
opacity: 0.5;
|
||||||
|
width: var(--header-icon-width);
|
||||||
|
i {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-frame-view-type {
|
||||||
|
line-height: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-frame-blockid {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-frame-end-icons {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.block-frame-settings {
|
||||||
|
display: flex;
|
||||||
|
width: 24px;
|
||||||
|
padding: 6px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
opacity: 0.5;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.block-frame-default-close {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
opacity: 0.5;
|
||||||
|
font-size: 11px;
|
||||||
|
width: 24px;
|
||||||
|
padding: 4px 6px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.block-frame-tech {
|
&.block-frame-tech {
|
||||||
border: 2px solid var(--border-color);
|
border: 2px solid var(--border-color);
|
||||||
border-radius: 7px;
|
border-radius: 7px;
|
||||||
@ -62,6 +146,11 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
|
|
||||||
|
.block-header-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
&.block-preview {
|
&.block-preview {
|
||||||
background-color: var(--main-bg-color);
|
background-color: var(--main-bg-color);
|
||||||
|
|
||||||
|
@ -95,6 +95,26 @@ function processTitleString(titleString: string): React.ReactNode[] {
|
|||||||
return partsStack[0];
|
return partsStack[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getBlockHeaderIcon(blockIcon: string, blockData: Block): React.ReactNode {
|
||||||
|
let blockIconElem: React.ReactNode = null;
|
||||||
|
if (util.isBlank(blockIcon)) {
|
||||||
|
blockIcon = "square";
|
||||||
|
}
|
||||||
|
let iconColor = blockData?.meta?.["icon:color"];
|
||||||
|
if (iconColor && !iconColor.match(colorRegex)) {
|
||||||
|
iconColor = null;
|
||||||
|
}
|
||||||
|
let iconStyle = null;
|
||||||
|
if (!util.isBlank(iconColor)) {
|
||||||
|
iconStyle = { color: iconColor };
|
||||||
|
}
|
||||||
|
const iconClass = util.makeIconClass(blockIcon, true);
|
||||||
|
if (iconClass != null) {
|
||||||
|
blockIconElem = <i key="icon" style={iconStyle} className={clsx(`block-frame-icon`, iconClass)} />;
|
||||||
|
}
|
||||||
|
return blockIconElem;
|
||||||
|
}
|
||||||
|
|
||||||
function getBlockHeaderText(blockIcon: string, blockData: Block, settings: SettingsConfigType): React.ReactNode {
|
function getBlockHeaderText(blockIcon: string, blockData: Block, settings: SettingsConfigType): React.ReactNode {
|
||||||
if (!blockData) {
|
if (!blockData) {
|
||||||
return "no block data";
|
return "no block data";
|
||||||
@ -103,21 +123,7 @@ function getBlockHeaderText(blockIcon: string, blockData: Block, settings: Setti
|
|||||||
if (settings?.blockheader?.showblockids) {
|
if (settings?.blockheader?.showblockids) {
|
||||||
blockIdStr = ` [${blockData.oid.substring(0, 8)}]`;
|
blockIdStr = ` [${blockData.oid.substring(0, 8)}]`;
|
||||||
}
|
}
|
||||||
let blockIconElem: React.ReactNode = null;
|
let blockIconElem = getBlockHeaderIcon(blockIcon, blockData);
|
||||||
if (!util.isBlank(blockIcon)) {
|
|
||||||
let iconColor = blockData?.meta?.["icon:color"];
|
|
||||||
if (iconColor && !iconColor.match(colorRegex)) {
|
|
||||||
iconColor = null;
|
|
||||||
}
|
|
||||||
let iconStyle = null;
|
|
||||||
if (!util.isBlank(iconColor)) {
|
|
||||||
iconStyle = { color: iconColor };
|
|
||||||
}
|
|
||||||
const iconClass = util.makeIconClass(blockIcon, false);
|
|
||||||
if (iconClass != null) {
|
|
||||||
blockIconElem = <i key="icon" style={iconStyle} className={clsx(`block-frame-icon`, iconClass)} />;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!util.isBlank(blockData?.meta?.title)) {
|
if (!util.isBlank(blockData?.meta?.title)) {
|
||||||
try {
|
try {
|
||||||
const rtn = processTitleString(blockData.meta.title) ?? [];
|
const rtn = processTitleString(blockData.meta.title) ?? [];
|
||||||
@ -207,6 +213,7 @@ interface BlockFrameProps {
|
|||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
onFocusCapture?: React.FocusEventHandler<HTMLDivElement>;
|
onFocusCapture?: React.FocusEventHandler<HTMLDivElement>;
|
||||||
preview: boolean;
|
preview: boolean;
|
||||||
|
numBlocksInTab?: number;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
blockRef?: React.RefObject<HTMLDivElement>;
|
blockRef?: React.RefObject<HTMLDivElement>;
|
||||||
dragHandleRef?: React.RefObject<HTMLDivElement>;
|
dragHandleRef?: React.RefObject<HTMLDivElement>;
|
||||||
@ -272,6 +279,117 @@ const BlockFrame_Tech_Component = ({
|
|||||||
|
|
||||||
const BlockFrame_Tech = React.memo(BlockFrame_Tech_Component) as typeof BlockFrame_Tech_Component;
|
const BlockFrame_Tech = React.memo(BlockFrame_Tech_Component) as typeof BlockFrame_Tech_Component;
|
||||||
|
|
||||||
|
const BlockFrame_Default_Component = ({
|
||||||
|
blockId,
|
||||||
|
onClose,
|
||||||
|
onClick,
|
||||||
|
preview,
|
||||||
|
blockRef,
|
||||||
|
dragHandleRef,
|
||||||
|
numBlocksInTab,
|
||||||
|
onFocusCapture,
|
||||||
|
children,
|
||||||
|
}: BlockFrameProps) => {
|
||||||
|
const [blockData] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
|
||||||
|
const settingsConfig = jotai.useAtomValue(atoms.settingsConfigAtom);
|
||||||
|
const isFocusedAtom = useBlockAtom<boolean>(blockId, "isFocused", () => {
|
||||||
|
return jotai.atom((get) => {
|
||||||
|
const winData = get(atoms.waveWindow);
|
||||||
|
return winData?.activeblockid === blockId;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
let isFocused = jotai.useAtomValue(isFocusedAtom);
|
||||||
|
const blockIcon = useBlockIcon(blockId);
|
||||||
|
if (preview) {
|
||||||
|
isFocused = true;
|
||||||
|
}
|
||||||
|
let style: React.CSSProperties = {};
|
||||||
|
if (!isFocused && blockData?.meta?.["frame:bordercolor"]) {
|
||||||
|
style.borderColor = blockData.meta["frame:bordercolor"];
|
||||||
|
}
|
||||||
|
if (isFocused && blockData?.meta?.["frame:bordercolor:focused"]) {
|
||||||
|
style.borderColor = blockData.meta["frame:bordercolor:focused"];
|
||||||
|
}
|
||||||
|
let handleSettings = (e: React.MouseEvent<any>) => {
|
||||||
|
let menuItems: ContextMenuItem[] = [];
|
||||||
|
menuItems.push({
|
||||||
|
label: "Focus Block",
|
||||||
|
click: () => {
|
||||||
|
alert("Not Implemented");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
menuItems.push({ label: "Minimize" });
|
||||||
|
menuItems.push({ type: "separator" });
|
||||||
|
menuItems.push({
|
||||||
|
label: "Move to New Window",
|
||||||
|
click: () => {
|
||||||
|
let currentTabId = globalStore.get(atoms.activeTabId);
|
||||||
|
try {
|
||||||
|
services.WindowService.MoveBlockToNewWindow(currentTabId, blockData.oid);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("error moving block to new window", e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
menuItems.push({ type: "separator" });
|
||||||
|
menuItems.push({
|
||||||
|
label: "Copy BlockId",
|
||||||
|
click: () => {
|
||||||
|
navigator.clipboard.writeText(blockData.oid);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
menuItems.push({ type: "separator" });
|
||||||
|
menuItems.push({ label: "Close", click: onClose });
|
||||||
|
ContextMenuModel.showContextMenu(menuItems, e);
|
||||||
|
};
|
||||||
|
if (preview) {
|
||||||
|
handleSettings = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
"block",
|
||||||
|
"block-frame-default",
|
||||||
|
isFocused ? "block-focused" : null,
|
||||||
|
preview ? "block-preview" : null,
|
||||||
|
numBlocksInTab == 1 ? "block-no-highlight" : null
|
||||||
|
)}
|
||||||
|
onClick={onClick}
|
||||||
|
onFocusCapture={onFocusCapture}
|
||||||
|
ref={blockRef}
|
||||||
|
style={style}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="block-frame-default-header"
|
||||||
|
ref={dragHandleRef}
|
||||||
|
onContextMenu={(e) => handleHeaderContextMenu(e, blockData, onClose)}
|
||||||
|
>
|
||||||
|
<div className="block-frame-default-header-iconview">
|
||||||
|
<div className="block-frame-view-icon">{getBlockHeaderIcon(blockIcon, blockData)}</div>
|
||||||
|
<div className="block-frame-view-type">{blockViewToName(blockData?.view)}</div>
|
||||||
|
{settingsConfig?.blockheader?.showblockids && (
|
||||||
|
<div className="block-frame-blockid">[{blockId.substring(0, 8)}]</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex-spacer"></div>
|
||||||
|
<div className="block-frame-end-icons">
|
||||||
|
<div className="block-frame-settings" onClick={handleSettings}>
|
||||||
|
<i className="fa fa-solid fa-cog fa-fw" />
|
||||||
|
</div>
|
||||||
|
<div className={clsx("block-frame-default-close")} onClick={onClose}>
|
||||||
|
<i className="fa fa-solid fa-xmark-large fa-fw" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{preview ? <div className="block-frame-preview" /> : children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const BlockFrame_Default = React.memo(BlockFrame_Default_Component) as typeof BlockFrame_Default_Component;
|
||||||
|
|
||||||
const BlockFrame_Frameless = ({
|
const BlockFrame_Frameless = ({
|
||||||
blockId,
|
blockId,
|
||||||
onClose,
|
onClose,
|
||||||
@ -354,27 +472,27 @@ const BlockFrame = React.memo((props: BlockFrameProps) => {
|
|||||||
if (!blockId || !blockData) {
|
if (!blockId || !blockData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let FrameElem = BlockFrame_Tech;
|
let FrameElem = BlockFrame_Default;
|
||||||
|
const numBlocks = tabData?.blockids?.length ?? 0;
|
||||||
// Preview should always render as the full tech frame
|
// Preview should always render as the full tech frame
|
||||||
if (!props.preview) {
|
if (!props.preview) {
|
||||||
// if 0 or 1 blocks, use frameless, otherwise use tech
|
// if 0 or 1 blocks, use frameless, otherwise use tech
|
||||||
const numBlocks = tabData?.blockids?.length ?? 0;
|
// if (numBlocks <= 1) {
|
||||||
if (numBlocks <= 1) {
|
// FrameElem = BlockFrame_Frameless;
|
||||||
FrameElem = BlockFrame_Frameless;
|
// }
|
||||||
}
|
|
||||||
if (blockData?.meta?.["frame"] === "tech") {
|
if (blockData?.meta?.["frame"] === "tech") {
|
||||||
FrameElem = BlockFrame_Tech;
|
FrameElem = BlockFrame_Tech;
|
||||||
} else if (blockData?.meta?.["frame"] === "frameless") {
|
} else if (blockData?.meta?.["frame"] === "frameless") {
|
||||||
FrameElem = BlockFrame_Frameless;
|
FrameElem = BlockFrame_Frameless;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return <FrameElem {...props} />;
|
return <FrameElem {...props} numBlocksInTab={numBlocks} />;
|
||||||
});
|
});
|
||||||
|
|
||||||
function blockViewToIcon(view: string): string {
|
function blockViewToIcon(view: string): string {
|
||||||
console.log("blockViewToIcon", view);
|
console.log("blockViewToIcon", view);
|
||||||
if (view == "term") {
|
if (view == "term") {
|
||||||
return "square-terminal";
|
return "terminal";
|
||||||
}
|
}
|
||||||
if (view == "preview") {
|
if (view == "preview") {
|
||||||
return "file";
|
return "file";
|
||||||
@ -388,6 +506,22 @@ function blockViewToIcon(view: string): string {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function blockViewToName(view: string): string {
|
||||||
|
if (view == "term") {
|
||||||
|
return "Terminal";
|
||||||
|
}
|
||||||
|
if (view == "preview") {
|
||||||
|
return "Preview";
|
||||||
|
}
|
||||||
|
if (view == "web") {
|
||||||
|
return "Web";
|
||||||
|
}
|
||||||
|
if (view == "waveai") {
|
||||||
|
return "WaveAI";
|
||||||
|
}
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
function useBlockIcon(blockId: string): string {
|
function useBlockIcon(blockId: string): string {
|
||||||
const blockIconOverrideAtom = useBlockAtom<string>(blockId, "blockicon:override", () => {
|
const blockIconOverrideAtom = useBlockAtom<string>(blockId, "blockicon:override", () => {
|
||||||
return jotai.atom<string>(null);
|
return jotai.atom<string>(null);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
--grey-text-color: #666;
|
--grey-text-color: #666;
|
||||||
--main-bg-color: #000000;
|
--main-bg-color: #000000;
|
||||||
--border-color: #333333;
|
--border-color: #333333;
|
||||||
--base-font: normal 15px / normal "Inter", sans-serif;
|
--base-font: normal 14px / normal "Inter", sans-serif;
|
||||||
--fixed-font: normal 12px / normal "Hack", monospace;
|
--fixed-font: normal 12px / normal "Hack", monospace;
|
||||||
--accent-color: rgb(88, 193, 66);
|
--accent-color: rgb(88, 193, 66);
|
||||||
--panel-bg-color: rgba(31, 33, 31, 1);
|
--panel-bg-color: rgba(31, 33, 31, 1);
|
||||||
@ -25,6 +25,10 @@
|
|||||||
--scrollbar-thumb-hover-color: rgba(255, 255, 255, 0.5);
|
--scrollbar-thumb-hover-color: rgba(255, 255, 255, 0.5);
|
||||||
--scrollbar-thumb-active-color: rgba(255, 255, 255, 0.6);
|
--scrollbar-thumb-active-color: rgba(255, 255, 255, 0.6);
|
||||||
|
|
||||||
|
--header-font: 700 11px / normal "Inter", sans-serif;
|
||||||
|
--header-icon-size: 14px;
|
||||||
|
--header-icon-width: 16px;
|
||||||
|
|
||||||
--tab-green: rgb(88, 193, 66);
|
--tab-green: rgb(88, 193, 66);
|
||||||
|
|
||||||
/* z-index values */
|
/* z-index values */
|
||||||
|
@ -262,10 +262,10 @@ const TerminalView = ({ blockId }: { blockId: string }) => {
|
|||||||
shellProcStatusRef.current = status;
|
shellProcStatusRef.current = status;
|
||||||
if (status == "running") {
|
if (status == "running") {
|
||||||
termRef.current?.setIsRunning(true);
|
termRef.current?.setIsRunning(true);
|
||||||
globalStore.set(blockIconOverrideAtom, "square-terminal");
|
globalStore.set(blockIconOverrideAtom, "terminal");
|
||||||
} else {
|
} else {
|
||||||
termRef.current?.setIsRunning(false);
|
termRef.current?.setIsRunning(false);
|
||||||
globalStore.set(blockIconOverrideAtom, "regular@square-terminal");
|
globalStore.set(blockIconOverrideAtom, "regular@terminal");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const initialRTStatus = services.BlockService.GetControllerStatus(blockId);
|
const initialRTStatus = services.BlockService.GetControllerStatus(blockId);
|
||||||
|
Loading…
Reference in New Issue
Block a user