diff --git a/button.js b/button.js
new file mode 100644
index 0000000..95648e9
--- /dev/null
+++ b/button.js
@@ -0,0 +1,9 @@
+export default function ColorBtn ({ $target, onClick }) {
+ const colorBtn = document.createElement('button')
+ colorBtn.innerText = 'Pick Colors!'
+ $target.appendChild(colorBtn)
+
+ colorBtn.addEventListener('click', () => {
+ onClick()
+ })
+}
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..8739ec3
--- /dev/null
+++ b/index.html
@@ -0,0 +1,13 @@
+
+
+
+ Colors
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/m2-gradient/app.js b/m2-gradient/app.js
new file mode 100644
index 0000000..cc20a49
--- /dev/null
+++ b/m2-gradient/app.js
@@ -0,0 +1,45 @@
+import ClickBtn from "./button.js"
+import Detail from "./detail.js"
+
+export default function App ({ target }) {
+
+ const picker = () => {
+ const hexString = '0123456789abcdef'
+ const pickIndex = () => Math.floor(Math.random() * 16)
+ const hexColorCode = () => {
+ let temp = '#'
+ for (let i = 0; i < 6; i++){
+ const index = pickIndex()
+ temp += hexString[index]
+ }
+ return temp;
+ }
+ return hexColorCode();
+ }
+
+ const way = () => {
+ const ways = ['right', 'left']
+ const pickIndex = () => Math.floor(Math.random() * 2)
+ return ways[pickIndex()]
+ }
+
+ const detail = new Detail({
+ target,
+ initialState: {
+ way: 'right',
+ start: '#ffffff',
+ end: '#ffffff'
+ }
+ })
+
+ new ClickBtn({
+ target,
+ onClick: () => {
+ detail.setState({
+ way: way(),
+ start: picker(),
+ end: picker()
+ })
+ }
+ })
+}
\ No newline at end of file
diff --git a/m2-gradient/button.js b/m2-gradient/button.js
new file mode 100644
index 0000000..935cb15
--- /dev/null
+++ b/m2-gradient/button.js
@@ -0,0 +1,9 @@
+export default function ClickBtn ({ target, onClick }) {
+ const clickBtn = document.createElement('button')
+ clickBtn.innerText = 'Click Me'
+ target.appendChild(clickBtn)
+
+ clickBtn.addEventListener('click', () => {
+ onClick()
+ })
+}
\ No newline at end of file
diff --git a/m2-gradient/detail.js b/m2-gradient/detail.js
new file mode 100644
index 0000000..fa28f55
--- /dev/null
+++ b/m2-gradient/detail.js
@@ -0,0 +1,30 @@
+export default function Detail ({ target, initialState }) {
+ const detail = document.createElement('div')
+ target.appendChild(detail)
+
+ this.state = initialState
+ this.setState = (nextState) => {
+ this.state = nextState
+ this.render()
+ }
+
+ this.render = () => {
+ const { way, start, end } = this.state
+ document.body.style.background = `
+ linear-gradient(to ${way}, ${start}, ${end})
+ `
+
+ detail.innerHTML = `
+
+ CLICK THE BUTTON BELLOW TO GENERATE
+ A RANDOM GRADIENT HEX COLOR COMBINATION
+
+
+
+ background: linear-gradient(to ${way}, ${start}, ${end});
+
+ `
+ }
+
+ this.render()
+}
\ No newline at end of file
diff --git a/m2-gradient/index.html b/m2-gradient/index.html
new file mode 100644
index 0000000..bbdfea6
--- /dev/null
+++ b/m2-gradient/index.html
@@ -0,0 +1,13 @@
+
+
+
+
+ Hex Colors
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/m2-gradient/main.css b/m2-gradient/main.css
new file mode 100644
index 0000000..7861d5f
--- /dev/null
+++ b/m2-gradient/main.css
@@ -0,0 +1,48 @@
+main {
+ width: 98vw;
+ height: 98vh;
+ display: grid;
+ justify-content: center;
+ align-content: center;
+}
+
+div {
+ text-align: center;
+}
+
+.descript, .gradientColor {
+ width: 58vw;
+ font-size: 35px;
+ justify-self: center;
+ font-family:'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
+ -webkit-animation:colorchange 8s linear infinite alternate;
+}
+
+ @-webkit-keyframes colorchange {
+ 0% {
+ color: white;
+ }
+ 30% {
+ color: gray;
+ }
+ 60% {
+ color: darkgray;
+ }
+ 100% {
+ color: black;
+ }
+}
+
+button {
+ transition : all 0.5s ease;
+ border: none;
+ font-size: 1rem;
+ padding: 0.7rem;
+ border-radius: 5px;
+ justify-self: center;
+}
+
+button:hover {
+ cursor:pointer;
+ background-color: rgb(197, 196, 196);
+}
\ No newline at end of file
diff --git a/m2-gradient/main.js b/m2-gradient/main.js
new file mode 100644
index 0000000..3c25277
--- /dev/null
+++ b/m2-gradient/main.js
@@ -0,0 +1,5 @@
+import App from "./app.js"
+
+const target = document.querySelector('main')
+
+new App({ target })
\ No newline at end of file
diff --git a/m2-gradient/picker.png b/m2-gradient/picker.png
new file mode 100644
index 0000000..2cc6910
Binary files /dev/null and b/m2-gradient/picker.png differ
diff --git a/m3-quote/api.js b/m3-quote/api.js
new file mode 100644
index 0000000..d708bba
--- /dev/null
+++ b/m3-quote/api.js
@@ -0,0 +1,15 @@
+const API_URL = "https://free-quotes-api.herokuapp.com";
+
+export const request = async () => {
+ try {
+ const res = await fetch(API_URL);
+ const result = await res.json();
+
+ if (!res.ok) {
+ throw new Error("api error!");
+ }
+ return result;
+ } catch (error) {
+ console.log(error.message);
+ }
+};
diff --git a/m3-quote/app.js b/m3-quote/app.js
new file mode 100644
index 0000000..3a0e1e0
--- /dev/null
+++ b/m3-quote/app.js
@@ -0,0 +1,12 @@
+import GenerateBtn from "./button.js";
+import QuoteDetail from "./quotedetail.js";
+
+export default function App({ target }) {
+ const quoteDetail = new QuoteDetail({ target });
+ new GenerateBtn({
+ target,
+ onClick: () => {
+ quoteDetail.render();
+ },
+ });
+}
diff --git a/m3-quote/button.js b/m3-quote/button.js
new file mode 100644
index 0000000..be827f2
--- /dev/null
+++ b/m3-quote/button.js
@@ -0,0 +1,9 @@
+export default function GenerateBtn({ target, onClick }) {
+ const nextButton = document.createElement("button");
+ target.appendChild(nextButton);
+ nextButton.innerText = "▶";
+
+ nextButton.addEventListener("click", () => {
+ onClick();
+ });
+}
diff --git a/m3-quote/index.html b/m3-quote/index.html
new file mode 100644
index 0000000..ddbe7b0
--- /dev/null
+++ b/m3-quote/index.html
@@ -0,0 +1,15 @@
+
+
+
+ Quote Generator
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/m3-quote/main.css b/m3-quote/main.css
new file mode 100644
index 0000000..c5704bb
--- /dev/null
+++ b/m3-quote/main.css
@@ -0,0 +1,51 @@
+body {
+ font-family: "Times New Roman", Times, serif;
+ height: 98vh;
+ background: #80e5ff;
+ display: grid;
+ justify-content: center;
+ align-content: center;
+ align-items: center;
+}
+
+main {
+ width: 50vw;
+ height: 40vh;
+ border-radius: 37px;
+ background: linear-gradient(to right, #55ddff, #72ffec);
+ box-shadow: -31px 31px 62px #6dc3d9, 31px -31px 62px #93ffff;
+ padding: 150px 70px 70px 70px;
+ display: grid;
+ grid-template-rows: repeat(3, 1fr);
+ justify-content: center;
+ align-content: center;
+}
+
+.quote,
+.author {
+ width: 50vw;
+ text-align: center;
+ font-size: 3.4vh;
+ align-self: center;
+}
+
+.author {
+ font-size: 2.3vh;
+ font-style: italic;
+}
+
+button {
+ transition: all 0.2s ease-in-out;
+ background: transparent;
+ color: white;
+ border: none;
+ align-self: end;
+ justify-self: end;
+ text-align: center;
+ font-size: 3vh;
+}
+
+button:hover {
+ color: rgba(0, 47, 255, 0.644);
+ cursor: pointer;
+}
diff --git a/m3-quote/main.js b/m3-quote/main.js
new file mode 100644
index 0000000..50e9540
--- /dev/null
+++ b/m3-quote/main.js
@@ -0,0 +1,5 @@
+import App from "./app.js";
+
+const target = document.querySelector("main");
+
+new App({ target });
diff --git a/m3-quote/quote.png b/m3-quote/quote.png
new file mode 100644
index 0000000..6bc4302
Binary files /dev/null and b/m3-quote/quote.png differ
diff --git a/m3-quote/quotedetail.js b/m3-quote/quotedetail.js
new file mode 100644
index 0000000..8d25c5f
--- /dev/null
+++ b/m3-quote/quotedetail.js
@@ -0,0 +1,19 @@
+import { request } from "./api.js";
+
+export default function QuoteDetail({ target }) {
+ const quotearea = document.createElement("div");
+ const authorarea = document.createElement("div");
+ quotearea.className = "quote";
+ authorarea.className = "author";
+ target.appendChild(quotearea);
+ target.appendChild(authorarea);
+
+ this.render = async () => {
+ const randomQuote = await request();
+ const { quote, author } = randomQuote;
+ quotearea.innerText = `${quote.replace(/\uFFFD/g, "-")}`;
+ authorarea.innerText = `by. ${author.length > 0 ? author.replace(/\uFFFD/g, "-") : "Unknown"}`;
+ };
+
+ this.render();
+}
diff --git a/main.css b/main.css
new file mode 100644
index 0000000..93a11b5
--- /dev/null
+++ b/main.css
@@ -0,0 +1,30 @@
+body {
+ margin: 0;
+ padding: 0;
+ background-color: black;
+}
+
+main {
+ width: 98vw;
+ height: 98vh;
+ display: grid;
+ justify-content: center;
+ align-content: center;
+}
+
+button {
+ transition : all 0.4s ease-out;
+ background: rgba(255, 255, 255, 0.342);
+ box-shadow: 0 4px 20px 0 rgba(0, 0, 0, 0.37);
+ backdrop-filter: blur( 20px );
+ border-radius: 10px;
+ border: 1px solid rgba( 255, 255, 255, 0.18 );
+ font-size: 20px;
+ padding: 5px 10px 5px 10px;
+ color: white;
+}
+
+button:hover {
+ background: rgba(14, 14, 14, 0.85);
+ cursor: pointer;
+}
\ No newline at end of file
diff --git a/main.js b/main.js
new file mode 100644
index 0000000..dc5ce90
--- /dev/null
+++ b/main.js
@@ -0,0 +1,30 @@
+import ColorBtn from "./button.js";
+
+const body = document.querySelector('body')
+const $target = document.querySelector('main')
+let egg = 0;
+
+const colorPicker = () => {
+ let targetColor = '#'
+ const hex = '0123456789abcdef'
+
+ const pickIndex = () => Math.floor( Math.random() * 16 );
+
+ for (let i = 0; i < 6; i++) {
+ const index = pickIndex();
+ targetColor += hex[index];
+ }
+
+ return targetColor;
+}
+
+new ColorBtn({
+ $target,
+ onClick: () => {
+ if (egg === 101) confirm("🎉 You've already clicked 100 times!\nDo you want to continue picking colors?")
+ const color = colorPicker();
+ console.log(color);
+ body.style.backgroundColor = color;
+ egg++;
+ }
+})
\ No newline at end of file
diff --git a/picker.png b/picker.png
new file mode 100644
index 0000000..2cc6910
Binary files /dev/null and b/picker.png differ