import { isMobile } from "@thi.ng/checks/is-mobile" ; import { div } from "@thi.ng/hiccup-html/blocks" ; import { button , inputFile , label } from "@thi.ng/hiccup-html/forms" ; import { span } from "@thi.ng/hiccup-html/inline" ; import { h1 } from "@thi.ng/hiccup-html/sections" ; import { staticRadio } from "@thi.ng/rdom-components/radio" ; import { $compile } from "@thi.ng/rdom/compile" ; import { $inputFile , $inputTrigger } from "@thi.ng/rdom/event" ; import { $replace } from "@thi.ng/rdom/replace" ; import { reactive , stream } from "@thi.ng/rstream/stream" ; import { sync } from "@thi.ng/rstream/sync" ; import { float } from "@thi.ng/strings/float" ; import { map } from "@thi.ng/transducers/map" ; import type { SortMode } from "./api" ; import { cssPalette } from "./components/css" ; import { PixelCanvas } from "./components/pixelcanvas" ; import { slider } from "./components/slider" ; import { downloadACT } from "./palette" ; import { postProcess , processImage } from "./process" ; const file = stream < File > ( ) ; const image = stream < HTMLImageElement > ( ) ; const num = reactive ( 8 ) ; const minChroma = reactive ( 10 ) ; const minArea = reactive ( 0.5 ) ; const sortMode = reactive < SortMode > ( "hue" ) ; const update = reactive ( true ) ; const size = ( isMobile ( ) ? 0.5 : 1 ) * 25 ; const main = sync ( { src : { image , num , minChroma , _ : update , } , xform : map ( ( params ) => processImage ( params . image , params . num , params . minChroma * 0.01 ) ) , } ) ; const result = sync ( { src : { main , minArea , sortMode } , xform : map ( ( { main : { buf , colors } , minArea , sortMode } ) => ( { buf , ... postProcess ( colors , minArea , sortMode ) , } ) ) , } ) ; file . subscribe ( { next ( file ) { const url = URL . createObjectURL ( file ) ; const img = new Image ( ) ; img . onload = ( ) => { image . next ( img ) ; URL . revokeObjectURL ( url ) ; } ; img . src = url ; } , } ) ; $compile ( div ( ".lh-copy.f6.f5-ns" , { } , h1 ( ".ma0" , { } , "Dominant colors" ) , inputFile ( ".db.mv3" , { accept : [ "image/jpg" , "image/png" , "image/gif" , "image/webp" ] , multiple : false , onchange : $inputFile ( file ) , } ) , slider ( num , "max. colors" , { min : 2 , max : 16 , step : 1 , } ) , slider ( minChroma , "min. chroma" , { min : 0 , max : 100 , step : 5 , } ) , slider ( minArea , "min. area" , { min : 0 , max : 25 , step : 0.5 , } ) , div ( ".mv3" , { } , "Sort colors by:" ) , staticRadio < SortMode > ( [ "hue" , "luma" , "area" ] , < any > sortMode , { label : ( id , radio ) => label ( ".db" , { for : id } , span ( ".dib.w-50.w-25-ns" , { } , id ) , radio ) , } ) , button ( ".db.mv3" , { onclick : $inputTrigger ( update ) } , "update" ) , $replace ( result . map ( ( res ) => div ( { } , cssPalette ( res . colors ) , new PixelCanvas ( res . buf ) , div ( { } , `hue range: ${ res . hues . map ( float ( 3 ) ) . join ( " .. " ) }` ) , button ( ".db.mv3" , { onclick : ( ) => downloadACT ( res . colors . map ( ( c ) => c . col ) ) , } , "download .act palette" ) ) ) ) ) ) . mount ( document . getElementById ( "app" ) ! ) ;