Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Created November 29, 2023 23:05
Show Gist options
  • Save dfkaye/b6e0dca12269dd4107b8b78e5d946d14 to your computer and use it in GitHub Desktop.
Save dfkaye/b6e0dca12269dd4107b8b78e5d946d14 to your computer and use it in GitHub Desktop.
using console parts to create styled output
// 29-30 August 2023
// console.styled.js
// Using console parts to create styled output.
// # Multiple output statements with `console.[method].apply`
// Usually we log console statements with any number of arguments.
console.log("one");
console.log("two", "arguments");
// Sometimes it makes sense to collect messages first, and output one at a time.
var parts = ["first", "second", "third"];
parts.forEach(part => console.log(part));
// We can, however, print them in one statement, using `console.[method].apply`.
console.log.apply(console, parts);
// # Styled output
// We describe a pattern for styling targeted content while ignoring prelude
// text (i.e., text that occurs before the styled content, and rest text (i.e.,
// the rest of the text that occurs after the styled content).
// 1. color directive
// Browser console (and maybe even the Node.js REPL), provides a directive to
// indicate that string output following it is to be styled by a *subsequent*
// string containing a CSS rule-set.
console.log("%c Color me red ", "color: red;");
// 2. "prelude" text
// If we prefix that text containing the directive, the prefix is not styled.
console.log("prefix to red text: " + "%c color me red ", "color: red;");
// 3. "rest" text
// Any text provided *after* the styling rules is unstyled.
console.log("prefix to red text: " + "%ccolor me red", "color: red;", "*rest*");
// A more complicated-looking set of statements...
console.log(
"unstyled prelude... " + "%cstyled content",
`
background: antiquewhite;
font-weight: 600;
outline: 1px solid red;
`,
"any subsequent unstyled text",
"\nmore unstyled text"
);
// 4. array of statements
// Text arguments like that last one can became hard to scan. We can put them in
// an array and use `console.log.apply` instead.
var parts = [
"unstyled prelude... " + "%cstyled content",
`
background: antiquewhite;
font-weight: 600;
outline: 1px solid red;
`,
"any subsequent unstyled text",
"\nmore unstyled text"
];
console.log.apply(console, parts);
// # Custom `console.styled()` output method
// Now we can define a method for the console that accepts properties to build
// up such arrays and apply them directly.
// An example shape:
var message = {
method: "warn",
title: null,
prelude: "aa <b> space </b>",
content: "aa",
style: "background: pink;",
rest: "<b> space </b> aa"
};
// A console method for this type of message
console.styled = function({ level, title, prelude, content, style, rest }) {
level || (level = 'log');
var param = arguments[0];
if (param !== Object(param)
|| param.toString() != '[object Object]'
|| Object.keys(param).length === 0){
return console.log("unstyled output:\n", param);
}
title = title ? title + '\n' : '';
prelude = prelude ? prelude + '' : '';
content = content ? content + '' : '';
style = style ? style + '' : '';
var output = title + [prelude, '%c', content].join('');
var message = output.length
? [output, style]
: [];
rest && (message.push('' + rest));
var method = level in console
? level
: 'log';
console.assert(
method === level,
`console.styled() log level "${level}" not supported; using "${method}".`
);
console[method].apply(console, message);
};
/* test it out */
console.styled(message);
console.styled({
content: "plain content"
});
console.styled({
content: "tomato content",
style: "background: tomato; color: white;"
});
console.styled({
prelude: "prelude: ",
content: "italic skyblue content",
style: "background: skyblue; font-style: italic;"
});
console.styled({
title: "TiTLE",
prelude: "prelude: ",
content: "underlined papayawhip content",
style: "background: papayawhip; text-decoration: underline;"
});
console.styled({
title: "TiTLE",
prelude: "<begin>",
content: "bold boxed content",
style: `
background: gainsboro;
border: 2px solid fuchsia;
font-weight: bold;
padding: 2px 1em 0;
`,
rest: "</end>"
});
// unsupported log level should print assertion message
// and then log "dog test"
console.styled({
level: 'dog',
content: "dog test"
});
// missing content param should log "rest"
console.styled({
rest: "...rest..."
});
// should capture error
var error;
try { console.styled(); }
catch (e) { error = e; }
finally { console.log(error); console.assert(error, "should get an error"); }
// should capture error
var error;
try { console.styled(null); }
catch (e) { error = e; }
finally { console.log(error); console.assert(error, "should get an error"); }
// should log Object { }
console.styled({ });
// should log Array[ 'a' ]
console.styled(['a']);
// should log Number { 99 }
console.styled(new Number(99));
// should log 1
console.styled(1);
// should log Boolean { false }
console.styled(new Boolean());
// should log true
console.styled(true);
// should log String { "string" }
console.styled(new String("string"));
// should log "ok"
console.styled("ok");
// style with invalid CSS
console.styled({
title: "a",
prelude: 'b',
content: "c",
style: "d",
rest: "e"
});
/*
a
bc e
*/
// style with valid CSS
console.styled({
title: "a",
prelude: 'b ',
content: " c ",
style: "background: gainsboro; outline: 2px solid aqua;",
rest: "e"
});
/*
a
bc e
*/
/* test non-string arguments */
// plain object
console.styled({ title: {}, prelude: {}, content: {}, style: {}, rest: {} });
/*
[object Object]
[object Object][object Object] [object Object]
*/
// object with valueOf()
console.styled({
title: {valueOf() { return 'title'}},
prelude: {valueOf() { return 'prelude'}},
content: {valueOf() { return 'content'}},
style: {valueOf() { return 'style'}},
rest: {valueOf() { return 'rest'}}
});
/*
title
preludecontent rest
*/
// array of strings
console.styled({
title: ["title"],
prelude: ["prelude"],
content: ["content"],
style: ["style"],
rest: ["rest"]
});
/*
title
preludecontent rest
*/
// number
console.styled({ title: 1, prelude: 2, content: 3, style: 4, rest: 5 });
/*
1
23 5
*/
// all args - date
console.styled({
title: new Date,
prelude: new Date,
content: new Date,
style: new Date,
rest: new Date
});
/*
Wed Aug 30 2023 16:49:37 GMT-0700 (Pacific Daylight Time)
Wed Aug 30 2023 16:49:37 GMT-0700 (Pacific Daylight Time)Wed Aug 30 2023 16:49:37 GMT-0700 (Pacific Daylight Time) Wed Aug 30 2023 16:49:37 GMT-0700 (Pacific Daylight Time)
*/
// all args - regexp
console.styled({
title: /title/i,
prelude: /^Prelude/,
content: /(?:content)+$/m,
style: /(?:style)/,
rest: /^rest$/m
});
/*
/title/i
/^Prelude//(?:content)+$/m /^rest$/m
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment