Hello Odin!
This is where I'll be going through The Odin Project. The readme itself includes random tidbits I've picked up along the way that are relevant to me as I'm learning, but probably won't be relevant to future me. This mostly consists of things that catch me off guard or are otherwise unexpected.
Apologies for the insistence on all lowercase in the readme - it makes it a lot easier for me to jot down my nonsense.
There are almost definitely going to be sections in here that aren't explicitly covered by The Odin Project, just by nature of coming across other resources while working on it.
Each folder has a subfolder called unedited
to indicate that these are the raw files provided by The Odin Project where needed. The files in the parent folder include the contents of this raw file as well as any edits I've made to them to complete the exercise.
-
ctrl + shift + p
for shortcut -
commit messages go at the bottom of the file it opens, save and close it once done to commit
-
commit files one by one, add a commit message for each, then sync - don't stage all your files in one go, then commit and sync straight away
-
add the below to preferences: open keyboard shortcuts (json):
[
// ...
{
"key": "ctrl+tab",
"command": "workbench.action.nextEditor"
},
{
"key": "ctrl+shift+tab",
"command": "workbench.action.previousEditor"
}
]
-
disable
HTML: Auto Create Quotes
andHTML: Auto close tags
-
disable
explorer.autoReveal
-
vs code doesn't like
#
in filenames/folder names -!
and.
are okay -
disable
Workbench > Editor: Enable Preview
in preferences -
ctrl + /
comments things out
-
html foundations covers:
- what tags are and examples of them
div
p
h1
-h6
ul
vsol
(andli
) (unordered lists, ordered lists, and points in lists)strong
em
- comments
img
a href
(both relative and absolute)span
(for only marking up part of a piece of text - see this file for more info)
- what a boilerplate html file should include (see here)
- what should go in the head (meta tags, title)
- when to use strong, b, em, and i
- what tags are and examples of them
-
split content into
<section>
s instead of using<div>
s - similarly use<header>
and<footer>
(e.g. actually put a header/footer in them rather than leaving them blank) -
html reference sheets can be found here (devdocs) and here (mozilla)
-
things covered in foundations:
- basic css (what it is, basic syntax, etc)
- type selectors in css (e.g.
div{[stylistic features]}
,p{[stylistic features]}
) - classes (preceded by
.
) - ids (preceded by
#
, unique) - grouping classes in css (i.e.
class-one, class-two{[stylistic features]}
) - for when different classes share some but not all stylistic features - chaining classes/ids in html (i.e.
class="class-one class-two"
) - for when an element should have multiple classes or ids applied to it. - you can do
.class-one.class-two{[stylistic features]}
in css and it'll only apply those styles to elements with both of those classes personally i feel like these should have different names as the html is the same whether you're applying multiple classes to the same element or applying styling to something with both classes in css - my opinion on this will likely change down the line as i see various use cases for it, but at the time of writing it's far more confusing than grouping and descendants- not sure what i meant by this but i think it was with regard to chaining having the same name in html and css despite being something different- descendant combinators in css (
.parent.child
only selects.child
if it's a child of (i.e. nested in) a.parent
in the html - this can also be done on elements/types, so instead of.parent.child {[stylistic features]}
you could dodiv p {[stylistic features]}
to apply styling to anyp
s that are children ofdiv
s - other selectors include:
,
to select more than one set of selectors (i.e. addition - sop, div
selects allp
s and alldiv
s)*
to select everything, which can also be used to select everything inside something else (e.g.p *
selects everything inside ap
)+
to select any siblings - elements that directly follow another that are on the same level (NOT children)~
to select all siblings -A ~ B
selects allB
s that appear afterA
, but notA
itself>
selects all direct children of an elementX:first-child
selectsX
when it's the first child of another element - NOT the first child ofX
X:only-child
- selectsX
if it's the only child of another elementX:last-child
- selectsX
when it's the last chid of another elementX:nth-child(N)
- selectsX
when it's the Nth child of another element - this includes its siblings, so it selects the item if it's only the Nth child in the list, and not the NthX
X:nth-last-child(N)
- selectsX
when it's the Nth child from the end - again, this includes siblings, soX:nth-last-child(3)
won't select the 3rd lastX
, but will only selectX
if it's 3rd from the end out of all of its siblings- if you specifically wanted the 3rd last X, you could ask for
X:nth-last-of-type(3)
- if you specifically wanted the 3rd last X, you could ask for
X:first-of-type
- selectsX
when it's the firstX
in a listX:nth-of-type(N)
- selectsX
when it's the NthX
in a list, where N can be a number, oreven
, orodd
- this also accepts
Nn+Y
, such as2n+3
which would select every 2ndX
, starting from the 3rd one, so 3, 5, 7 etc
- this also accepts
X:only-of-type
- selectsX
when it's the only child of its type within the parentX:last-of-type
- selectsX
when its the last of its type within its parentX:empty
- selects anyX
without childrenX:not(Y)
- selects anyX
that doesn't have attributeY
X[attribute="Y"]
- selects anything with said attribute, so:[href]
selects anything with anhref
,a[href]
selects anya
s that have anhref
attached (i.e.a href="URL"
)a href="google.com"
selects anya
s that have anhref
ofgoogle.com
X[attribute^="xyz"]
selects anything where the attribute begins withxyz
- you can use$
instead of^
for when you want it to end withxyz
, and*
when you wantxyz
to appear anywhere in the attribute
- the cascade (i.e. specificity)
- css specificity is weird at first:
- check out this page (w3schools) for a comprehensive breakdown
- in essence:
- a declaration that is more specific will take precedence over one that is less specific
- it's a scoring system whereby each id used gets 100 points, each class, pseudo-class (e.g.
:hover
and:first-of-type
), or attribute selector(e.g.[checked]
) gets 10, and each type selector or pseudo-element (e.g.:before
and:selection
) gets 1 point- i.e. in general, an id selector beats class selectors, which beat type selectors
- inline styling gets a specificity value of 1,000 and is always given highest priority unless the
!important
rule is used - the lower down a rule is in the file, the higher the priority (if all else is equal) - if
font-size
is set to24px
on the bottom line and also set higher up at18px
for two rules of equal priority,24px
will take priority - similarly if something is styled with equal priority in bothstyles.css
andindex.html
, the styling in the html file will take priority - the universal (
*
) selector (and+
,~
,>
, and empty spaces:* {[stylstic features]}
is overridden by everything - the
>
selector is called a child selector - whereas.parent .child
will select any.child
found in.parent
, no matter how deeply nested it is,.parent > .child
will only target.child
when it's a DIRECT descendant of.parent
(rather than ones that are also further nested) - i don't fully understand these at the time of writing, but:
- now understood - id selectors have a higher specificity than attribute selectors
- now understood - class selector beats any number of element selectors (i.e.
.class{}
will always beatdiv{}
)
- children inherit typography-based properties (
color
,font-size
,font-family
, etc), but targeting it directly overrides this (i.e. if parent class hasfont-size
set to18px
and child class isn't explicitly set tofont-size: 24px
, it will inherit18px
- if it is explicitly set tofont-size: 24px
, this will override the inheritance) - the number of hits on the highest reached level matter -
.paragraph:first-of-type
has two hits on the fourth level (one class and one pseudo-class) whereasp.paragraph
has one hit on the fourth level (.paragraph
) and one on the fifth (p
- a type selector) - from highest to lowest priority:
- anything that applies to an active transition
!important
- anything that applies to an active animation
- almost everything else:
- inline styling
@layer
- id
- class/attribute/pseudo-class
- type/pseudo-element
- position on
styles.css
-
you can use something like
background: red !important
to confirm you're selecting the correct element (similarly we can doborder: 2px solid red
) -
css reference sheets can be found here (devdocs) and here (mozilla)
-
other useful css info can be found at csstricks
-
in css,
img.huge
targets any images with thehuge
class, whereas.huge-image
is a class of its own and while it can be applied to images, it can also be applied to literally anything else. so while on the front-end, these should function similarly (provided the rest of your code is good), it's bad practice to use the latter because it's asking for trouble, and makes your code unnecessarily hard to read -
for
font-family
, only use quotation marks around the font name if there are spaces in it (e.g. "Times New Roman"
vsVerdana
) -
best practice is to use a space before
{
, but not for=
or"
-
at the time of writing (i.e. this probably won't be relevant beyond june 2023), i'm not entirely sure what the use case is for ids, grouping, chaining, or descendants - i understand how to use them in theory, but in reality i'm not sure when to apply each
-
best practice is to use hyphens instead of camelCase
-
in your browser's console, a strikethrough on a css style means it's overridden by something else
-
when adding css via browser console, if you want to apply something universally throughout the page, ensure you have the root
<html>
tag selected - where your css goes depends on what you have selected -
the box model:
- every element in a webpage is a box -
p
s are wrapped in boxes,h1
s are,img
s are, etc padding
,margin
, andborder
:padding
increases the space between the border of a box and the content of the boxmargin
increases the space between the borders of a box and the borders of adjacent boxes.border
adds space (even if it’s only a pixel or two) between the margin and the padding- take a look at the below image for a visual explanation:
margin
doesn't double up - if two elements next to one another have amargin
of60px
, themargin
will be60px
and not120px
- if one has amargin
of70px
, the totalmargin
will be70px
(i.e. the one with the largestmargin
is picked)- the
height
of an element is actually calculated asheight
+padding
+border
, unless we usebox-sizing: border-box;
when we do this, theheight
/width
of the element are dynamically assigned based on thepadding
+border
(so if an element has100px
height
,20px
padding
, and20px
border
, it will be140px
in total, but if we useborder-box
, theheight
will dynamically decrease to60px
) -border-box
is almost always used
- boxes take both outer and inner display types:
- outer display types include
block
andinline
:block
:- box breaks onto a new line
width
andheight
properties are respectedpadding
,margin
, andborder
will cause other elements to be pushed away- if
width
is not specified, box will fill as much space available in its container as possible - some html elements such as
h1
andp
useblock
as their default
inline
:- will not break onto a new line
width
andheight
are ignored- top and bottom
padding
,margin
, andborder
s apply but don't cause other inline boxes to move away - left and right
padding
,margin
, andborder
s apply and DO cause other inline boxes to move away - some html elements such as
a
,span
,em
, andstrong
useinline
as their default - generally speaking, you don't want to add padding/margin to inline elements
- inner display types dicate how elements inside that box are laid out
- this can be changed by setting, for example,
display: flex
- the element will still keepdisplay: block
, but any direct children of this block will be comeflex
items (see: flexbox)
- this can be changed by setting, for example,
- there is also a middle ground of
display: inline-block
which behaves like an inline element but has block-style padding and margin, but generallyflexbox
is used instead
- outer display types include
div
andspan
have no implicit meaning, they primarily exist to hookid
s orclass
es onto blocks.div
is usually used to divide the page into different blocksspan
can be used to group text/inline elements and is only used when nothing else is appropriate (e.g. highlighting text in ap
)
margin-left: auto
will align an element to the right end of its container- increasing the
margin
of one element effectively increases the size of its container - so take into account size changes when using margin. if one element hasmargin: 12px
then applyingmargin: auto
to something else in the same container, while it will take themargin
of the other element into account, might not look right visually because the margin isn't visible - use borders (seebox-container
class here and here for more info) or inspect element to help with debugging - ran into an interesting issue when doing 2-margin-and-padding:
text-align: center
worked as expected- i wanted to approach it with a different solution by wrapping the text in
span
tags and usingmargin: auto
- this didn't work
- solution:
span
is aninline
element by default, so themargin
was effectively ignored - we had to make thedisplay: flex
as well - we could also wrap it in
p
tags and set thewidth
tofit-content
, becausep
is ablock
by default
- every element in a webpage is a box -
-
ul has a default padding of 40px, so you might want to override this
-
flex stuff:
-
justify-content
accepts:flex-start
flex-end
center
space-between
space-around
-
align-content
accepts the same as the above as well asstretch
-
align-items
andalign-self
accept:flex-start
flex-end
center
baseline
stretch
-
align-content
determines spacing between lines and only comes into effect when there are multiple lines, whilealign-items
aligns the items themselves -
flex-direction
accepts:row
/row-reverse
column
/column-reverse
- both of the above
reverse
s will require you to useflex-end
if you want the items to appear at the start rather than the end, as the new starting point is set to the original end when usingreverse
-
flex-wrap
accepts:nowrap
wrap
wrap-reverse
-
flex-flow
combinesflex-direction
andflex-wrap
and accepts the same arguments as them, e.g.flex-flow: row wrap
-
justify-content: center
to a container is usually functionally the same as addingmargin: 0 auto
to that container's children (but the latter is bad practice, generally)- remember,justify-content
does exactly what it says, it aligns the contents inside it, and not the element itself -align-self
aligns an actual element and takes precedence overjustify-content
andalign-content
justify-content: space-around
puts equal spacing on both sides of the items, including at the edges, whereasspace-between
puts space between them (so goes to the edge of the container)
-
items inside
containers-2
, which in turn is insidecontainer-1
, don't count as items incontainer-1
(i.e. items aren't found recursively) - an item is only really a child of its direct container. in the below code, the only items inmenu
aredate
andlinks
- notsignup
orlogin
<div class='menu'> <div class='date'>Aug 14, 2016</div> <div class='links'> <div class='signup'>Sign Up</div> <div class='login'>Login</div> </div> </div>
display: flex
only applies to direct children of a container rather than grandchildren. similarly,justify-content
only applies to direct children, not children of children - see this exercise for a good example of this
-
align-items
is used for vertical alignment, but when you rotate a container's direction, thejustify-content
property also changes, sojustify-content
andalign-content
switch functions - the best way to see this is thatjustify-content
applies along the main axis, andalign-items
applies along the cross axis -
by default,
flex-direction: row-reverse
only applies on a per row basis -order
applies throughout the whole container -
order
is0
by default, if we change an item's order to1
, ceteris paribus it would move to the end of the container -
flex: initial
overrides something inherited likeflex: 1
, so rather than scaling, it lets you set fixed widths -
applying
margin-left: auto
to something in a container will move it to the right hand side of the container; it will also shift any items after that item in the container -
flex: 1
is equivalent toflex: 1 1 0
which is also equivalent toflex-grow: 1; flex-shrink: 1; flex-basis: 0
flex-grow
defines how quickly an item increases in size to take up the extra space beyond its definedwidth
orflex-basis
flex-shrink
defines how quickly an item shrinks in size when the container is too smallflex-basis
defines the base size of an item - above this, theflex-grow
multiplier will apply how quickly it scales up in relation to other elements, and below this, theflex-shrink
value will apply - so it's not thewidth
, so much as "this is the minimum width we'd like it to be in an ideal world, but you can shrink if necessary", providedflex-shrink
is set to1
or more- setting
flex-basis
toauto
means that they use their definedheight
whenflex-direction
iscolumn
(similarly, definedwidth
is used whenflex-direction
isrow
) - if we simply useflex: 1
thenflex-basis
is set to0px
, meaning that the height of any columns created will be0
height
overridesflex: 1
whenflex-direction
isrow
, andwidth
overridesflex: 1
whenflex-direction
iscolumn
- no matter what, the item won't go above these values
-
justify-self
is ignored in flexbox - if we want to move something to the end of the container, we setmargin-top
ormargin-left
toauto
depending on where we want it to go -
by default, children bunch at the start of the primary axis, and stretch to fill the entire container along the cross axis
-
when
flex-wrap
is set towrap
,align-items
applies to the items on each individual row, whereasalign-content
applies to every row in that box -
remember to set
display: flex
!!! this needs to be done in multiple places depending on what you want to flex - usually you'll want to apply this to anything whose children should flex. similarly, you don't want to overuse flex - while you can achieve what you want, this exercise is a good example of how you can achieve the same without using flexbox
-
-
min-width
is set to the the length of the longest unbroken string of characters for elements containing text, but can be set manually - content will overflow from the container ifmin-width
is bigger than the size of the container -
we can use
@media all and (max-width: VALUE) { .container{} }
to apply conditional formatting based on display width (see this css-tricks article for more info) -
margin: auto
doesn't work on<div>
s because they automatically take up full width -
vw
can be used on a height, similarlyvh
can be used on a width - this lets you make items scale (like the boxes here) -
generally speaking,
px
is best to use for padding,svw
/svh
for responsiveness, and sometimes%
for height - but play it by eardvh
andvh
cause content to resize as the user scrolls which isn't idealpx
is mostly used for borders, margin, box shadows etcem
for font sizes
-
rem
is best to use for font sizes, potentially withclamp
(e.g.3rem, 5svw+1rem, 6rem
- min, preferred, max)- you can also use a
clamp
or evenmin
ongap
s between elements
- you can also use a
-
media queries can be used to stack side by side elements into a column on mobile
-
when adding padding to
a
s inside anli
, you want to apply padding to theli
instead of thea
, because they're the outermost wrapper - applying it to thea
won't actually do anything because they don't have any siblings to pad against -
think outside the box, and think explicitly about what you're telling parents to do - in the flex-modal exercise, we don't want to justify or align the close button itself, but we want to set its parent container to justify its content to
space-between
- because if there are only two items in a container, that sets one to the far left, and one to the far right -
you can use custom properties to set variables, for example:
:root { --modal-and-icon-spacing: 12px; }
this can then be called on with
var(--modal-and-icon-spacing);
elsewhere
-
let
,const
, andvar
are used for variableslet
andvar
are very similar, butvar
has no block scope - only current function or global (if defined outside a function), and are processed at function start (or script start for globals)const
cannot be reassigned- generall speaking,
const
names are uppercase for legibility
-
we can define multiple variables on each line by separating with commas, or on separate lines with tab indentation:
let user = 'name', age = 25, message = 'Hello';
-
when changing a variable, you can't use
let
etc on it again - it's already declared as a type -
variables can only contain letters, numbers, and $ or _, first character cannot be a number, and they are case sensitive
-
==
tests whether values are the same,===
tests whether the data types are also the same; same with!=
and!==
-
prefixing and postfixing operators (++, for example) works slightly differently -
counter++
increments the counter and returns the original value,++counter
increments it and returns the new value - in the below example,a
,b
, andc
are output as2
,d
is output as1
let a = 1, b = 1; let c = ++a; let d = b++;
-
+
will concatenate anything in the same statement if it encounters a string, so:"" + 1 + 0
will output10
4 + 5 + "px"
will output45px
4 + 5 + "px" + 2 + 7
will output45px27
-
putting
+
before a string variable will convert them to a number - so ifapples = "2"
andoranges = "3"
(note the quotation marks) and wealert (apples + oranges)
, we'll get23
because they're concatenated strings, but if wealert (+apples + +oranges
), we'll get5
because they've been converted to numbers -
to include a variable in a concatenation, you have to use template literals -
`
instead of"
or'
- so`Hello, ${name}`
, for example - these also respect line breaks without needing to manually enter a break character- calculations can be done in template literals by doing
`${variableA - variableB}`
- calculations can be done in template literals by doing
-
all string methods return a new string rather than modifying the original string
-
regex is written without quotes
-
OR (
||
) finds the first truthy value when given multiple values - or returns the last value if all are false- similarly, AND (
&&
) finds the first false value when given multiple values- or returns the last value if all are true
- similarly, AND (
-
variables declared within a function are local to that function - variables defined outside of a function are available and editable globally
- similarly, if a variable exists globally but we define it inside a function with
let
or similar, the global value remains ignored and unedited
- similarly, if a variable exists globally but we define it inside a function with
-
we can edit an argument that's been passed to a function, for example to emphasise text (e.g.
function showMessage(from, text){from = '*' + from + '*' + text;}
will italicise the originalfrom
value) -
you can define a default value in a function (i.e. the value used if no argument is given) by putting
=
and then the default string or value after the parameter - we can also set a default value to be another function, so that if no parameter is given for X, we call a different function instead -
calling
return
without a value causes a function to exit immediately -
best practice is that a function should do exactly what its name says -
show
,get
,calc
,create
, orcheck
, for example. so,getAge
shouldn't show analert
withage
-
the standard way of creating a function (
function Y(){CODE}
) is called a function declaration, but we can also have a function expression, whereby we saylet Y = function(){CODE};
(note the semicolon at the end) - this stores it in a variable, and writingalert(Y)
would output the code, rather than running it- function expressions are only usable from the moment they appear in the code, rather than being created at runtime
- however, if we have a function declaration inside another function or a conditional then call it outside that function, it won't work as intended, because function declarations are local and only visible in the code block in which they reside
- we can use a function expression to declare a variable as a function outside of that function, then define it inside - this is especially useful for conditionals, for example
- generally speaking, we only want to use function expressions when a function declaration is not fit for the task (as above)
-
callback functions can be used as arguments in another function:
function ask(question, yes, no) { if (confirm(question)) yes(); else no(); } function showOk() { alert( "You agreed." ); } function showCancel() { alert( "You canceled the execution." ); } // usage: functions showOk, showCancel are passed as arguments to ask ask("Do you agree?", showOk, showCancel);
or in the shorter form:
function ask(question, yes, no) { if (confirm(question)) yes() else no(); } ask( "Do you agree?", function() { alert("You agreed."); }, function() { alert("You canceled the execution."); } );
-
functions should be short and do exactly one thing
- best practice is to nest functions, so rather than putting your whole code in
function showPrimes(n){}
,showPrimes()
should have one or more functions inside, such asisPrime()
- compare how much easier the second one is to read compared to the first:
vs
function showPrimes(n) { nextPrime: for (let i = 2; i < n; i++) { for (let j = 2; j < i; j++) { if (i % j == 0) continue nextPrime; } alert( i ); // a prime } }
function showPrimes(n) { for (let i = 2; i < n; i++) { if (!isPrime(i)) continue; alert(i); // a prime } } function isPrime(n) { for (let i = 2; i < n; i++) { if ( n % i == 0) return false; } return true; }
- compare how much easier the second one is to read compared to the first:
- best practice is to nest functions, so rather than putting your whole code in
-
question mark operators can also be used in functions for if/else queries, e.g.
function checkAge(age) { return (age > 18) ? true : confirm("Did your parents give you permission?") }
- the colon separates the response for true from the response for false- similarly, we can use or operators to do the same,
return (age > 18) || confirm("Did your parents give you permission?")
- similarly, we can use or operators to do the same,
-
arrow functions are another way of expressing functions, e.g.
let sum (a, b) => a+b;
- if there is a single argument, parentheses around it can be ommitted, if there are no arguments then they can be empty but must be present
- they can also be used with operators, e.g.
let function = (a < x) ? () => alert("Hello") : () => alert("Goodbye");
- another example is
let double = n => alert(n + " doubled is equal to " + n * 2); double(3)
-
when troubleshooting errors, type errors can tell you something isn't a function when it actually is - the key thing to bear in mind here is that the function you're calling might not be compatible with that type of data (see below for example)
const str1 = "Hello"; const str2 = "World!"; const message = str1.push(str2);
-
when working with the console, remember to use
console.log()
and notreturn
-
things covered in foundations:
- setting up git, pretty much
- refer here (odin project) for a crash course (incl. setting up commits in vs code)
- setting up git, pretty much
-
general order of affairs is
git add FILENAME
,git commit -m "message"
,git push
-
when using the git cli, instead of moving or deleting files via an explorer,
git mv
orgit rm
them, then push the change - otherwise you'll make a mess. note: this doesn't apply when using vs code as it does this for you -
rather than doing
git add *
, it's best to git add files individually - that way you can add individual commit messages rather than all of your commit messages in one commit being the same
i won't be clearing these out when they're completed, but it's nice to have a history of where i've been and where i am in comparison - i'll probably at least mark them as complete
- look into what these do - they're not covered by The Odin Project
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
done - look into when to use ids, grouping, chaining, and descendants
-
done - look into css specificity - foundation test 6-cascade-fix says chaining selectors and ids gives a rule a higher specificity, but what is the exact order?
-
done (see flexbox notes) - why doesn't
justify-self: flex-end
do the same asmargin: auto
? -
need to learn css grid
-
in chrome, f12 --> console --> cog on second row --> tick "selected content only" to hide errors from extensions
-
extra tools can be used via chrome dev tools by clicking the three dots and going to more tools
-
the .cls button (in styles) can be used to add a class to an element - remember to press enter after doing this
- similarly, .hov can be used to force element states (visited, hover, etc)
-
the window icon to the right of .cls and .hov can be used to open up the sidebar (padding/margin) pane
-
sources --> breakpoints can be used to pause javascript (specifically event listener ones)
- plugin *.js files may interfere here, so you can right click and ignore them
- you can also click on a line number to always pause on that line
-
scope in the devtools tells you what variables are currently defined
-
when editing js in devtools, we have to ctrl + s to save it
- flexbox cheat sheet (malven)
- interactive guide to flexbox (josh w comeau)
- css-tricks flexbox cheat sheet (image)
- compact version of this css-tricks guide
- flexbox visual guide - marina ferreira
- javascript.info
- javascript string methods w3schools and w3schools reference, also at mozilla
- arrow functions cheat sheet (samantha ming)
- the xy problem - how to ask questions
- conventional commits - how to structure your commit messages
- introduction to flexbox - interneting is hard
- interneting is hard as a whole
- interneting is hard - responsive design
- freecodecamp's intro to flexbox
- one day, I want my portfolio to look like this (video on it here)
- javascript for impatient programmers
- when not to use regex
- differences between regular and arrow functions
i firmly believe that ai is a scourge but have to concede that it has its uses for debugging and getting it to eli5 things, so...
- prettier - automatic code formatting
- codebeautify - similar to prettier
- code beautifier - similar again
- css optimizer - restructure function is really useful for merging classes with same properties
- caniuse - checks browser compatibility with various things
- autoprefixer - uses caniuse for adding vendor prefixes to css automatically
- free images can be found at pexels, pixabay, and unsplash
- realtimecolors to see color schemes on a live website
- fontpair for fonts that go well together
- haikei to generate svg/png graphics
- gradient.style for css gradients and shapes
- omatsuri for a bunch of stuff, from color shades to triangle generators, symbols, etc
- utopia for type scaling
- wowebook for free webdev ebooks
- live update the page you're working on (installed)