Year #2, Week #9 đŸ’» 🚂

New stuff we learned this week: đŸ€”

Webfonts

  • the font you specify in a CSS font-family declaration will only be visible to the user if they have that font installed on their system. Sadly, there are only a few fonts that are reliably found on nearly all computers. These fonts are generally referred to as web-safe fonts. They are safe for the web because they will be available for almost everybody.
  • the web-safe fonts are (approximately):
    • “Arial” (sans-serif)
    • “Arial Black” (sans-serif)
    • “Verdana” (sans-serif)
    • “Tahoma” (sans-serif)
    • “Trebuchet MS” (sans-serif)
    • “Impact” (sans-serif)
    • “Times New Roman” (serif)
    • “Didot” (serif)
    • “Georgia” (serif)
    • “American Typewriter” (serif)
    • “AndalĂ© Mono” (monospace)
    • “Courier” (monospace)
    • “Lucida Console” (monospace)
    • “Monaco” (monospace)
    • “Bradley Hand” (cursive)
    • “Brush Script MT” (cursive)
    • “Luminari” (fantasy)
    • “Comic Sans MS” (cursive)
  • One way to deal with the fact that a user might not have a font installed on their system is by using the concept of fallback fonts — that is, specifying a list of fonts in a CSS declaration:
html {
  font-family: Baskerville, "Times New Roman", serif;
}
  • from the above code, if the user doesn’t have Baskerville (which generally only Mac users do), they will get Times New Roman — also a serif font. Sometimes this is good enough.
  • however, because many web designers really wanted to be able to design their pages with specific fonts, eventually a standard called Web fonts emerged. It works like this: first you declare a font-face in your css like this:
@font-face {
  font-family: "Goat Banjo Rodeo";
  src: url("goatBanjoRodeo.woff");
}
  • a font-face declaration is comprised of a name for the font (line 2 above), and one or more sources for a font-file for that font. The most common and modern source format is a .woff file, however, not all older browsers support that format, so you can supply a number of different sources, letting the browser choose which one they understand, like this:
@font-face {
  font-family: "Goat Banjo Rodeo";
  src: url("fonts/gbr.eot");
  src: url("fonts/gbr-webfont.eot?#iefix") format("embedded-opentype"), url("fonts/gbr-webfont.woff2")
      format("woff2"), url("fonts/gbr-webfont.woff") format("woff"), url("fonts/gbr-webfont.ttf")
      format("truetype"), url("fonts/gbr-webfont.svg#gbf") format("svg");
  font-weight: normal;
  font-style: normal;
}

classnames npm package

  • it’s very common in react to be applying a number of classes to an item, often with variables (from css modules) or conditionally based on some state. This can lead to some ugly-looking junk trying to set the className prop of components:
const Block: React.FC = () => {
  const [ok, setOk] = useState(false);
  return (
    // this next line is yucky
    <div className={`${style.wrap}${ok ? " ok" : ""}`}>
      <h1>Howdy</h1>
      <p>Partner</p>
    </div>
  );
};
  • the npm classnames package is a widely-used solution to this problem. It gives you a bunch of flexibility for passing values to it, and always produces a nice string of space-separated css classes:
import classnames from "classnames";

// pass it plain old strings:
classnames("foo", "bar");
// -> "foo bar"

// or an array of strings:
classnames(["foo", "bar"]);
// -> "foo bar"

// it pitches falsy things and non-empty strings:
classnames(undefined, null, false, "", "foo");
// -> "foo"

// good for CONDITIONALLY adding a class:
let isOpen = true;
let isBlue = false;
classnames("menu", isOpen && "open", isBlue && "blue");
// -> "menu open"

// also accepts object syntax where KEYS are the classnames
// and VALUES are booleans controlling if class is added
// so we could rewrite the above example as:
classnames("menu", {
  open: isOpen,
  blue: isBlue,
});
// -> "menu open"

// you can MIX AND MATCH all the ways of passing args:
classnames(["foo"], "bar", null, { lol: true });
// -> "foo bar lol"

CSS Transitions

  • by default, when certain CSS values change dynamically, the browser renders the change instantaneously. Consider this CSS:
a {
  color: red;
}

a:hover {
  color: blue;
}
  • when a user hovers over an <a> tag, the color will instantly change to blue. But if we wanted the transition to blue slowly, we could indicate that by adding transition-<x> properties, like so:
