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}