Year #2, Week #21 đ» đ
New stuff we learned this week: đ€
Basic Responsive Images đŒ
- if you set an explicit width for an HTML
<img>
tag, this can cause problems, especially if viewed on a device not wide enough to show the whole image:
img {
/* đ„” img will be chopped off on screens < 640px */
width: 640px;
}
- very often it is desirable to have images change size based on the size of the screen in which they are viewed, so that, for instance, a small phone can still see the entirety of an image.
- to make this work, we can set the
width
attribute of an image to a relative unit, and then it will automatically become responsive â that is, it will change itâs size along with the screen size. We can accomplish that with some basic CSS like this:
img {
/* đ better, but still has problems */
width: 100%;
}
- the code above is better, but suffers from a couple problems. For one, weâre
now controlling the width with CSS, but setting it independently of the
height, which can cause the image to get stretched and distorted. Luckily,
the fix for this is easy, we can tell the browser to keep the aspect ratio
consistent by supplying
height: auto;
, like so:
img {
/* đ§ getting close now... */
width: 100%;
height: auto; /* keeps aspect-ratio same */
}
- the remaining problem with the above code is that at large screen sizes
the browser will render the image at 100% width, even if that width is larger
than the source image, which results in ugly pixelation. What works better is
to specify
100%
as themax-width
which will cause the browser not to upsize the image:
img {
/* đ shrink proportionately for small screens
but don't let grow larger than img orig size */
max-width: 100%;
height: auto;
}
- this technique is often layered with other visual/layout tweaks, such as changing an image to float at larger screen sizes, like so:
img {
max-width: 100%;
height: auto;
}
@media (min-width: 720px) {
img {
float: left;
margin: 1em 1em 1em 0;
}
}
Object.entries()
- Weâre already somewhat familiar with some of the
static methods on the global
Object
class in javascript, includingObject.keys()
andObject.values()
, which both return arrays, the former of the objectâs keys, the latter, of itâs values:
const person = {
name: "Jared",
age: 42,
hasBeard: true,
};
Object.keys(person); // ["name", "age", "hasBeard"]
Object.values(person); // ["Jared", 42, true]
- another useful method is
Object.entries()
which returns an array of arrays, each array being a pair of[key, value]
, like so:
const person = {
name: "Jared",
age: 42,
hasBeard: true,
};
Object.entries(person);
// > [["name", "Jared"], ["age", 42], ["hasBeard", true]]
Object.entries()
is often useful when iterating over an object. Since it returns an array, you can usefor...of
, like so:
for (let pair of Object.entries(someObj)) {
console.log(`key=${pair[0]}, val=${pair[1]}`);
}
- a neat trick is to immediately destructure the pair returned from each
iteration of
Object.entries()
, like so:
// đ destructure for greater clarity and expressiveness
for (let [key, value] of Object.entries(someObj)) {
console.log(`key=${key}, val=${value}`);
}
CSS: Basic linear-gradient
- a CSS linear gradient creates a image consisting of a transition between two or more colors. The simplest example of a gradient that fades evenly from red (on the top) to blue (on the bottom) would be:
#some-element {
background: linear-gradient(red, blue);
}
- you can also control the direction of the gradient, with an optional first
value to the
linear-gradient()
function, in the format of either<angle>
, orto <keyword>
, as shown in the examples below:
#some-element {
/* <to-KEYWORD> syntax: */
/* gradient angles from bottom right "to" top right */
background: linear-gradient(to left top, red, blue);
/* gradient angles from left "to" right */
background: linear-gradient(to, red, blue);
/* <angle> syntax */
/* 0deg is the same as `to top` */
background: linear-gradient(0deg, red, blue);
/* angle at 45 degrees from bottom left to top right */
background: linear-gradient(45deg, red, blue);
/* you can also specify the angle in "turn"s */
background: linear-gradient(0.25turn, red, blue);
}
- If you donât specify otherwise, the browser will evenly transition between
your colors across the whole dimensions of the element. If you want instead
to control how and when the colors transition, you can specify more
information than just the color, in whatâs known as a
color-stop
, which is a color followed by one or two _optional stop positions, usually specified in percentages, as shown in these examples:
#some-element {
/* Color stop: A gradient going from the bottom to top,
starting blue, turning green at 40% of its length,
and finishing red */
background: linear-gradient(0deg, blue, green 40%, red);
/* Multi-position color stop: A gradient tilted 45 degrees,
with a red bottom-left half and a blue top-right half,
with a hard line where the gradient changes from red to blue */
background: linear-gradient(45deg, red 0 50%, blue 50% 100%);
}
- one useful hack to know is that you can create a âbackground-imageâ of a solid color out of a linear gradient, by just supplying the same color twice (especially useful when youâre want to layer a color over a background image):
#some-element {
/* same as a solid red background image */
background-image: linear-gradient(red, red);
}
- there are more options and tons of interesting combinations you can come up with to create an infinite variety of interesting linear-gradients, you can read more and play with interactive examples on the mdn page here.
CSS: Multiple Background Images
- CSS supports adding multiple background images to the same element. The syntax is simple, you just do it like this:
.some-element {
background: <background1>, <background2>, ...<backgroundN>;
}
- a concrete example might be:
.some-element {
background: url("./cat.png"), linear-gradient(blue, red);
}
- any of the
background-X
declarations support the same syntax, so you can specify them without thebackground
shorthand notation:
.some-element {
background-image: url("./cat.png"), url("./dog.png");
/* cat.png goes in "top left", dog.png in "top right" */
background-position: top left, top right;
}
- a common use case is to overlay a semi-transparent color on top of an
image, using multiple backgroung images, and faking a background âimageâ
with
linear-gradient()
, like so:
.some-element {
background: url("cat.jpg"), linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2));
}
- CSS multiple background images stack FRONT to BACK, or FRONT-FIRST, so a
value of
background: url("cat.png"), url("dog.png");
would putcat.png
ABOVEdog.png
.
Homework Plan
- 1 days review all flashcards (in your app)
- 1 days Flashcard App assignment
- 1 day Akron Snowmen assignment
- 1 day CSS Gradient Exploration
- 1 day Personal Project assignment
- 1 day touch typing practice
- 4 days Execute Program homework
Flashcard App Assignment
- make sure youâve addressed any feedback I left on last weeks merge request, then merge.
- carefully read and review the âObject.entries()â section of âNew Stuffâ above ^^^.
- connect with vscode, checkout master, pull, and make a new branch
- please read one time through all of the steps before you start any work, then come back and work on it step-by-step. đ
- this weekâs homework wonât walk you with as much detail through the process, itâs a fairly straightforward task that Iâll just describe, that youâll need to figure out how to do. A bunch of it is quite similar to last weekâs flashcard assignment, so if you need to, review that assignment.
- the first part of the task is this: weâre going to convert our
card-data.json
data structure to be an OBJECT instead of an array, it should look basically like this:
// card-data.json
{
"5a62d167-46be-4046-a73d-0273cb10e846": {
"front": "vim",
"back": "best editor ever",
"category": "self-evident truths",
"created": "2021-03-11T17:10:41.589Z"
}
// [...] with many more like it...
}
- after weâre done, weâll be able to lookup a card in constant time with a
âBig Oâ of
0
. Your friends will be so proud! - to do this, I want you to make another throw-away
.js
script, like you did last week, and programatically loop over all of the cards, building up the object one by one. As with the last assignment, take it step by step, logging things out, and only actually write the file to disk when youâre satisfied itâs going to work correctly. Also, you should probably make a backup of the file before you start as well. (But be careful not to commit the backup file to git, OK?) - Requirement: notice in my example above how I did not repeat the UUID in the card object, and that it is only in the KEY or left-hand-side of the object. This is how I want you to do it too.
- once youâve got the data structure converted, youâve now broken your app,
because the
server/index.ts
file was expecting the card data in the other format. Weâll fix that now. - start by fixing the
GET /cards
route. To do this, I donât want you to change the client (web app) code at all. Instead, I want you to change the card data back into an array for this route, so that the web-app is none the wiser about the backend change weâre making. That means, youâll need to create an array of all your cards AND as youâre creating that array, youâll need to insert the id field back into the card object, like before. REQUIREMENT: you MUST useObject.entries()
in your solution to this part of the homework. - once you think youâve got the
GET /cards
route working correctly, fire up your web app in dev mode and check that it really is working. The web-app should work as is, with the code untouched. - commit your work.
- next, fix the
POST /cards
card creation endpoint. Again, donât change the web-app code at all, let it send the data in the exact same way. Just change the server so that it inserts the new card into the OBJECT instead of pushing it into an array. - test that adding a card works in your web-app, and commit your work.
- finally, change the
DELETE /cards/<id>
route. This is where our constant-time big O of 0 really shines. Weâll shave nanoseconds off of the time it takes to delete cards, it will be great! đ đ - verify from the web-app that deleting cards still works, and commit your work.
- last but not least, use the âdeleteâ feature you built last week (and made
FAST this week), to carefully delete all of the âtrashâ cards you made while
testing the âadd cardâ feature. For now, donât delete cards youâve memorized
like
cd
, weâll do that soon. For now, just get rid of all the test cards. - build your site, make sure your production daemon is running, submit a MR,
then slack me 3 things:
- your built URL
- your MR URL
- a phrase telling me you deleted the test cards so I know you read the directions carefully and didnât miss that step.
Personal Project Homework
- Refer to your work plan you created a few weeks ago, and select the next item on your list. If youâre ahead or behind of where you thought you would be, make any modifications you think appropriate, then Slack me your goal for this week by WEDNESDAY at 9AM!!!! đ đ
- Make sure youâve addressed all of my feedback from last week, merge your MR, connect with vscode, pull from origin, and create a new branch.
- Implement the feature or chunk of work you planned.
- When you think youâre done, check things like:
- did you leave in any
console.log()
s? - does it look good at all screen sizes?
- do your storybook stories work and cover your components (if youâre using storybook)
- are your components and variables named well?
- is there anything you want to clean up, refactor, or DRY up before you submit?
- did you leave in any
- when youâre happy with the code, build your site, submit a MR, and Slack both the URLs.
- after I review, address any feedback I give you.
Akron Snowmen Assignment
- Be sure youâve addressed any changes requested on last weeks individual assignments, so that I can merge your work in before you start this assignment. If you havenât, address the feedback now and slack me to let me know.
- once your changes from last week are merged in, connect with vscode, switch to master, pull from upstream, delete your old branch, and create a new branch.
- carefully and slowly read and review the âresponsive imagesâ, âlinear gradientsâ, and âmultiple css background imagesâ section of âNew Stuffâ above ^^^.
- This week, weâre going to build the components necessary to make a few
âarticleâ-type pages. That includes:
<ArticleHeadline>
<ArticleImage />
<ArticlePage />
- Fire up Storybook, and create a new Component, and Story file for the
<ArticleHeadline>
component. Then read all these requirements before starting. The component should:- look good at all screen sizes. You MUST start by designing it for mobile-size screens and then tweak it to look good at other screen sizes, not vice-versa.
- take the magic
children
prop for passing the text of the headline in. - it should accept an image as a prop, which it will display as a background image behind the headline
- it should accept a string for a css background color value which will be overlaid over the image (using the multiple background images technique taught in class).
- the background image should be positioned using
background-size: cover
- the color passed as a prop should be stacked on top of the image, so that the text is legible.
- make sure that the text looks good if a long headline is passed in, causing the text to wrap to two lines.
- Next, weâre going to make an
<ArticleImage>
component. This component is meant to make it easy for us to add nicely aligned, responsive images into our article page. Read all the requirements below:- The component should take an
image
prop, which is astring
which should be the image to display. (It could be a full web URL, but weâre going to be importing images in our js/ts files and doing it that way) - You must create a Storybook story file for the component
- You must start by working on the MOBILE view of the component (mobile first!!).
- In the mobile view, the image should be the full-width of the containing element, and be responsive to adapt to different screen-sizes, as discussed in the âResponsive Imagesâ section of âNew Stuffâ above.
- In your story for the mobile view, embed the component inside a div with some dummy text, both before and after the image. Then, using this before/after text, make sure that at the mobile viewport size, there is appropriate margins added to the image to make the text not get too close to the image, and to look generally decent.
- the component should also take a
direction
prop that is a union of two possible strings:'left' | 'right'
. - at larger screen sizes, the image should stop taking up the full width
and instead FLOAT to the side indicated by the
direction
prop. - when floating, the image should have appropriate margins applied so that text doesnât run right into the image itself. These margins will be different than those needed for small screens, since text will also be floating around the image, and will be able to possibly touch the imageâs side if youâre not careful.
- make sure you have a Storybook Story for the component that shows it working
when aligned both
left
andright
. - NOTE: at small screen sizes, the component should render exactly the same
no matter what value the
direction
prop is, since that prop only comes into play when floating the image to one side at larger screen sizes.
- The component should take an
- Commit your work.
- Finally, weâre going to make a very simple
<ArticlePage>
component, that is just a thin wrapper around the<ArticleHeadline>
component, with some nice padding for a big text area below. - Create a new component called
<ArticlePage>
, and create a new Storybook story for it. First read through, then work through these requirements:- start by giving it image, color, and headline props (strings for all three)
- it should also take the magic
children
prop, for the main âbodyâ or text+images of the âarticleâ. - The JSX innerds of this component should be basically in two parts.
First, right after an opening
<div>
, the component should render a<ArticleHeadline>
component. Pass the component the 3 props I mentioned above. - after the ArticleHeadline, it should have another
div
, and inside that div, render thechildren
prop. - The inner div which contains the
children
prop should get a css class, and be styled a little bit, mostly to give it a little padding so that the text and images placed in it are nicely spaced away from the headline, left, right, and bottom of the page. - when youâre all done, you should be able to use the component like this:
const SaltArticlePage: React.FC = () => (
<Layout>
<ArticlePage title="About Salt" image={SaltTruck} color="pink">
<ArticleImage image={Salt_1} direction="left">
<BodyText>
Salt is good, unless it loses its saltiness, etc.
Lorum ipsum dolor set...
</BodyText>
<ArticleImage image={Salt_2} direction="right">
<BodyText>
Lorem ipsum dolor set
</BodyText>
<BodyText>
Lorem ipsum dolor set
</BodyText>
</Article>
</Layout>
)
- Commit your work
- Finally, create a new page in the
./pages/
dir, next toindex.tsx
andour-team.tsx
. Make a fake article page, you can use dummy text. Insert at least two images, and test that everything is working and looks good when using the new components. Fix or tweak anything that doesnât look right. NOTE: this page should not use the<ArticleHeadline>
component directly â instead it should just use the<ArticlePage>
component, which passes props down to an ArticleHeadline component. It should however use the<ArticleImage>
component, as part of thechildren
, as shown in my example above. - Commit your work. Build the site, submit a MR, build the storybook site, and submit all the URLs in a Slack message.
CSS Gradient Exploration Assignment
- Start by slowly and carefully reading and studying the code samples from the âLinear Gradientâ section of âNew Stuffâ above ^^^.
- Next, take a few minutes and read this whole page, pausing to try out several of the techniques shown in the âCSS Demoâ section up near the top.
- Then, slowly and carefully read through this page as well. Itâs not critical that you perfectly understand all of the techniques and variations of gradients, or that you memorize them, but I do want you to study it until you have a basic sense of how gradients work, and what kinds of things are possible with them.