CSS for accent-color looks pretty dope! I think the lack of reliable CSS styling on native form elements- an that goes WAY back to Web 1.0 days - has created so much bogus work making fakey components.
Thursday, September 30, 2021
css accent-color
jira: origins
Finding by our scrummaster Eric Stolls about Jira, a tool we rely on heavily:
I stumbled across this today. Fun Fact about the origin of the name Jira - The product name is a truncation of Gojira, the Japanese word for Godzilla. The name originated from a nickname Atlassian developers used to refer to Bugzilla, which was previously used internally for bug-tracking.
Heh, Bugzilla was probably a play off of the old "Mozilla". My personal homepage is still called "Kirkzilla" as a play on that, back when it was just the html view of my Netscape bookmarks.
Friday, September 24, 2021
low-key but excellent improvement in iOS 15: calendar time editing
Many people praise the return of the "maginify loupe" in iOS 15, letting you more easily see what you're highlighting just a bit a part from your big ol', but I just stumbled on an improvement I'm even more grateful for: iOS 14's calendar entry edit field was a mess. Here it is on iOS14 (on my sweetie Melissa's phone):
This is what you see in edit mode and go to edit the start time - a text-ish input for the time appears underneath what you clicked to edit it. I always found that unintuitive, to have 2 fields meaning the same thing, one editable - especially since it was easy to conceptually mix up with the other field beneath it, the one for End time.
But earlier I had been denoted that on my iOS 15 phone, the old "tumblers" are back!
command line and text "fun"
In the so-old-school it’s new department, Command Line Interfaces are back - if they ever went away in the first place.
Firebear Studio has a list of 75 Best Node.js Command Line Apps & Utilities. You can build some awesome into your installer, like parallel dynamic spinner/progress bars, giant ASCII font banners, and slick pick list and options sets.
Asciiflow is another text-based cool tool… it’s a simple diagram editor, but it outputs ASCII (both extended and old-school)…
From
+----------------+
| |
| |
| Are we having |
| +-----------------+
| fun yet? | |
| | |
| | |
+----------------+ |
+-----------v-------+
| |
| |
| Well Why Not? |
| |
| |
| |
+-------------------+
Just make sure you are using a fixed-width font!
Tuesday, September 21, 2021
the size of boxes
Box-sizing is a minor annoyance for the modern web developer. In short, the question is “when setting the size of a DOM object, should you include the border and padding (“border-box” for the “box-sizing” property) or just the content “guts”? (“content-box”)
Historically, “content-box” was, and remains, the default, even though the consensus is “border-box” is easier to work with. So many sites will put something like
* {
box-sizing: border-box;
}
So your design system needs to account for that - testing in an environment where that has been set. (Empirically it seems Figma uses the older content-box model.)
- Right Click on an page and hit “Inspect”
- Under the Styles tab, hit the “+” button for “New Style Rule”
- Replace any class or element name with “*”
- Click to enter a new CSS property and enter `box-sizing: border-box;` resulting in something like
The MDN box-sizing page goes into more detail on the options you have for it.
Monday, September 20, 2021
css resize property
You know, CSS resize property is pretty cool, for oldtimers like me it's one of those things that would have been a HUGE pain to try and implement in the browser, but now we get it for free:
overflow: auto;
I guess that's in the same family as setting the contenteditable property on a div:
Obviously the DOM is so much more dynamic than it was back in the day, so it's great they added some hooks into that. (Editing the content of the div, basically making everything into a textarea... sort of weird but I guess not that much different than using developer/inspector tools
Thursday, September 16, 2021
phone goofiness and p5 instead of pixel editors
After getting a nice yellow silcone magsafe case for my iPhone, I decided to lean into the "duck" theme I stumbled on a few weeks ago:
The pixel duck was "inspired" by a google search for "pixel ducks", I then used browser-based tool piskel to roughly copy it (but using fewer colors.)
In making the actual background image, I was fumbling both with Acorn and Pixelmator... in both cases I ran into problems - either resizing without resampling, or just other basic functions. So I switched to a p5.js program. The "scale" trick to flip the image was a little wonky, and it took some finesse, but in general I like the control by doing design in code.
(Before this the theme was bumblebees, with an intermediate diver/blooper theme after I drowned buzzbuzz and had to get a new iPhone.)
Wednesday, September 15, 2021
WIP: permutation engine
A while back I showed a storybook component showing a 2D grid of combinations for props for a component library. V2 looked a little less cool but did a much better job of coming up with ALL permutations, not just the 1+1 combos you can show on a grid...
Here is the code:
import React from 'react'; import PropTestingProps from './permutation-testing.props'; import { PermutationTestingStyle } from './permutation-testing.style'; import { Button } from '../Button/button.component'; import { Checkbox } from '../Checkbox/checkbox.component'; import { Radio } from '../Radio/radio.component'; import styled from 'styled-components'; import { IconButton } from '../IconButton/icon-button.component'; import { Slider } from '../Slider/slider.component'; import { Tab } from '../Tab/tab.component'; import { TextArea } from '../TextArea/text-area.component'; import { TextField } from '../TextField/text-field.component'; import { Dropdown } from '../Dropdown/dropdown.component'; import { TypeAhead } from '../TypeAhead/type-ahead.component'; const Table = styled.table` th { font-weight: bold; } th, td { padding: 8px; font-family: sans-serif; vertical-align: middle; text-align: left; } margin-bottom: 16px; `; let count = 0; interface ComponentPropMatrixProps { label: string; permutations: string[]; render: React.FC; } const getAllSubsets = (theArray: string[]) => theArray.reduce( (subsets, value) => subsets.concat(subsets.map((set) => [value, ...set])), [[] as string[]], ); const ComponentPropSubsetsList = (props: ComponentPropMatrixProps) => { const { permutations, render, label } = props; // get all subsets, sort on length of subset, then keep original order of elemts const subsets = getAllSubsets(permutations) .sort((a, b) => a.length - b.length) .map((arr) => arr.sort((a, b) => permutations.indexOf(a) - permutations.indexOf(b)), ); return ( <> <h3>{label}</h3> <Table> <tbody> {subsets.map((subset) => { const subsetAsProps = {}; subset.forEach((x) => { subsetAsProps[x] = true; }); count++; console.log(count); return ( <tr key={JSON.stringify(subset)}> <td>{render({ componentProps: subsetAsProps, label })}</td> <th>{subset.join(' ')}</th> </tr> ); })} </tbody> </Table> </> ); }; // idle, checked, error, disabled const buttonVariations: React.ReactChild[] = []; for (const shape of ['rectangle', 'oval']) { for (const size of ['sm', 'lg']) { for (const ord of ['primary', 'secondary', 'tertiary']) { console.log(`${size} ${shape} ${ord}`); buttonVariations.push( <ComponentPropSubsetsList label={`Button ${size} ${shape} ${ord}`} permutations={['disabled']} render={({ componentProps, label }) => ( <Button size={size} shape={shape} buttonType={ord} {...componentProps} > Button </Button> )} />, ); } } } const checkboxVariations: React.ReactChild[] = []; for (const size of ['sm', 'md']) { checkboxVariations.push( <ComponentPropSubsetsList label={`Checkbox ${size}`} permutations={['checked', 'error', 'disabled']} render={({ componentProps, label }) => ( <Checkbox size={size} {...componentProps} label='Checkbox' /> )} />, ); } const iconButtonVariations: React.ReactChild[] = []; for (const shape of ['square', 'circle']) { for (const size of ['sm', 'md', 'lg']) { for (const ord of ['primary', 'secondary', 'tertiary']) { iconButtonVariations.push( <ComponentPropSubsetsList label={`Icon Button ${size} ${shape} ${ord}`} permutations={['disabled']} render={({ componentProps, label }) => ( <IconButton size={size} shape={shape} buttonType={ord} {...componentProps} > Icon Button </IconButton> )} />, ); } } } const radioVariations: React.ReactChild[] = []; for (const size of ['sm', 'md']) { radioVariations.push( <ComponentPropSubsetsList label={`Radio ${size}`} permutations={['checked', 'error', 'disabled']} render={({ componentProps, label }) => ( <Radio size={size} {...componentProps} id={`${JSON.stringify(componentProps)}_${size}`} label='Checkbox' /> )} />, ); } const sliderVariations: React.ReactChild[] = []; sliderVariations.push( <ComponentPropSubsetsList label={`Slider`} permutations={[]} render={({ componentProps, label }) => ( <Slider {...componentProps} label='Slider' /> )} />, ); const tabVariations: React.ReactChild[] = []; tabVariations.push( <ComponentPropSubsetsList label={`Tab`} permutations={[]} render={({ componentProps, label }) => <Tab {...componentProps}>Tab</Tab>} />, ); const textAreaVariations: React.ReactChild[] = []; textAreaVariations.push( <ComponentPropSubsetsList label={`Text Area`} permutations={['disabled', 'error']} render={({ componentProps, label }) => ( <TextArea {...componentProps}>Some Text</TextArea> )} />, ); const textFieldVariations: React.ReactChild[] = []; textFieldVariations.push( <ComponentPropSubsetsList label={`Text Field`} permutations={['disabled', 'error']} render={({ componentProps, label }) => ( <TextField value='Some Text' {...componentProps}></TextField> )} />, ); const dropDownVariations: React.ReactChild[] = []; dropDownVariations.push( <ComponentPropSubsetsList label={`Dropdown`} permutations={['disabled', 'error']} render={({ componentProps, label }) => ( <Dropdown value='Some Text' {...componentProps}></Dropdown> )} />, ); const typeAheadVariations: React.ReactChild[] = []; typeAheadVariations.push( <ComponentPropSubsetsList label={`Type Ahead`} permutations={['disabled', 'error']} render={({ componentProps, label }) => ( <TypeAhead value='Some Text' {...componentProps}></TypeAhead> )} />, ); export const PermutationTesting = (props: PropTestingProps) => { return ( <PermutationTestingStyle> {buttonVariations} {checkboxVariations} {iconButtonVariations} {radioVariations} {sliderVariations} {tabVariations} {textAreaVariations} {textFieldVariations} {dropDownVariations} {typeAheadVariations} </PermutationTestingStyle> ); };
As maybe you can see it's pretty easy to spin up new variants. "getAllSubsets()" is some very clever code I found online and honestly don't quite understand that makes all the permutations possible.
Monday, September 13, 2021
stuntcoding and the power of sin (and cos)
A while back I made this (somewhat pretentious) business card:
It has a small Processing program on the back - in 2014 I impressed Ben Fry, co-founder of Processing, by having it there.//spiro.pde - see processing.org float a,b; void draw(){ noStroke(); fill(0,10); rect(0,0,100,100); fill(255); ellipse(50+(20*cos(a)+10*cos(b)), 50+(20*sin(a)+10*sin(b)), 3,3); a += map(mouseX,0,100,-.5,.5); b += map(mouseY,0,100,-.5,.5); } //see in action: http://kirk.is/card/It's nothing too fancy... just using the mouseX and mouseY as speed controls for a pair of nested circles - very much like a spirograph. ("draw()" is the p5 function called every tick of the clock)
t=0 draw=_=>{createCanvas(w=500,w) n=sin t+=.03 for(c=0;c<w;c+=31)for(r=0;r<w;r+=31)if((r+c)%2<1){beginShape(fill(0)) for(i=0;i<4;i++)for(b=i*PI/2+max(min(n(t+dist(w,w,c,r))*1.5+n(t/2)/2,1), -1)*PI,a=b+3.9;a>b+2.3;a-=.1)vertex(c+cos(b)*32+cos(a)*18,r+n(b)*32+n(a)*18) endShape()}}Here's the tweet that it came from. You can see it in an editor here.
let t=0; function draw(){ createCanvas(w=500,w); let n=sin; t+=.03; for(c=0;c<w;c+=31){ for(r=0;r<w;r+=31){ if((r+c)%2<1){ beginShape(); fill(0); for(i=0;i<4;i++) { for(b=i*PI/2+max(min(n(t+dist(w,w,c,r))*1.5+n(t/2)/2,1),-1)*PI, a=b+3.9; a>b+2.3; a-=.1) { vertex(c+cos(b)*32+cos(a)*18,r+n(b)*32+n(a)*18); } } endShape() } } } }I swapped in `function draw()` for `draw=_=>` - I was looking up what "_" meant before I realized it was just a throw away variable for the fat arrow notation.
let t=0; const SZ = 500; function draw(){ createCanvas(SZ,SZ); t+=.03; for(c=0;c<SZ;c+=31){ for(r=0;r<SZ;r+=31){ if((r+c)%2<1) { beginShape(); fill(0); for(i=0;i<4;i++){ b=i*PI/2+max(min(sin(t+dist(SZ,SZ,c,r))*1.5+sin(t/2)/2,1),-1)*PI; a=b+3.9; while(a>b+2.3) { vertex(c+cos(b)*32+cos(a)*18,r+sin(b)*32+sin(a)*18); a-=.1; } } endShape() } } } }Also I replaced the cleverly initialized "w" variable with a big old const SZ, my favorite shortcut for the size of a thing.
if((r+c)%2<1) {
b = mouseX / 10 + i * PI/2;
So that just leaves us with this monster that effectively sets b for each spinner to a constant (outside of the i * PI /2 boost):
max(min(sin(t+dist(SZ/2,SZ/2,c,r))*1.5+sin(t/2)/2,1),-1)*PI
what color shall we paint the bike shed
Today at work I had reason to mention bikeshedding, where too much time and attention is paid to not-significant-enough details. Here's another example of it used in context.
Saturday, September 4, 2021
links in the traditional blue
Why is the sky are links on the web traditionally blue? A really fun look at very early browsers.
Fun ("fun") fact - I've had a personal start page ("kirkzilla", a play on mozilla) on line for, like, decades. At first it used a trick in early Netscape of displaying your saved bookmarks as a page, but later I made it its own thing. But I kept the colors the classic Mozilla even when I had to use CSS to do so...