a {
  color: red;
  transition-duration: 200ms; /* LENGTH of transition */
  transition-property: color; /* WHAT to transition */
  transition-timing-function: linear; /* SHAPE of trans. */
  transition-delay: 100ms; /* DELAY before transition */
}

a:hover {
  color: blue;
}
  • examples of transition-timing-function include linear, ease, ease-in, ease-out, ease-in-out, and more

  • some css properties can not be transitioned — and it’s fairly intuitive to figure out which ones those are. If there is no way to mathematically calculate intermediate states, then it probably can’t be transitioned. For instance, moving from display: none to display: flex is not transitionable, because there is no way to smoothly transition from one to another. But you can transition from opacity: 0 to opacity: 1 to achieve a “fade-in” effect.

Typescript: Type “Narrowing”

  • Typescript can NARROW types inside of conditional statements.
  • Study this code block, reading the comments, until it makes sense.
type MyUnion = string | boolean | Array<string>;

function takesUnion(val: MyUnion) {
  // on this line TS only knows that `val` is
  // one of 3 things: string, boolean, or array of strings
  if (Array.isArray(val)) {
    // inside these rabbit ears
    // 😎 TS KNOWS that `val` must be `Array<string>`
    // so you can safely do:
    val.forEach((item) => console.log(item));
  } else if (typeof val === "string") {
    // 😎 in here TS KNOWS that `val` is a string!
    // so this works and typechecks!
    val.toLowerCase();
  } else {
    // 😎 and in here TS KNOWS `val` must be a boolean!
    let x: boolean = val; // OK √
  }
}

Useful Links:


Homework Plan

🩃  A bit lighter on homework this week because of Thanksgiving. But make sure to do FOUR separate days of Execute Program!

  • 1 day review all flashcards (in your app)
  • 1 day Flashcard App assignment
  • 1 day classnames assignment
  • 1 day touch typing practice
  • 1 day touch watch CSS Transitions video
  • 4 days Execute Program homework


  • Flashcard App Homework


    • Slowly and carefully review the “New Stuff” above ^^^.
    • Watch the CSS Transitions Video first.
    • Merge your MR from last week, switch to master, pull changes from origin, delete your branch from last week, and make a new branch.
    • Integrate 2 webfonts from Google Fonts into your Flashcards app.
    • commit your work.
    • Add 2 CSS Transitions to your Flashcards app — but no using the transition: shorthand property! Use the longer-form transition-<x> format. Shorthands are (almost always) evil!
    • commit your work.
    • add 5 new css cards:
      • @font-face
      • transition-duration
      • transition-property
      • transition-timing-function
      • transition-delay
    • add 15 new cards from your old physical/digital location.
    • commit your work.
    • build your site, push up a MR, put links in Slack.

    Classnames Homework


    • Slowly and carefully review the “classnames” section and the “type narrowing” section in New Stuff above ^^^.
    • visit this url, copy the git clone url, clone the repo and open up the cloned repo through vscode.
    • install the dependencies
    • create a new branch
    • read ALL the rest of these instructions before getting started!
    • run the test with npm run test or npm run test:watch (for watch mode)
    • one by one get the tests passing, changing the next xit() to it() one by one.
    • hints/clarifications:
      • the real classnames package takes variadic arguments, meaning, it can take as many arguments as you pass it. I haven’t taught you how to do that in JS yet, so for this assignment, we’re limiting the function to take 1 - 3 arguments. I already created the function signature types for you, and made the last two arguments optional by using the ? char. You will have to slowly morph the Input type, making it a Union of all the things that the function can accept.
      • because the function takes up to 3 arguments, each of which can be all of the same things, you might find it’s helpful to create a helper function, something like handleSingleArgument() and then call it 3 times, using it somehow to build up the final output of the function.
      • you might want to review some of the Array functions from here.
      • you can use the function Array.isArray(x) to test if something is an array. Don’t use typeof because it returns object for arrays.
      • if you have a Union type in typescript, something like type Foo = string | boolean; you can test the type using various tricks (like the typeof operator and Array.isArray()). Typescript is smart enough to narrow the type inside an if block.
      • if you haven’t read the “Type Narrowing” section above including watching the video I made (linked above) — stop and do that now. It will be very helpful for this assignment.
    • commit your work when you finish, submit a MR, slack the MR url.
    ← All homework