projectPanel.ts

  1import { ColorScheme } from "../theme/colorScheme"
  2import { withOpacity } from "../theme/color"
  3import {
  4    Border,
  5    TextStyle,
  6    background,
  7    border,
  8    foreground,
  9    text,
 10} from "./components"
 11import { interactive, toggleable } from "../element"
 12import merge from "ts-deepmerge"
 13export default function projectPanel(colorScheme: ColorScheme) {
 14    const { isLight } = colorScheme
 15
 16    let layer = colorScheme.middle
 17
 18    type EntryStateProps = {
 19        background?: string
 20        border?: Border
 21        text?: TextStyle
 22        iconColor?: string
 23    }
 24
 25    type EntryState = {
 26        default: EntryStateProps
 27        hovered?: EntryStateProps
 28        clicked?: EntryStateProps
 29    }
 30
 31    const entry = (unselected?: EntryState, selected?: EntryState) => {
 32        const git_status = {
 33            git: {
 34                modified: isLight
 35                    ? colorScheme.ramps.yellow(0.6).hex()
 36                    : colorScheme.ramps.yellow(0.5).hex(),
 37                inserted: isLight
 38                    ? colorScheme.ramps.green(0.45).hex()
 39                    : colorScheme.ramps.green(0.5).hex(),
 40                conflict: isLight
 41                    ? colorScheme.ramps.red(0.6).hex()
 42                    : colorScheme.ramps.red(0.5).hex(),
 43            },
 44        }
 45
 46        const base_properties = {
 47            height: 22,
 48            background: background(layer),
 49            iconColor: foreground(layer, "variant"),
 50            iconSize: 7,
 51            iconSpacing: 5,
 52            text: text(layer, "sans", "variant", { size: "sm" }),
 53            status: {
 54                ...git_status,
 55            },
 56        }
 57
 58        const selectedStyle: EntryState | undefined = selected
 59            ? selected
 60            : unselected
 61
 62        const unselected_default_style = merge(
 63            base_properties,
 64            unselected?.default ?? {},
 65            {}
 66        )
 67        const unselected_hovered_style = merge(
 68            base_properties,
 69            { background: background(layer, "hovered") },
 70            unselected?.hovered ?? {},
 71        )
 72        const unselected_clicked_style = merge(
 73            base_properties,
 74            { background: background(layer, "pressed") },
 75            unselected?.clicked ?? {},
 76        )
 77        const selected_default_style = merge(
 78            base_properties,
 79            {
 80                background: background(colorScheme.lowest),
 81                text: text(colorScheme.lowest, "sans", { size: "sm" }),
 82            },
 83            selectedStyle?.default ?? {},
 84        )
 85        const selected_hovered_style = merge(
 86            base_properties,
 87            {
 88                background: background(colorScheme.lowest, "hovered"),
 89                text: text(colorScheme.lowest, "sans", { size: "sm" }),
 90            },
 91            selectedStyle?.hovered ?? {},
 92        )
 93        const selected_clicked_style = merge(
 94            base_properties,
 95            {
 96                background: background(colorScheme.lowest, "pressed"),
 97                text: text(colorScheme.lowest, "sans", { size: "sm" }),
 98            },
 99            selectedStyle?.clicked ?? {},
100        )
101
102        return toggleable({
103            state: {
104                inactive: interactive({
105                    state: {
106                        default: unselected_default_style,
107                        hovered: unselected_hovered_style,
108                        clicked: unselected_clicked_style,
109                    },
110                }),
111                active: interactive({
112                    state: {
113                        default: selected_default_style,
114                        hovered: selected_hovered_style,
115                        clicked: selected_clicked_style,
116                    },
117                }),
118            },
119        })
120    }
121
122    const defaultEntry = entry()
123
124    return {
125        openProjectButton: interactive({
126            base: {
127                background: background(layer),
128                border: border(layer, "active"),
129                cornerRadius: 4,
130                margin: {
131                    top: 16,
132                    left: 16,
133                    right: 16,
134                },
135                padding: {
136                    top: 3,
137                    bottom: 3,
138                    left: 7,
139                    right: 7,
140                },
141                ...text(layer, "sans", "default", { size: "sm" }),
142            },
143            state: {
144                hovered: {
145                    ...text(layer, "sans", "default", { size: "sm" }),
146                    background: background(layer, "hovered"),
147                    border: border(layer, "active"),
148                },
149                clicked: {
150                    ...text(layer, "sans", "default", { size: "sm" }),
151                    background: background(layer, "pressed"),
152                    border: border(layer, "active"),
153                },
154            },
155        }),
156        background: background(layer),
157        padding: { left: 6, right: 6, top: 0, bottom: 6 },
158        indentWidth: 12,
159        entry: defaultEntry,
160        draggedEntry: {
161            ...defaultEntry.inactive.default,
162            text: text(layer, "sans", "on", { size: "sm" }),
163            background: withOpacity(background(layer, "on"), 0.9),
164            border: border(layer),
165        },
166        ignoredEntry: entry(
167            {
168                default: {
169                    text: text(layer, "sans", "disabled"),
170                },
171            },
172            {
173                default: {
174                    iconColor: foreground(layer, "variant"),
175                },
176            }
177        ),
178        cutEntry: entry(
179            {
180                default: {
181                    text: text(layer, "sans", "disabled"),
182                },
183            },
184            {
185                default: {
186                    background: background(layer, "active"),
187                    text: text(layer, "sans", "disabled", { size: "sm" }),
188                },
189            }
190        ),
191        filenameEditor: {
192            background: background(layer, "on"),
193            text: text(layer, "sans", "on", { size: "sm" }),
194            selection: colorScheme.players[0],
195        },
196    }
197}