-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2011 from cardstack/cs-7513-create-colorpalette-b…
…oxel-ui-component Add Boxel UI components: ColorPicker, ColorPalette
- Loading branch information
Showing
6 changed files
with
338 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
148 changes: 148 additions & 0 deletions
148
packages/boxel-ui/addon/src/components/color-palette/index.gts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import { eq } from '@cardstack/boxel-ui/helpers'; | ||
import { concat, fn } from '@ember/helper'; | ||
import { on } from '@ember/modifier'; | ||
import { htmlSafe } from '@ember/template'; | ||
import Component from '@glimmer/component'; | ||
|
||
import ColorPicker from '../color-picker/index.gts'; | ||
|
||
interface Signature { | ||
Args: { | ||
color: string; | ||
onChange: (color: string) => void; | ||
}; | ||
Element: HTMLDivElement; | ||
} | ||
|
||
const DEFAULT_PALETTE_COLORS = [ | ||
// Row 1 | ||
'#000000', | ||
'#777777', | ||
'#FA2200', | ||
'#FA7F01', | ||
'#FBEB06', | ||
'#1EDF67', | ||
'#39B1FF', | ||
'#9D00FF', | ||
// Row 2 | ||
'#A6A6A6', | ||
'#CFCFCF', | ||
'#FCA6A7', | ||
'#FCD2A7', | ||
'#FCF8A6', | ||
'#A6F4CA', | ||
'#A7E4FF', | ||
'#DEA6FF', | ||
]; | ||
|
||
export default class ColorPalette extends Component<Signature> { | ||
colors = DEFAULT_PALETTE_COLORS; | ||
|
||
<template> | ||
<div class='color-palette-container' ...attributes> | ||
<div class='color-palette'> | ||
{{#each this.colors as |color|}} | ||
<button | ||
type='button' | ||
class='swatch {{if (eq color @color) "selected"}}' | ||
style={{htmlSafe (concat '--swatch-color: ' color)}} | ||
{{on 'click' (fn @onChange color)}} | ||
title={{color}} | ||
/> | ||
{{/each}} | ||
</div> | ||
|
||
<label class='color-picker-container'> | ||
<span class='custom-color-label'>Custom Color</span> | ||
<ColorPicker @color={{@color}} @onChange={{@onChange}} /> | ||
</label> | ||
</div> | ||
|
||
<style scoped> | ||
.custom-color-label { | ||
margin-left: var(--boxel-sp-sm); | ||
color: var(--boxel-450); | ||
} | ||
.color-palette-container { | ||
display: flex; | ||
gap: var(--boxel-sp); | ||
align-items: flex-start; | ||
flex-direction: column; | ||
} | ||
.color-picker-container { | ||
--swatch-size: 1.8rem; | ||
border: 1px solid var(--boxel-border-color); | ||
border-radius: var(--boxel-border-radius); | ||
padding: var(--boxel-sp-sm); | ||
background: none; | ||
display: flex; | ||
align-items: center; | ||
cursor: pointer; | ||
flex-direction: row-reverse; | ||
width: 18rem; | ||
justify-content: flex-end; | ||
} | ||
.color-picker-container:hover { | ||
background-color: var(--boxel-light-100); | ||
color: var(--boxel-600); | ||
} | ||
.color-palette { | ||
--swatch-size: 1.8rem; | ||
display: grid; | ||
grid-template-columns: repeat(8, var(--swatch-size)); | ||
gap: var(--boxel-sp-xs); | ||
} | ||
.swatch { | ||
width: var(--swatch-size); | ||
height: var(--swatch-size); | ||
border: 1px solid transparent; | ||
border-radius: 50%; | ||
padding: 2px; | ||
cursor: pointer; | ||
transition: transform 0.1s ease; | ||
background-color: transparent; | ||
} | ||
.swatch::before { | ||
content: ''; | ||
display: block; | ||
width: 100%; | ||
height: 100%; | ||
border-radius: 50%; | ||
background-color: var(--swatch-color); | ||
} | ||
.swatch:hover:not(:disabled) { | ||
transform: scale(1.1); | ||
} | ||
.swatch.selected { | ||
background-color: white; | ||
border-color: var(--boxel-800); | ||
} | ||
.color-input { | ||
width: 1.35rem; | ||
height: 1.35rem; | ||
padding: 0; | ||
border: none; | ||
cursor: pointer; | ||
border-radius: 50%; | ||
} | ||
.color-input::-webkit-color-swatch-wrapper { | ||
padding: 0; | ||
} | ||
.color-input::-webkit-color-swatch { | ||
border: 1px solid transparent; | ||
border-radius: 50%; | ||
} | ||
</style> | ||
</template> | ||
} |
45 changes: 45 additions & 0 deletions
45
packages/boxel-ui/addon/src/components/color-palette/usage.gts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { fn } from '@ember/helper'; | ||
import Component from '@glimmer/component'; | ||
import { tracked } from '@glimmer/tracking'; | ||
import FreestyleUsage from 'ember-freestyle/components/freestyle/usage'; | ||
|
||
import ColorPalette from './index.gts'; | ||
|
||
export default class ColorPaletteUsage extends Component { | ||
@tracked color = '#000000'; | ||
|
||
private handleColorChange = (newColor: string) => { | ||
this.color = newColor; | ||
}; | ||
|
||
<template> | ||
<FreestyleUsage | ||
@name='ColorPalette' | ||
@description='A color palette component that provides a set of predefined colors and a custom color picker.' | ||
> | ||
<:example> | ||
<ColorPalette | ||
@color={{this.color}} | ||
@onChange={{this.handleColorChange}} | ||
/> | ||
</:example> | ||
|
||
<:api as |Args|> | ||
<Args.String | ||
@name='color' | ||
@optional={{false}} | ||
@description='Currently selected color in hex format.' | ||
@value={{this.color}} | ||
@onInput={{fn (mut this.color)}} | ||
@defaultValue='#000000' | ||
/> | ||
<Args.Action | ||
@name='onChange' | ||
@description='Callback function that receives the newly selected color value.' | ||
@value={{this.handleColorChange}} | ||
@onInput={{fn (mut this.handleColorChange)}} | ||
/> | ||
</:api> | ||
</FreestyleUsage> | ||
</template> | ||
} |
74 changes: 74 additions & 0 deletions
74
packages/boxel-ui/addon/src/components/color-picker/index.gts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { on } from '@ember/modifier'; | ||
import Component from '@glimmer/component'; | ||
|
||
interface Signature { | ||
Args: { | ||
color: string; | ||
disabled?: boolean; | ||
onChange: (color: string) => void; | ||
showHexString?: boolean; | ||
}; | ||
Element: HTMLDivElement; | ||
} | ||
|
||
export default class ColorPicker extends Component<Signature> { | ||
private handleColorChange = (event: Event) => { | ||
let input = event.target as HTMLInputElement; | ||
this.args.onChange(input.value); | ||
}; | ||
|
||
<template> | ||
<div class='color-picker' ...attributes> | ||
<input | ||
type='color' | ||
value={{@color}} | ||
class='input' | ||
disabled={{@disabled}} | ||
aria-label='Choose color' | ||
{{on 'input' this.handleColorChange}} | ||
/> | ||
{{#if @showHexString}} | ||
<span class='hex-value'>{{@color}}</span> | ||
{{/if}} | ||
</div> | ||
|
||
<style scoped> | ||
.color-picker { | ||
--swatch-size: 1.4rem; | ||
display: inline-flex; | ||
align-items: center; | ||
gap: var(--boxel-sp-xs); | ||
} | ||
.input { | ||
width: var(--swatch-size); | ||
height: var(--swatch-size); | ||
padding: 0; | ||
border: none; | ||
cursor: pointer; | ||
background: transparent; | ||
border: 1px solid var(--boxel-200); | ||
border-radius: 50%; | ||
} | ||
.input:disabled { | ||
pointer-events: none; | ||
} | ||
.input::-webkit-color-swatch-wrapper { | ||
padding: 0; | ||
} | ||
.input::-webkit-color-swatch { | ||
border: 1px solid transparent; | ||
border-radius: 50%; | ||
} | ||
.hex-value { | ||
font: var(--boxel-font); | ||
color: var(--boxel-dark); | ||
text-transform: uppercase; | ||
} | ||
</style> | ||
</template> | ||
} |
63 changes: 63 additions & 0 deletions
63
packages/boxel-ui/addon/src/components/color-picker/usage.gts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { fn } from '@ember/helper'; | ||
import Component from '@glimmer/component'; | ||
import { tracked } from '@glimmer/tracking'; | ||
import FreestyleUsage from 'ember-freestyle/components/freestyle/usage'; | ||
|
||
import ColorPicker from './index.gts'; | ||
|
||
export default class ColorPickerUsage extends Component { | ||
@tracked color = '#ff0000'; | ||
@tracked disabled = false; | ||
@tracked showHexString = true; | ||
|
||
private onChange = (newColor: string) => { | ||
this.color = newColor; | ||
}; | ||
|
||
<template> | ||
<FreestyleUsage | ||
@name='ColorPicker' | ||
@description='A color picker that allows users to select a color from the color spectrum.' | ||
> | ||
<:example> | ||
<ColorPicker | ||
@color={{this.color}} | ||
@onChange={{this.onChange}} | ||
@showHexString={{this.showHexString}} | ||
@disabled={{this.disabled}} | ||
/> | ||
</:example> | ||
|
||
<:api as |Args|> | ||
<Args.String | ||
@name='color' | ||
@optional={{false}} | ||
@description='Hex color value.' | ||
@value={{this.color}} | ||
@onInput={{fn (mut this.color)}} | ||
@defaultValue='#ff0000' | ||
/> | ||
<Args.Action | ||
@name='onChange' | ||
@description='A callback function that is called when the color is changed.' | ||
@value={{this.onChange}} | ||
@onInput={{fn (mut this.onChange)}} | ||
/> | ||
<Args.Bool | ||
@name='disabled' | ||
@description='Whether the color picker is disabled.' | ||
@value={{this.disabled}} | ||
@onInput={{fn (mut this.disabled)}} | ||
@defaultValue={{false}} | ||
/> | ||
<Args.Bool | ||
@name='showHexString' | ||
@description='Whether to show the hex color value next to the picker.' | ||
@value={{this.showHexString}} | ||
@onInput={{fn (mut this.showHexString)}} | ||
@defaultValue={{true}} | ||
/> | ||
</:api> | ||
</FreestyleUsage> | ||
</template> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters