Style cleanup for channels panel
This commit is contained in:
@@ -1,6 +1,118 @@
|
||||
export const ButtonVariant = {
|
||||
Default: 'default',
|
||||
Ghost: 'ghost'
|
||||
} as const
|
||||
import { font_sizes, useTheme } from "../common"
|
||||
import { Layer, Theme } from "../theme"
|
||||
import { TextStyle, background } from "../style_tree/components"
|
||||
|
||||
export type Variant = typeof ButtonVariant[keyof typeof ButtonVariant]
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
export namespace Button {
|
||||
export type Options = {
|
||||
layer: Layer,
|
||||
background: keyof Theme["lowest"]
|
||||
color: keyof Theme["lowest"]
|
||||
variant: Button.Variant
|
||||
size: Button.Size
|
||||
shape: Button.Shape
|
||||
margin: {
|
||||
top?: number
|
||||
bottom?: number
|
||||
left?: number
|
||||
right?: number
|
||||
},
|
||||
states: {
|
||||
enabled?: boolean,
|
||||
hovered?: boolean,
|
||||
pressed?: boolean,
|
||||
focused?: boolean,
|
||||
disabled?: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
export type ToggleableOptions = Options & {
|
||||
active_background: keyof Theme["lowest"]
|
||||
active_color: keyof Theme["lowest"]
|
||||
}
|
||||
|
||||
/** Padding added to each side of a Shape.Rectangle button */
|
||||
export const RECTANGLE_PADDING = 2
|
||||
export const FONT_SIZE = font_sizes.sm
|
||||
export const ICON_SIZE = 14
|
||||
export const CORNER_RADIUS = 6
|
||||
|
||||
export const variant = {
|
||||
Default: 'filled',
|
||||
Outline: 'outline',
|
||||
Ghost: 'ghost'
|
||||
} as const
|
||||
|
||||
export type Variant = typeof variant[keyof typeof variant]
|
||||
|
||||
export const shape = {
|
||||
Rectangle: 'rectangle',
|
||||
Square: 'square'
|
||||
} as const
|
||||
|
||||
export type Shape = typeof shape[keyof typeof shape]
|
||||
|
||||
export const size = {
|
||||
Small: "sm",
|
||||
Medium: "md"
|
||||
} as const
|
||||
|
||||
export type Size = typeof size[keyof typeof size]
|
||||
|
||||
export type BaseStyle = {
|
||||
corder_radius: number
|
||||
background: string | null
|
||||
padding: {
|
||||
top: number
|
||||
bottom: number
|
||||
left: number
|
||||
right: number
|
||||
},
|
||||
margin: Button.Options['margin']
|
||||
button_height: number
|
||||
}
|
||||
|
||||
export type LabelButtonStyle = BaseStyle & TextStyle
|
||||
// export type IconButtonStyle = ButtonStyle
|
||||
|
||||
export const button_base = (
|
||||
options: Partial<Button.Options> = {
|
||||
variant: Button.variant.Default,
|
||||
shape: Button.shape.Rectangle,
|
||||
states: {
|
||||
hovered: true,
|
||||
pressed: true
|
||||
}
|
||||
}
|
||||
): BaseStyle => {
|
||||
const theme = useTheme()
|
||||
|
||||
const layer = options.layer ?? theme.middle
|
||||
const color = options.color ?? "base"
|
||||
const background_color = options.variant === Button.variant.Ghost ? null : background(layer, options.background ?? color)
|
||||
|
||||
const m = {
|
||||
top: options.margin?.top ?? 0,
|
||||
bottom: options.margin?.bottom ?? 0,
|
||||
left: options.margin?.left ?? 0,
|
||||
right: options.margin?.right ?? 0,
|
||||
}
|
||||
const size = options.size || Button.size.Medium
|
||||
const padding = 2
|
||||
|
||||
const base: BaseStyle = {
|
||||
background: background_color,
|
||||
corder_radius: Button.CORNER_RADIUS,
|
||||
padding: {
|
||||
top: padding,
|
||||
bottom: padding,
|
||||
left: options.shape === Button.shape.Rectangle ? padding + Button.RECTANGLE_PADDING : padding,
|
||||
right: options.shape === Button.shape.Rectangle ? padding + Button.RECTANGLE_PADDING : padding
|
||||
},
|
||||
margin: m,
|
||||
button_height: 16,
|
||||
}
|
||||
|
||||
return base
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { interactive, toggleable } from "../element"
|
||||
import { background, foreground } from "../style_tree/components"
|
||||
import { useTheme, Theme } from "../theme"
|
||||
import { ButtonVariant, Variant } from "./button"
|
||||
import { useTheme, Theme, Layer } from "../theme"
|
||||
import { Button } from "./button"
|
||||
|
||||
export type Margin = {
|
||||
top: number
|
||||
@@ -17,19 +17,24 @@ interface IconButtonOptions {
|
||||
| Theme["highest"]
|
||||
color?: keyof Theme["lowest"]
|
||||
margin?: Partial<Margin>
|
||||
variant?: Variant
|
||||
variant?: Button.Variant
|
||||
size?: Button.Size
|
||||
}
|
||||
|
||||
type ToggleableIconButtonOptions = IconButtonOptions & {
|
||||
active_color?: keyof Theme["lowest"]
|
||||
active_layer?: Layer
|
||||
}
|
||||
|
||||
export function icon_button({ color, margin, layer, variant = ButtonVariant.Default }: IconButtonOptions) {
|
||||
export function icon_button({ color, margin, layer, variant, size }: IconButtonOptions = {
|
||||
variant: Button.variant.Default,
|
||||
size: Button.size.Medium,
|
||||
}) {
|
||||
const theme = useTheme()
|
||||
|
||||
if (!color) color = "base"
|
||||
|
||||
const background_color = variant === ButtonVariant.Ghost ? null : background(layer ?? theme.lowest, color)
|
||||
const background_color = variant === Button.variant.Ghost ? null : background(layer ?? theme.lowest, color)
|
||||
|
||||
const m = {
|
||||
top: margin?.top ?? 0,
|
||||
@@ -38,15 +43,17 @@ export function icon_button({ color, margin, layer, variant = ButtonVariant.Defa
|
||||
right: margin?.right ?? 0,
|
||||
}
|
||||
|
||||
const padding = {
|
||||
top: size === Button.size.Small ? 0 : 2,
|
||||
bottom: size === Button.size.Small ? 0 : 2,
|
||||
left: size === Button.size.Small ? 0 : 4,
|
||||
right: size === Button.size.Small ? 0 : 4,
|
||||
}
|
||||
|
||||
return interactive({
|
||||
base: {
|
||||
corner_radius: 6,
|
||||
padding: {
|
||||
top: 2,
|
||||
bottom: 2,
|
||||
left: 4,
|
||||
right: 4,
|
||||
},
|
||||
padding: padding,
|
||||
margin: m,
|
||||
icon_width: 14,
|
||||
icon_height: 14,
|
||||
@@ -72,17 +79,18 @@ export function icon_button({ color, margin, layer, variant = ButtonVariant.Defa
|
||||
|
||||
export function toggleable_icon_button(
|
||||
theme: Theme,
|
||||
{ color, active_color, margin, variant }: ToggleableIconButtonOptions
|
||||
{ color, active_color, margin, variant, size, active_layer }: ToggleableIconButtonOptions
|
||||
) {
|
||||
if (!color) color = "base"
|
||||
|
||||
return toggleable({
|
||||
state: {
|
||||
inactive: icon_button({ color, margin, variant }),
|
||||
inactive: icon_button({ color, margin, variant, size }),
|
||||
active: icon_button({
|
||||
color: active_color ? active_color : color,
|
||||
margin,
|
||||
layer: theme.middle,
|
||||
layer: active_layer,
|
||||
size
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import { Interactive, interactive, toggleable, Toggleable } from "../element"
|
||||
import { TextStyle, background, text } from "../style_tree/components"
|
||||
import { useTheme } from "../theme"
|
||||
import { Button } from "./button"
|
||||
|
||||
type LabelButtonStyle = {
|
||||
corder_radius: number
|
||||
background: string | null
|
||||
padding: {
|
||||
top: number
|
||||
bottom: number
|
||||
left: number
|
||||
right: number
|
||||
},
|
||||
margin: Button.Options['margin']
|
||||
button_height: number
|
||||
} & TextStyle
|
||||
|
||||
/** Styles an Interactive<ContainedText> */
|
||||
export function label_button_style(
|
||||
options: Partial<Button.Options> = {
|
||||
variant: Button.variant.Default,
|
||||
shape: Button.shape.Rectangle,
|
||||
states: {
|
||||
hovered: true,
|
||||
pressed: true
|
||||
}
|
||||
}
|
||||
): Interactive<LabelButtonStyle> {
|
||||
const theme = useTheme()
|
||||
|
||||
const base = Button.button_base(options)
|
||||
const layer = options.layer ?? theme.middle
|
||||
const color = options.color ?? "base"
|
||||
|
||||
const default_state = {
|
||||
...base,
|
||||
...text(layer ?? theme.lowest, "sans", color),
|
||||
font_size: Button.FONT_SIZE,
|
||||
}
|
||||
|
||||
return interactive({
|
||||
base: default_state,
|
||||
state: {
|
||||
hovered: {
|
||||
background: background(layer, options.background ?? color, "hovered")
|
||||
},
|
||||
clicked: {
|
||||
background: background(layer, options.background ?? color, "pressed")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** Styles an Toggleable<Interactive<ContainedText>> */
|
||||
export function toggle_label_button_style(
|
||||
options: Partial<Button.ToggleableOptions> = {
|
||||
variant: Button.variant.Default,
|
||||
shape: Button.shape.Rectangle,
|
||||
states: {
|
||||
hovered: true,
|
||||
pressed: true
|
||||
}
|
||||
}
|
||||
): Toggleable<Interactive<LabelButtonStyle>> {
|
||||
const activeOptions = {
|
||||
...options,
|
||||
color: options.active_color || options.color,
|
||||
background: options.active_background || options.background
|
||||
}
|
||||
|
||||
return toggleable({
|
||||
state: {
|
||||
inactive: label_button_style(options),
|
||||
active: label_button_style(activeOptions),
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
text,
|
||||
} from "../style_tree/components"
|
||||
import { useTheme, Theme } from "../theme"
|
||||
import { ButtonVariant, Variant } from "./button"
|
||||
import { Button } from "./button"
|
||||
import { Margin } from "./icon_button"
|
||||
|
||||
interface TextButtonOptions {
|
||||
@@ -14,7 +14,7 @@ interface TextButtonOptions {
|
||||
| Theme["lowest"]
|
||||
| Theme["middle"]
|
||||
| Theme["highest"]
|
||||
variant?: Variant
|
||||
variant?: Button.Variant
|
||||
color?: keyof Theme["lowest"]
|
||||
margin?: Partial<Margin>
|
||||
text_properties?: TextProperties
|
||||
@@ -25,7 +25,7 @@ type ToggleableTextButtonOptions = TextButtonOptions & {
|
||||
}
|
||||
|
||||
export function text_button({
|
||||
variant = ButtonVariant.Default,
|
||||
variant = Button.variant.Default,
|
||||
color,
|
||||
layer,
|
||||
margin,
|
||||
@@ -34,7 +34,7 @@ export function text_button({
|
||||
const theme = useTheme()
|
||||
if (!color) color = "base"
|
||||
|
||||
const background_color = variant === ButtonVariant.Ghost ? null : background(layer ?? theme.lowest, color)
|
||||
const background_color = variant === Button.variant.Ghost ? null : background(layer ?? theme.lowest, color)
|
||||
|
||||
const text_options: TextProperties = {
|
||||
size: "xs",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { interactive, Interactive } from "./interactive"
|
||||
import { toggleable } from "./toggle"
|
||||
import { toggleable, Toggleable } from "./toggle"
|
||||
|
||||
export { interactive, Interactive, toggleable }
|
||||
export { interactive, Interactive, toggleable, Toggleable }
|
||||
|
||||
@@ -3,7 +3,7 @@ import { DeepPartial } from "utility-types"
|
||||
|
||||
type ToggleState = "inactive" | "active"
|
||||
|
||||
type Toggleable<T> = Record<ToggleState, T>
|
||||
export type Toggleable<T> = Record<ToggleState, T>
|
||||
|
||||
export const NO_INACTIVE_OR_BASE_ERROR =
|
||||
"A toggleable object must have an inactive state, or a base property."
|
||||
|
||||
@@ -9,7 +9,7 @@ import { interactive, toggleable } from "../element"
|
||||
import { useTheme } from "../theme"
|
||||
import collab_modals from "./collab_modals"
|
||||
import { text_button } from "../component/text_button"
|
||||
import { toggleable_icon_button } from "../component/icon_button"
|
||||
import { icon_button, toggleable_icon_button } from "../component/icon_button"
|
||||
import { indicator } from "../component/indicator"
|
||||
|
||||
export default function contacts_panel(): any {
|
||||
@@ -27,7 +27,7 @@ export default function contacts_panel(): any {
|
||||
color: foreground(layer, "on"),
|
||||
icon_width: 14,
|
||||
button_width: 16,
|
||||
corner_radius: 8,
|
||||
corner_radius: 8
|
||||
}
|
||||
|
||||
const project_row = {
|
||||
@@ -62,8 +62,9 @@ export default function contacts_panel(): any {
|
||||
}
|
||||
|
||||
const header_icon_button = toggleable_icon_button(theme, {
|
||||
layer: theme.middle,
|
||||
variant: "ghost",
|
||||
size: "sm",
|
||||
active_layer: theme.lowest,
|
||||
})
|
||||
|
||||
const subheader_row = toggleable({
|
||||
@@ -87,8 +88,8 @@ export default function contacts_panel(): any {
|
||||
state: {
|
||||
active: {
|
||||
default: {
|
||||
...text(layer, "ui_sans", "active", { size: "sm" }),
|
||||
background: background(layer, "active"),
|
||||
...text(theme.lowest, "ui_sans", { size: "sm" }),
|
||||
background: background(theme.lowest),
|
||||
},
|
||||
clicked: {
|
||||
background: background(layer, "pressed"),
|
||||
@@ -140,8 +141,8 @@ export default function contacts_panel(): any {
|
||||
},
|
||||
active: {
|
||||
default: {
|
||||
...text(layer, "ui_sans", "active", { size: "sm" }),
|
||||
background: background(layer, "active"),
|
||||
...text(theme.lowest, "ui_sans", { size: "sm" }),
|
||||
background: background(theme.lowest),
|
||||
},
|
||||
clicked: {
|
||||
background: background(layer, "pressed"),
|
||||
@@ -221,8 +222,8 @@ export default function contacts_panel(): any {
|
||||
},
|
||||
active: {
|
||||
default: {
|
||||
...text(layer, "ui_sans", "active", { size: "sm" }),
|
||||
background: background(layer, "active"),
|
||||
...text(theme.lowest, "ui_sans", { size: "sm" }),
|
||||
background: background(theme.lowest),
|
||||
},
|
||||
clicked: {
|
||||
background: background(layer, "pressed"),
|
||||
@@ -271,8 +272,8 @@ export default function contacts_panel(): any {
|
||||
},
|
||||
active: {
|
||||
default: {
|
||||
...text(layer, "ui_sans", "active", { size: "sm" }),
|
||||
background: background(layer, "active"),
|
||||
...text(theme.lowest, "ui_sans", { size: "sm" }),
|
||||
background: background(theme.lowest),
|
||||
},
|
||||
clicked: {
|
||||
background: background(layer, "pressed"),
|
||||
@@ -306,13 +307,10 @@ export default function contacts_panel(): any {
|
||||
},
|
||||
},
|
||||
contact_button_spacing: NAME_MARGIN,
|
||||
contact_button: interactive({
|
||||
base: { ...contact_button },
|
||||
state: {
|
||||
hovered: {
|
||||
background: background(layer, "hovered"),
|
||||
},
|
||||
},
|
||||
contact_button: icon_button({
|
||||
variant: "ghost",
|
||||
color: "variant",
|
||||
size: "sm",
|
||||
}),
|
||||
disabled_button: {
|
||||
...contact_button,
|
||||
@@ -364,7 +362,7 @@ export default function contacts_panel(): any {
|
||||
}),
|
||||
state: {
|
||||
active: {
|
||||
default: { background: background(layer, "active") },
|
||||
default: { background: background(theme.lowest) },
|
||||
},
|
||||
},
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user