Conic Gradient CSS
<div></div>
<style>
div {
width: 200px;
height: 200px;
background: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);
}
</style>
CSS conic gradient. I got this snippet from CSS Tricks article… 😀
<div></div>
<style>
div {
width: 200px;
height: 200px;
background: conic-gradient(red, yellow, lime, aqua, blue, magenta, red);
}
</style>
CSS conic gradient. I got this snippet from CSS Tricks article… 😀
document.addEventListener('touchmove', e => e.preventDefault(), {
passive: false
});
document.body.innerHTML += `
<style>
* {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
body {
background: #333;
}
.select-box {
border: 1px solid white;
outline: 1px solid black;
}
.swatch {
border: none;
outline: none;
}
</style>
`;
const col = document.body.appendChild(document.createElement('div'));
Object.assign(col.style, {
position: 'absolute',
left: 0,
top: 0,
width: '100%',
height: '200px',
background:
`linear-gradient(0, black 0%, transparent 50%, transparent 50%, white 100%),
linear-gradient(90deg, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000)`
});
const swatches = document.body.appendChild(document.createElement('div'));
Object.assign(swatches.style, {
position: 'absolute',
top: '200px',
left: 0,
width: '100%'
});
function box(x, y, cls = 'select-box', parent = document.body) {
const box = parent.appendChild(document.createElement`div`);
box.classList.add(cls);
Object.assign(box.style, {
position: 'absolute',
left: `${x}%`,
top: `${y}px`,
width: '40px',
height: '40px',
background: 'none',
transform: 'translate(-50%, -50%)',
cursor: 'pointer',
color: 'white'
});
return box;
}
function touch(e) {
let x = e.clientX;
let y = e.clientY;
if (e.touches != null && e.touches.length > 0) {
x = e.touches[0].clientX;
y = e.touches[0].clientY;
}
return { x, y };
}
document.addEventListener('touchstart', onDown);
document.addEventListener('touchmove', onMove);
document.addEventListener('touchend', onUp);
document.addEventListener('mousedown', onDown);
document.addEventListener('mousemove', onMove);
document.addEventListener('mouseup', onUp);
let down = false;
let currBox;
let currSwatch;
let swatchHeight = 30;
let id = 0;
function toHSL(x, y) {
let deg = x * 360;
return `hsl(${deg}deg, 100%, ${100 - y / 2}%)`;
}
function onDown(e) {
let { x, y } = touch(e);
down = true;
let hPercent = x / innerWidth;
let color = toHSL(hPercent, y);
if (e.target.classList.contains('swatch')) {
e.target.style.outline = '2px solid red';
e.target.style.zIndex = 999;
down = false;
setTimeout(() => {
if (confirm('Would you like to remove this swatch?')) {
currBox = document.querySelector(
`.select-box[data-id="${e.target.dataset.id}"]`
);
if (currBox != null) {
currBox.parentNode.removeChild(currBox);
e.target.parentNode.removeChild(e.target);
}
} else {
e.target.style.outline = null;
e.target.style.zIndex = null;
}
}, 250);
} else if (e.target.classList.contains('select-box')) {
currBox = e.target;
c = document.querySelector(`.swatch[data-id="${currBox.dataset.id}"]`);
} else {
currBox = box(hPercent * 100, y);
currBox.dataset.id = id++;
currSwatch = box(0, 0, 'swatch', swatches);
currSwatch.dataset.id = currBox.dataset.id;
Object.assign(currSwatch.style, {
width: '100%',
position: 'relative',
height: `${swatchHeight}px`,
transform: 'none',
background: color
});
}
}
function onMove(e) {
if (down) {
let { x, y } = touch(e);
let hPercent = x / innerWidth;
let color = toHSL(hPercent, y);
Object.assign(currBox.style, {
left: `${hPercent * 100}%`,
top: `${y}px`
});
currSwatch.style.background = color;
}
}
function onUp(e) {
down = false;
currBox = null;
}
Click anywhere on the spectrum to add a color… color boxes can be dragged, color swatches can be deleted by clicking on them…
Just something that popped into my head awhile back so figured I’d do a speed-coded prototype. I’d like to revisit this and add more to it.
function box(x, y, col = 'red', cursor){
const box = document.body.appendChild(
document.createElement`div`
)
box.classList.add(col + '-box')
Object.assign(box.style, {
position: 'absolute',
left: `${x}%`,
top: `${y}%`,
width: '30px',
height: '30px',
background: col,
cursor: cursor || 'pointer',
color: 'white'
})
return box
}
const NUM = 10;
for (let i = 0; i < NUM; i++)
box(
Math.random() * 100,
Math.random() * 100)
let destX = destY = x = y = 0;
const blue = box(destX, destY, 'blue', 'default')
const info = box(0, 30, 'gray')
info.innerHTML = 'click the red boxes'
Object.assign(info.style, {
width: '100%',
padding: '.5em',
fontFamily: 'sans-serif'
})
document.addEventListener('click', e => {
const curr = e.target
if (curr.classList.contains('red-box')) {
destX = curr.offsetLeft
destY = curr.offsetTop
curr.style.background = 'black'
setTimeout(() => curr.style.background = 'red', 700)
if (info.parentNode != null) {
info.parentNode.removeChild(info);
}
}
})
function loop() {
x += (destX - x) / 12
y += (destY - y) / 12
blue.style.transform = `translate3d(${x}px, ${y}px, 0)`
requestAnimationFrame(loop)
}
loop()
Click a red box, watch the blue box animate…
const tmpl = `
main
h1 Welcome
hr
nav
button one
button two
button three
hr
p this is a test
p this is another test
textarea hello
ul
li alpha
li beta
li zeta
ul
li organize
li things
li and stuff
hr
footer 2022
`
let htm = parse(tmpl);
document.body.innerHTML += htm
console.log(htm)
function isTag(tag) {
return !/Unknown/.test(document.createElement(tag) + '')
}
function parse(input) {
let lines = input.split(/\n/)
let html = []
let closeTags = []
let lastIndent = 0;
for (let i = 1; i < lines.length; i++) {
let indent = 0;
let tag = '';
let content = ''
let line = lines[i]
let mode = 'start';
for (let j = 0; j < line.length; j++) {
const char = line[j]
if (char == ' ' && mode === 'start') {
indent++;
} else if (char != ' ' && mode != 'content') {
mode = 'tag'
tag += char
} else {
mode = 'content'
content += char;
}
}
if (indent <= lastIndent && closeTags.length > 0) {
let back = lastIndent
while(back >= indent) {
html.push(closeTags.pop())
back -= 2
}
}
if (tag.length > 0) {
let xtra = ''
let origTag = tag;
if (!isTag(tag)) {
tag = 'div'
xtra = ` class="${origTag}" `
}
closeTags.push(`</${tag}>`)
html.push(`<${tag + xtra}>`)
if (content.length > 0) html.push(content)
}
lastIndent = indent;
}
return [...html, ...closeTags.reverse()].join('')
}
Parse a minimalistic html template inspired by the likes of jade, haml, pug etc… This is very speed-coded. I may revisit the same thing with a bit more of an elegant approach in the future.
const isTag = tag => {
return !/Unknown/.test(document.createElement(tag) + '')
}
console.log('section:', isTag('section'))
console.log('div:', isTag('div'))
console.log('nav:', isTag('nav'))
console.log('banana:', isTag('banana'))
Check if a tagName
is a valid html element.
When casting a dom node to a string, you’ll get a class name like this:
document.createElement('div') + ''
// '[object HTMLDivElement]'
// you can cast to a string with `toString` if
// you want things to be more readable
document.createElement('section').toString()
// '[object HTMLElement]'
document.createElement('input') + ''
// '[object HTMLInputElement]'
When you try to create something with an unknown tagName
you’ll end up with:
document.createElement('banana') + ''
// '[object HTMLUnknownElement]'
So, testing for the presence of the string Unknown
is an easy way to check if a tagName
is valid in a given browser. This is the perfect kind of thing to memoize:
const tags = {}
const isTag = tag => {
if (tags[tag] != null) {
// already calculated
console.log('loking up: ', tag, tags[tag]);
return tags[tag]
}
const result = !/Unknown/.test(document.createElement(tag) + '')
tags[tag] = result
return result
}
console.log('calculator', isTag('calculator'))
console.log('calculator', isTag('calculator'))
console.log('strong', isTag('strong'))
console.log('strong', isTag('strong'))