- Clone the repository
git clone https://github.com/Kakamotobi/fe-max--shopping.git
- Install dependencies
npm install
- Run the development server
npm run dev
- Amazon mainpage clone.
- Top Nav Bar
- Login Section
- Login "tooltip"
- Appears after 1 second after page load.
- Login Section Hover
- Login "tooltip" disappears.
- Login modal appears.
- Close modal when no longer hovering over the section or modal.
- Dim main section.
- Login "tooltip"
- Shipping Section Hover
- Shipping address modal appears.
- Close modal when no longer hovering over the section or modal.
- Dim main section.
- Navbar expands the whole width of the viewport.
- Search bar grows when vw >= 1120px.
- Login Section
- Hero Infinite Carousel
- Automatically move to next slide after 10s of no interaction.
- Search Form
- Fetch autocomplete data
- Autocomplete Panel
- Use up/down arrows to navigate autocomplete options.
- Side Bar
- Open when burger button on sub nav is clicked.
- Fetch contents from server.
- Main Menu
- Map main menu contents to corresponding sub menus.
- Compressed portion of contents
- Sub Menus
- Back Drop (dimmed layer)
- Server
- Hero images endpoint
- Card images endpoint
- Search autocomplete endpoint
- Side bar contents endpoint
- SCSS cannot be naturally hooked into Web Components.
-
Compile SCSS files into CSS (using dart-sass compiler) and fetch it as text in JS. Then, insert that CSS string into the Web Component.
-
Example
sass index.scss:build/css/index.css
const cssString = await (await fetch("build/styles/index.css")).text(); const template = document.createElement("template"); const style = document.createElement("style"); template.innerHTML = ` <div> <p>Hello!</p> </div> `; style.textContent = cssString; export default class TestComponent extends HTMLElement { constructor() { super(); const shadowRoot = this.attachShadow({ mode: "open" }); shadowRoot.append(template.content.cloneNode(true), style); } } customElements.define("test-component", TestComponent);
-
Although the overhead is minimal since it is fetched from my own server (relatively cheap), it is still a request/response cycle.
- However, it is acceptable since the request is only sent once for each corresponding component (i.e. no need to fetch every time the component is generated).
- Use SASS' JavaScript API.
- Example 1 -
compile
const sass = require("sass"); const cssString = sass.compile("./index.scss").css;
- Example 2 -
compileString
const sass = require("sass"); const sassString = ` div { p { color: blue; } } `; const cssString = sass.compileString(sassString).css;
- No formatter --> Prone to runtime errors.
- Problem: the "sass" library only supports CommonJS.
- Need a way to use ESModules instead of Commonjs.
- Transpile the whole "sass" library to ESModules?
- Check "sass-loader" source code?
- Simpler and better to use a module bundler.
- Transpile the whole "sass" library to ESModules?
- Need a way to use ESModules instead of Commonjs.
-
@import
makes variables, mixins, etc. globally accessible.@import
is discouraged as it will eventually be removed.
// index.scss @import "./_variables.scss"; @import "./otherfile.scss";
// _variables.scss $color-blue: "blue";
// otherfile.scss p { color: $color-blue; }
-
@use
makes variables, mixins, etc. only available within the scope of the current file (i.e. not globally accessible).// index.scss @use "./otherfile.scss";
// _variables.scss $color-blue: "blue";
// otherfile.scss @use "./variables.scss" as *; p { color: $color-blue; }
- Elements related to headings, tables, form, img, inline elements (Ex:
a
,span
). - The Shadow DOM can be attached to any HTML tag. However, attaching it to one of these elements may not make sense and lead to displacements.
- Need to dim the main portion upon hovering over certain tooltips, and upon showing autocomplete panel.
- Trigger the dimmed layer by creating and dispatching a custom event from the components to the
top-header
(parent) component.
- Declare a single
back-drop
component in the body. - Any component that needs a backdrop will have a reference to that
back-drop
component. - Set the desired position and height of the backdrop when in need.
- Approach
- Make
back-drop
reactive instead of passive.- i.e.
back-drop
activates/deactivates based on external events in components that useback-drop
but those components are unaware ofback-drop
.
- i.e.
- Make
- Steps
- Register custom events (
"showSelf"
,"hideSelf"
). - In
BackDrop
, loop through its listenables and for each listenable, add event listeners to those custom events (and while doing so, include its backdrop logic - activate/deactivate). - A
ComponentWithBackDrop
component dispatches the custom event to itself when needed -->BackDrop
activates/deactivates based on the custom event that occured in itself.ComponentWithBackDrop
components are unaware ofBackDrop
.
- Register custom events (
- Save all instances of
ComponentWithBackDrop
in a static property.- Use this static property to close all instances that are not currently being activated.
- Hence, at any point in time, there can only be one
ComponentWithBackDrop
that is showing. - No need to handle z-index anymore.
- When typing in Korean, the last character stays in "composing" state.
- The keyboard event fires twice when
isComposing
istrue
. - To prevent double firing, we can ignore the first event that was fired, which is when
isComposing
istrue
.- i.e. when the input is in "composing" state and the arrow key is pressed, two of the same events are fired. The first should be ignored and only the second should fall through.
- Possible approaches to map the options in the main menu to their corresponding sub menu.
- Assign ids, to begin with, in the original data.
- Use indices to assign ids in the fetched data.
- Side Bar data does not change often and the number of items is relatively small. Also, the ids are exclusively used for the UI. Therefore, there is really no other reason to assign ids in the data itself. Simply assign and use the indices once the data is fetched.
- To what extent and by what standard should components and/or logic be separated?
- Is it ideal to separate things that, when alteration is needed, alter together at the same time?
- Am I separating things that only really make sense to be used together?
- Think about the use cases of said components and logic rather than trying to separate everything just for the sake of separating or trying to blindly follow an architecture/pattern.
AutocompletePanel
requires some sort of input/form from the user that it will base its contents on.- This is provided by
SearchForm
and hence,AutocompletePanel
if needed, will be solely used forSearchForm
.
- This is provided by
- Therefore, consider
AutocompletePanel
an inherent part ofSearchForm
and focus on makingSearchForm
as reusable as possible.
SearchFormService
receives an endpoint and a default search term to handle the business logic (fetching, serialize/deserialize, current/previous search term comparison).AutocompletePanel
State- Search results - handled through
attributeChangedCallback
lifecycle.
- Search results - handled through
- Objective: build self-responsible modules that are focused on their own functionality rather than changing external state. —> Separation of Concerns
- Ex: whenever a
ComponentWithBackDrop
shows itself, activate the BackDrop component.- The position of the arrow’s tail represents the place of invocation.
- Traditionally, the arrow’s tail is directly at the source itself. However, in reactive programming, the arrow's tail is not directly at the source. The source is unaware that it is triggering the arrow, and hence, also unaware of the arrow's target.
BackDrop
.