tui: show monochrome file icons by default in tree view, revealing colors on hover to reduce visual clutter and help users focus on code content
parent
ce7484b4f5
commit
a685e7a805
|
|
@ -447,12 +447,13 @@ export default function FileTree(props: {
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={`flex flex-col gap-0.5 ${props.class ?? ""}`}>
|
<div data-component="filetree" class={`flex flex-col gap-0.5 ${props.class ?? ""}`}>
|
||||||
<For each={nodes()}>
|
<For each={nodes()}>
|
||||||
{(node) => {
|
{(node) => {
|
||||||
const expanded = () => file.tree.state(node.path)?.expanded ?? false
|
const expanded = () => file.tree.state(node.path)?.expanded ?? false
|
||||||
const deep = () => deeps().get(node.path) ?? -1
|
const deep = () => deeps().get(node.path) ?? -1
|
||||||
const kind = () => visibleKind(node, kinds(), marks())
|
const kind = () => visibleKind(node, kinds(), marks())
|
||||||
|
const active = () => !!kind() && !node.ignored
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
|
|
@ -530,7 +531,30 @@ export default function FileTree(props: {
|
||||||
onClick={() => props.onFileClick?.(node)}
|
onClick={() => props.onFileClick?.(node)}
|
||||||
>
|
>
|
||||||
<div class="w-4 shrink-0" />
|
<div class="w-4 shrink-0" />
|
||||||
<FileIcon node={node} class="text-icon-weak size-4" />
|
<Switch>
|
||||||
|
<Match when={node.ignored}>
|
||||||
|
<FileIcon
|
||||||
|
node={node}
|
||||||
|
class="size-4 filetree-icon filetree-icon--mono"
|
||||||
|
style="color: var(--icon-weak-base)"
|
||||||
|
mono
|
||||||
|
/>
|
||||||
|
</Match>
|
||||||
|
<Match when={active()}>
|
||||||
|
<FileIcon
|
||||||
|
node={node}
|
||||||
|
class="size-4 filetree-icon filetree-icon--mono"
|
||||||
|
style={kindTextColor(kind()!)}
|
||||||
|
mono
|
||||||
|
/>
|
||||||
|
</Match>
|
||||||
|
<Match when={!node.ignored}>
|
||||||
|
<span class="filetree-iconpair size-4">
|
||||||
|
<FileIcon node={node} class="size-4 filetree-icon filetree-icon--color" />
|
||||||
|
<FileIcon node={node} class="size-4 filetree-icon filetree-icon--mono" mono />
|
||||||
|
</span>
|
||||||
|
</Match>
|
||||||
|
</Switch>
|
||||||
</FileTreeNode>
|
</FileTreeNode>
|
||||||
</FileTreeNodeTooltip>
|
</FileTreeNodeTooltip>
|
||||||
</Match>
|
</Match>
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,35 @@
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
File tree: show monochrome weak icons by default.
|
||||||
|
On hover, show the original file-type colors.
|
||||||
|
*/
|
||||||
|
[data-component="filetree"] .filetree-icon--mono {
|
||||||
|
color: var(--icon-base);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="filetree"] .filetree-iconpair {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="filetree"] .filetree-iconpair [data-component="file-icon"] {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="filetree"] .filetree-iconpair .filetree-icon--color {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="filetree"]:hover .filetree-iconpair .filetree-icon--color {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="filetree"]:hover .filetree-iconpair .filetree-icon--mono {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
import type { Component, JSX } from "solid-js"
|
import type { Component, JSX } from "solid-js"
|
||||||
import { createMemo, splitProps } from "solid-js"
|
import { createMemo, splitProps, Show } from "solid-js"
|
||||||
import sprite from "./file-icons/sprite.svg"
|
import sprite from "./file-icons/sprite.svg"
|
||||||
import type { IconName } from "./file-icons/types"
|
import type { IconName } from "./file-icons/types"
|
||||||
|
|
||||||
|
let filter = 0
|
||||||
|
|
||||||
export type FileIconProps = JSX.GSVGAttributes<SVGSVGElement> & {
|
export type FileIconProps = JSX.GSVGAttributes<SVGSVGElement> & {
|
||||||
node: { path: string; type: "file" | "directory" }
|
node: { path: string; type: "file" | "directory" }
|
||||||
expanded?: boolean
|
expanded?: boolean
|
||||||
|
mono?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FileIcon: Component<FileIconProps> = (props) => {
|
export const FileIcon: Component<FileIconProps> = (props) => {
|
||||||
const [local, rest] = splitProps(props, ["node", "class", "classList", "expanded"])
|
const [local, rest] = splitProps(props, ["node", "class", "classList", "expanded", "mono"])
|
||||||
const name = createMemo(() => chooseIconName(local.node.path, local.node.type, local.expanded || false))
|
const name = createMemo(() => chooseIconName(local.node.path, local.node.type, local.expanded || false))
|
||||||
|
const id = `file-icon-mono-${filter++}`
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
data-component="file-icon"
|
data-component="file-icon"
|
||||||
|
|
@ -20,7 +24,15 @@ export const FileIcon: Component<FileIconProps> = (props) => {
|
||||||
[local.class ?? ""]: !!local.class,
|
[local.class ?? ""]: !!local.class,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<use href={`${sprite}#${name()}`} />
|
<Show when={local.mono}>
|
||||||
|
<defs>
|
||||||
|
<filter id={id} color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-color="currentColor" result="flood" />
|
||||||
|
<feComposite in="flood" in2="SourceAlpha" operator="in" />
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</Show>
|
||||||
|
<use href={`${sprite}#${name()}`} filter={local.mono ? `url(#${id})` : undefined} />
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue