-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
35 changed files
with
2,235 additions
and
7 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
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
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
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,87 @@ | ||
<script lang="ts"> | ||
import _ from 'lodash' | ||
import Regl from 'regl' | ||
import REGL from 'regl' | ||
import { | ||
computed, | ||
defineComponent, | ||
onMounted, | ||
onUnmounted, | ||
PropType, | ||
ref, | ||
watch, | ||
} from 'vue' | ||
import {REGL_QUAD_DEFAULT} from './util' | ||
interface UniformsProp { | ||
[name: string]: number[] | string | ||
} | ||
export default defineComponent({ | ||
name: 'GlslCnavas', | ||
props: { | ||
fragmentString: { | ||
type: String, | ||
default: ` | ||
precision mediump float; | ||
varying vec2 uv; | ||
void main() { gl_FragColor = vec4(uv, 0, 1); }`, | ||
}, | ||
uniforms: { | ||
type: Object as PropType<UniformsProp>, | ||
default: () => ({}), | ||
}, | ||
}, | ||
setup(props) { | ||
const canvas = ref<null | HTMLCanvasElement>(null) | ||
const regl = ref<null | REGL.Regl>(null) | ||
onMounted(() => { | ||
if (!canvas.value) { | ||
return | ||
} | ||
regl.value = Regl({ | ||
attributes: { | ||
depth: false, | ||
premultipliedAlpha: false, | ||
}, | ||
canvas: canvas.value, | ||
}) | ||
}) | ||
onUnmounted(() => regl.value?.destroy()) | ||
const uniformKeys = ref(_.keys(props.uniforms)) | ||
const drawCommand = computed(() => { | ||
if (!regl.value) return null | ||
const prop = regl.value.prop as any | ||
const uniforms = _.fromPairs(uniformKeys.value.map(k => [k, prop(k)])) | ||
return regl.value({ | ||
...REGL_QUAD_DEFAULT, | ||
frag: props.fragmentString, | ||
uniforms, | ||
}) | ||
}) | ||
watch( | ||
() => [regl.value, drawCommand.value, props.uniforms], | ||
() => { | ||
drawCommand.value && drawCommand.value(props.uniforms) | ||
} | ||
) | ||
return {canvas} | ||
}, | ||
}) | ||
</script> | ||
|
||
<template> | ||
<canvas ref="canvas" /> | ||
</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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<template> | ||
<button class="InputButton">{{ label }}</button> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
interface Props { | ||
label: string | ||
} | ||
withDefaults(defineProps<Props>(), {label: ''}) | ||
</script> | ||
|
||
<style lang="stylus" scoped> | ||
@import './common.styl' | ||
.InputButton | ||
padding 0 1em | ||
height var(--tq-input-height) | ||
border-radius var(--tq-input-border-radius) | ||
background var(--tq-color-primary-container) | ||
color var(--md-sys-color-on-primary-container) | ||
font-size inherit | ||
hover-transition(background, collor) | ||
&:hover, &:focus-visible | ||
color var(--tq-color-on-primary) | ||
background var(--tq-color-primary) | ||
</style> |
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,149 @@ | ||
<template> | ||
<div class="InputColorPicker"> | ||
<div class="InputColorPicker__wrapper"> | ||
<div | ||
v-for="({name, mode}, i) in pickerData" | ||
:key="i" | ||
class="InputColorPicker__picker" | ||
> | ||
<component | ||
:is="name" | ||
:rgba="rgba" | ||
:mode="mode" | ||
@partialUpdate="onPartialUpdate" | ||
/> | ||
</div> | ||
<Button | ||
v-if="isEyeDropperSupported" | ||
class="InputColorPicker__eyeDropper" | ||
label="Pick Color" | ||
@click="pickColor" | ||
/> | ||
</div> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import {computed, defineComponent, shallowRef, watch} from 'vue' | ||
import InputButton from '../InputButton.vue' | ||
import SliderAlpha from './SliderAlpha.vue' | ||
import SliderHSV from './SliderHSV.vue' | ||
import SliderHSVRadial from './SliderHSVRadial.vue' | ||
import SliderRGB from './SliderRGB.vue' | ||
import {color2rgba, RGBA, rgba2color} from './use-hsv' | ||
export default defineComponent({ | ||
name: 'InputColorPicker', | ||
components: { | ||
SliderHSV, | ||
SliderHSVRadial, | ||
SliderRGB, | ||
SliderAlpha, | ||
InputButton, | ||
}, | ||
props: { | ||
modelValue: { | ||
type: String, | ||
required: true, | ||
}, | ||
colorSpace: { | ||
type: String, | ||
default: 'rgba', | ||
}, | ||
pickers: { | ||
type: String, | ||
default: 'svh,a', | ||
}, | ||
}, | ||
emit: ['update:modelValue'], | ||
setup(props, context) { | ||
const rgba = shallowRef<RGBA>({r: 0, g: 0, b: 0, a: 0}) | ||
const hasAlpha = computed(() => props.colorSpace.endsWith('a')) | ||
const colorString = computed(() => rgba2color(rgba.value, hasAlpha.value)) | ||
watch( | ||
() => props.modelValue, | ||
() => { | ||
if (props.modelValue !== colorString.value) { | ||
const _rgba = color2rgba(props.modelValue, hasAlpha.value) | ||
if (!_rgba) { | ||
return | ||
} | ||
rgba.value = _rgba | ||
} | ||
}, | ||
{immediate: true} | ||
) | ||
function onPartialUpdate(newPartialDict: Partial<RGBA>) { | ||
const newDict = {...rgba.value, ...newPartialDict} | ||
rgba.value = newDict | ||
const newValue = rgba2color(newDict, hasAlpha.value) | ||
context.emit('update:modelValue', newValue) | ||
} | ||
const pickerData = computed(() => | ||
props.pickers | ||
.split(',') | ||
.map(picker => { | ||
if (/^[hsv]{3}$/.test(picker)) { | ||
return {name: 'SliderHSV', mode: picker} | ||
} else if (['r', 'g', 'b'].includes(picker)) { | ||
return {name: 'SliderRGB', mode: picker} | ||
} else if (picker === 'hsvr') { | ||
return {name: 'SliderHSVRadial'} | ||
} else if (picker === 'a') { | ||
return {name: 'SliderAlpha'} | ||
} | ||
return null | ||
}) | ||
.filter(v => v !== null) | ||
) | ||
// EyeDropper | ||
const isEyeDropperSupported = 'EyeDropper' in window | ||
async function pickColor() { | ||
const eyeDropper = new (window as any)['EyeDropper']() | ||
const newValue: string = (await eyeDropper.open()).sRGBHex | ||
context.emit('update:modelValue', newValue) | ||
} | ||
return { | ||
rgba, | ||
onPartialUpdate, | ||
pickerData, | ||
isEyeDropperSupported, | ||
pickColor, | ||
} | ||
}, | ||
}) | ||
</script> | ||
|
||
<style lang="stylus"> | ||
@import './common.styl' | ||
.InputColorPicker | ||
padding 0 | ||
&__wrapper | ||
position relative | ||
&__picker | ||
margin-bottom $picker-gap | ||
&:last-child | ||
margin-bottom 0 | ||
&__eyeDropper | ||
display block | ||
margin 0 auto | ||
</style> |
Oops, something went wrong.