2023-03-25 20:30:32 +00:00
const colors = [ '#ff0000' , '#00ff00' , '#0000ff' ] ;
let colorsChanged = true ;
2023-03-25 23:29:03 +00:00
// Copied from https://github.com/revoltchat/backend/blob/master/crates/quark/src/util/regex.rs
const RE _COLOUR = "^(?:[a-z ]+|var\(--[a-z\d-]+\)|rgba?\([\d, ]+\)|#[a-f0-9]+|(repeating-)?(linear|conic|radial)-gradient\(([a-z ]+|var\(--[a-z\d-]+\)|rgba?\([\d, ]+\)|#[a-f0-9]+|\d+deg)([ ]+(\d{1,3}%|0))?(,[ ]*([a-z ]+|var\(--[a-z\d-]+\)|rgba?\([\d, ]+\)|#[a-f0-9]+)([ ]+(\d{1,3}%|0))?)+\))$" ;
2023-03-25 20:30:32 +00:00
function updateUi ( ) {
const radios = document . getElementsByName ( 'gradient_type' ) ;
document . getElementById ( 'config_linear' ) . style . display = radios [ 0 ] . checked ? 'unset' : 'none' ;
document . getElementById ( 'config_radial' ) . style . display = radios [ 1 ] . checked ? 'unset' : 'none' ;
document . getElementById ( 'config_conic' ) . style . display = radios [ 2 ] . checked ? 'unset' : 'none' ;
if ( colorsChanged ) {
colorsChanged = false ;
const list = document . getElementById ( 'color-list' ) ;
while ( list . lastChild ) list . lastChild . remove ( ) ;
for ( let i in colors ) {
i = Number ( i ) ;
const color = colors [ i ] ;
let colorInput = document . createElement ( 'input' ) ;
colorInput . type = 'color' ;
colorInput . value = color ;
2023-03-25 21:45:42 +00:00
colorInput . onchange = ( e ) => changeColor ( i , e . currentTarget . value ) ;
2023-03-25 20:30:32 +00:00
list . appendChild ( colorInput ) ;
let button1 = document . createElement ( 'button' ) ;
button1 . innerText = '^' ;
button1 . disabled = i == 0 ;
button1 . onclick = ( ) => moveUp ( i ) ;
list . appendChild ( button1 ) ;
let button2 = document . createElement ( 'button' ) ;
button2 . innerText = 'v' ;
button2 . disabled = i == colors . length - 1 ;
button2 . onclick = ( ) => moveDown ( i ) ;
list . appendChild ( button2 ) ;
let button3 = document . createElement ( 'button' ) ;
button3 . innerText = 'Delete' ;
button3 . onclick = ( ) => removeColor ( i ) ;
list . appendChild ( button3 ) ;
2023-03-25 22:05:43 +00:00
// Dynamic distance scaling between color nodes, too much effort to implement rn
/ *
let sliderValue = document . createElement ( 'span' ) ;
sliderValue . innerText = '50%' ;
let slider = document . createElement ( 'input' ) ;
slider . type = 'range' ;
slider . min = 0 ;
slider . max = 100 ;
slider . value = 50 ;
slider . autocomplete = 'off' ;
slider . oninput = ( e ) => sliderValue . innerText = ` ${ e . currentTarget . value } % ` ;
list . appendChild ( slider ) ;
list . appendChild ( sliderValue ) ;
* /
2023-03-25 20:30:32 +00:00
list . appendChild ( document . createElement ( 'br' ) ) ;
}
}
2023-03-25 21:45:42 +00:00
document . getElementById ( 'custom_pos_inputs' ) . hidden = ! document . getElementById ( 'conic_custom_position' ) . checked ;
const css = generateCss ( ) ;
if ( css ) {
document . getElementById ( 'preview' ) . style . backgroundImage = css ;
document . getElementById ( 'output' ) . value = css ;
2023-03-25 22:05:43 +00:00
if ( css . length > 128 ) {
document . getElementById ( 'output_error' ) . innerText = ` Warning: The generated CSS is ${ css . length } characters long, which exceeds Revolt's limit of 128 characters. You will not be able to use this gradient on Revolt. ` ;
}
2023-03-25 23:29:03 +00:00
// for some reason this won't work
//else if (!css.match(new RegExp(RE_COLOUR, 'i'))) {
// document.getElementById('output_error').innerText = `Warning: The generated CSS doesn't match against the validation regex. This means that Revolt will not accept one of the set parameters.`;
//}
2023-03-25 22:05:43 +00:00
else document . getElementById ( 'output_error' ) . innerText = '' ;
2023-03-25 21:45:42 +00:00
}
2023-03-25 20:30:32 +00:00
}
function removeColor ( index ) {
colorsChanged = true ;
colors . splice ( index , 1 ) ;
updateUi ( ) ;
}
2023-03-25 21:45:42 +00:00
function appendColor ( ) {
colorsChanged = true ;
colors . push ( '#ffbbaa' ) ;
updateUi ( ) ;
}
function changeColor ( index , color ) {
colorsChanged = true ;
colors [ index ] = color ;
updateUi ( ) ;
}
2023-03-25 20:30:32 +00:00
function moveUp ( index ) {
colorsChanged = true ;
[ colors [ index ] , colors [ index - 1 ] ] = [ colors [ index - 1 ] , colors [ index ] ] ;
updateUi ( ) ;
}
function moveDown ( index ) {
colorsChanged = true ;
[ colors [ index ] , colors [ index + 1 ] ] = [ colors [ index + 1 ] , colors [ index ] ] ;
updateUi ( ) ;
}
2023-03-25 22:05:43 +00:00
/ * *
* @ returns { string }
* /
function generateColorList ( ) {
const noTransition = document . getElementById ( 'no_transition' ) . checked ;
if ( noTransition ) {
const distance = 100 / colors . length ;
const colorCodes = [ ] ;
for ( let i = 0 ; i < colors . length ; i ++ ) {
colorCodes . push ( i == 0 ? colors [ i ] : ` ${ colors [ i ] } ${ Math . round ( distance * i * 10 ) / 10 } % ` ) ;
colorCodes . push ( i == colors . length - 1 ? colors [ i ] : ` ${ colors [ i ] } ${ Math . round ( distance * ( i + 1 ) * 10 ) / 10 } % ` ) ;
}
return colorCodes . join ( ',' ) ;
}
else return colors . join ( ',' ) ;
}
2023-03-25 20:30:32 +00:00
/ * *
* @ returns { string }
* /
function generateCss ( ) {
const radios = document . getElementsByName ( 'gradient_type' ) ;
if ( radios [ 0 ] . checked ) return generateCssLinear ( ) ;
if ( radios [ 1 ] . checked ) return generateCssRadial ( ) ;
if ( radios [ 2 ] . checked ) return generateCssConic ( ) ;
2023-03-25 21:45:42 +00:00
return '' ;
2023-03-25 20:30:32 +00:00
}
/ * *
* @ returns { string }
* /
function generateCssLinear ( ) {
2023-03-25 21:45:42 +00:00
const rotation = document . getElementById ( 'rotation' ) . value ;
2023-03-25 22:05:43 +00:00
return ` linear-gradient( ${ rotation } deg, ${ generateColorList ( ) } ) ` ;
2023-03-25 20:30:32 +00:00
}
/ * *
* @ returns { string }
* /
function generateCssRadial ( ) {
2023-03-25 21:45:42 +00:00
let radios = document . getElementsByName ( 'radial_mode' ) ;
const mode = Array . from ( radios ) . find ( r => r . checked ) . value ? ? 'circle' ;
radios = document . getElementsByName ( 'radial_pos' ) ;
const pos = Array . from ( radios ) . find ( r => r . checked ) . value ? ? 'center' ;
2023-03-25 22:05:43 +00:00
return ` radial-gradient( ${ mode } at ${ pos } , ${ generateColorList ( ) } ) ` ;
2023-03-25 20:30:32 +00:00
}
/ * *
* @ returns { string }
* /
function generateCssConic ( ) {
2023-03-25 21:45:42 +00:00
const rotation = document . getElementById ( 'rotation_conic' ) . value ;
const showCustomPos = document . getElementById ( 'conic_custom_position' ) . checked ;
const x = document . getElementById ( 'conic_x' ) . value ;
const y = document . getElementById ( 'conic_y' ) . value ;
2023-03-25 23:29:03 +00:00
// have to remove all of this because Revolt doesn't allow it, smh
// from ${rotation}deg${showCustomPos ? ` at ${x}% ${y}%` : ''},
return ` conic-gradient( ${ generateColorList ( ) } ) ` ;
2023-03-25 20:30:32 +00:00
}
// Initial update
2023-03-25 23:29:03 +00:00
window . onload = ( ) => {
2023-03-25 20:30:32 +00:00
updateUi ( ) ;
2023-03-25 23:29:03 +00:00
} ;