diff --git a/Colors/index.css b/Colors/index.css
new file mode 100644
index 0000000..d80c1e6
--- /dev/null
+++ b/Colors/index.css
@@ -0,0 +1,33 @@
+body {
+ box-sizing: border-box;
+ margin: 0px;
+}
+.container {
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.btn {
+ background-color: transparent;
+ color: #343a40;
+ text-align: center;
+ vertical-align: center;
+ cursor: pointer;
+ font-weight: 400px;
+ font-size: 1rem;
+ line-height: 1.5;
+ border-radius: 5px;
+ padding: 10px;
+ display: inline-block;
+}
+
+.btn:focus {
+ box-shadow: 0 0 0 0.2rem rgb(52 58 64 / 50%);
+}
+
+.btn:hover {
+ background-color: #343a40;
+ color: white;
+}
diff --git a/Colors/index.html b/Colors/index.html
new file mode 100644
index 0000000..09c2c67
--- /dev/null
+++ b/Colors/index.html
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+ Colors
+
+
+
+
+
+
diff --git a/Colors/index.js b/Colors/index.js
new file mode 100644
index 0000000..5e92739
--- /dev/null
+++ b/Colors/index.js
@@ -0,0 +1,4 @@
+document.querySelector('.btn').addEventListener('click', () => {
+ const colorCode = '#' + Math.round(Math.random() * 0xffffff).toString(16)
+ document.querySelector('.container').style = `background-color: ${colorCode}`
+})
diff --git a/Hex colors gradient/index.html b/Hex colors gradient/index.html
new file mode 100644
index 0000000..2f398a9
--- /dev/null
+++ b/Hex colors gradient/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ Hex Colors
+
+
+
+
+
+
Click the button bellow to generate a random gradient hex color combination
+
+
+
+
+
+
diff --git a/Hex colors gradient/src/css/style.css b/Hex colors gradient/src/css/style.css
new file mode 100644
index 0000000..cc8d448
--- /dev/null
+++ b/Hex colors gradient/src/css/style.css
@@ -0,0 +1,74 @@
+body {
+ box-sizing: border-box;
+ font-family: 'Comfortaa', sursive;
+ margin: 0px;
+}
+
+.container {
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+}
+
+h1 {
+ text-transform: uppercase;
+}
+
+h2 {
+ text-transform: lowercase;
+}
+
+h1,
+h2 {
+ margin-bottom: 0.5rem;
+ font-weight: 500;
+ line-height: 1.2;
+ animation: change 5s infinite alternate;
+ padding: 50px;
+}
+
+@keyframes change {
+ 0% {
+ color: #ffffff;
+ }
+ 20% {
+ color: #cccccc;
+ }
+
+ 40% {
+ color: #999999;
+ }
+ 60% {
+ color: #666666;
+ }
+ 80% {
+ color: #333333;
+ }
+ 100% {
+ color: #ffffff;
+ }
+}
+
+.btn {
+ display: inline-block;
+ font-weight: 400;
+ font-size: 1rem;
+ border: 1px solid transparent;
+ border-radius: 0.25rem;
+ padding: 10px 20px;
+ cursor: pointer;
+ background-color: white;
+}
+
+.btn-light {
+ color: #212529;
+ background-color: #e2e6ea;
+ border-color: #dae0e5;
+ box-shadow: 0 0 0 0.2rem rgb(216 217 219 / 50%);
+}
+
+.btn:hover {
+ background-color: #e2e6ea;
+}
diff --git a/Hex colors gradient/src/js/App.js b/Hex colors gradient/src/js/App.js
new file mode 100644
index 0000000..1ccb0f9
--- /dev/null
+++ b/Hex colors gradient/src/js/App.js
@@ -0,0 +1,47 @@
+import Button from './Button.js';
+
+export default function App({$target}) {
+ const $background = document.createElement('h2');
+ $target.appendChild($background);
+
+ const selectRandomColor = () => {
+ return '#' + Math.round(Math.random() * 0xffffff).toString(16);
+ };
+
+ this.state = {
+ hexcode1: '#ffffff',
+ hexcode2: '#ffffff',
+ };
+
+ this.setState = (nextState) => {
+ this.state = nextState;
+ this.render();
+ };
+
+ new Button({
+ $target,
+ onClick: () => {
+ const nextHexCode = {
+ hexcode1: selectRandomColor(),
+ hexcode2: selectRandomColor(),
+ };
+ this.setState(nextHexCode);
+ },
+ });
+
+ this.render = () => {
+ const {hexcode1, hexcode2} = this.state;
+
+ $background.innerHTML = `
+ background: linear-gradient(to right,
+ ${hexcode1}
+ ,
+ ${hexcode2}
+ );
+ `;
+
+ document.querySelector('main').style = `background: linear-gradient(to right, ${hexcode1} , ${hexcode2}`;
+ };
+
+ this.render();
+}
diff --git a/Hex colors gradient/src/js/Button.js b/Hex colors gradient/src/js/Button.js
new file mode 100644
index 0000000..f307b22
--- /dev/null
+++ b/Hex colors gradient/src/js/Button.js
@@ -0,0 +1,18 @@
+export default function Button({$target, onClick}) {
+ const $submitButton = document.createElement('button');
+ $submitButton.id = 'submit';
+ $submitButton.className = 'btn';
+ $submitButton.textContent = 'Click Me';
+
+ $target.appendChild($submitButton);
+
+ let isInitialize = true;
+
+ $submitButton.addEventListener('click', (e) => {
+ if (isInitialize) {
+ $submitButton.className += ' btn-light';
+ isInitialize = false;
+ }
+ onClick();
+ });
+}
diff --git a/Hex colors gradient/src/main.js b/Hex colors gradient/src/main.js
new file mode 100644
index 0000000..1294ac3
--- /dev/null
+++ b/Hex colors gradient/src/main.js
@@ -0,0 +1,5 @@
+import App from './js/App.js';
+
+const $target = document.querySelector('#hex-colors');
+
+new App({$target});
diff --git a/README.md b/README.md
index 32b2d84..8e7c12a 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,14 @@
-# FE-JS-miniproject-study
\ No newline at end of file
+# 25 Beginner JavaScript Project Ideas
+## 규칙
+- 브랜치명은 JSmini_lia 형식으로 만들어 주세요.
+- 매주 주어진 양의 project를 완성 후 project 단위로 PR해 주세요!
+ - [Project1/리아] 프로젝트명
+ - 예) [Project1/리아] Colors
+
+## 1회차(~9/12)
+### Project 1 Colors
+
+### Project 2 Hex colors gradient
+
+### Project 3 Random quote generator
+
diff --git a/Random quote generator/index.html b/Random quote generator/index.html
new file mode 100644
index 0000000..1725179
--- /dev/null
+++ b/Random quote generator/index.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+ Quote Generator
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Random quote generator/src/css/index.css b/Random quote generator/src/css/index.css
new file mode 100644
index 0000000..7fd6ccd
--- /dev/null
+++ b/Random quote generator/src/css/index.css
@@ -0,0 +1,71 @@
+body {
+ box-sizing: border-box;
+ font-family: 'Comfortaa', sursive;
+ margin: 0px;
+}
+
+.container {
+ height: 100vh;
+ width: 100%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ background: radial-gradient(circle, #5181b0 200px, #605ea6, #6649a0);
+}
+
+.inner-quotes-container {
+ display: flex;
+ flex-direction: column;
+ flex-grow: 1;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ min-height: 400px;
+ width: 900px;
+ padding: 0 25px;
+ border-radius: 10px;
+ background-color: #f4edea;
+ border: 10px solid #06bdc1;
+ box-shadow: 0px 2px 6px 0px rgb(0 0 0 / 90%);
+}
+
+.btn {
+ display: inline-block;
+ font-weight: 400;
+ color: #212529;
+ text-align: center;
+ cursor: pointer;
+ vertical-align: middle;
+ background-color: transparent;
+ border: 1px solid transparent;
+ padding: 0.375rem 0.75rem;
+ font-size: 1rem;
+ line-height: 1.5;
+ border-radius: 0.25rem;
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
+}
+
+.btn-info {
+ margin: 30px;
+ color: #fff;
+ background-color: #17a2b8;
+ border-color: #17a2b8;
+}
+
+.btn-info:hover {
+ color: #fff;
+ background-color: #138496;
+ border-color: #117a8b;
+}
+
+.inner-quotes-container p {
+ font-size: 1.5rem;
+ color: black;
+}
+
+.inner-quotes-container h3 {
+ font-size: 2rem;
+ color: black;
+ font-family: 'Dancing Script', cursive;
+}
diff --git a/Random quote generator/src/js/App.js b/Random quote generator/src/js/App.js
new file mode 100644
index 0000000..eb51934
--- /dev/null
+++ b/Random quote generator/src/js/App.js
@@ -0,0 +1,32 @@
+import {request} from './api.js';
+import Button from './Button.js';
+import Quote from './Quote.js';
+
+export default function App({$target}) {
+ this.state = {
+ quote: '',
+ author: '',
+ };
+
+ this.setState = (nextState) => {
+ this.state = nextState;
+ this.render();
+ };
+
+ const quote = new Quote({
+ $target,
+ initialState: this.state,
+ });
+
+ new Button({
+ $target,
+ onClick: async () => {
+ const randomQuote = await request('');
+ this.setState(randomQuote);
+ },
+ });
+
+ this.render = () => {
+ quote.setState(this.state);
+ };
+}
diff --git a/Random quote generator/src/js/Button.js b/Random quote generator/src/js/Button.js
new file mode 100644
index 0000000..8d058bf
--- /dev/null
+++ b/Random quote generator/src/js/Button.js
@@ -0,0 +1,15 @@
+export default function Button({$target, onClick}) {
+ const $quoteButton = document.createElement('div');
+ $quoteButton.className = 'quote-btn';
+ $target.appendChild($quoteButton);
+
+ this.render = () => {
+ $quoteButton.innerHTML = `
+
+ `;
+ };
+
+ this.render();
+
+ $quoteButton.addEventListener('click', onClick);
+}
diff --git a/Random quote generator/src/js/Quote.js b/Random quote generator/src/js/Quote.js
new file mode 100644
index 0000000..9b30834
--- /dev/null
+++ b/Random quote generator/src/js/Quote.js
@@ -0,0 +1,22 @@
+export default function Quote({$target, initialState}) {
+ const $quotes = document.createElement('div');
+ $quotes.className = 'inner-quotes-container';
+ $target.appendChild($quotes);
+
+ this.state = initialState;
+
+ this.setState = (nextState) => {
+ this.state = nextState;
+ this.render();
+ };
+
+ this.render = () => {
+ const {quote, author} = this.state;
+ $quotes.innerHTML = `
+ ${quote ? `"${quote}"` : ''}
+ ${author ? `-${author}` : ''}
+ `;
+ };
+
+ this.render();
+}
diff --git a/Random quote generator/src/js/api.js b/Random quote generator/src/js/api.js
new file mode 100644
index 0000000..465c993
--- /dev/null
+++ b/Random quote generator/src/js/api.js
@@ -0,0 +1,14 @@
+const API_END_POINT = 'https://free-quotes-api.herokuapp.com';
+
+export const request = async (url) => {
+ try {
+ const res = await fetch(`${API_END_POINT}${url}`);
+ if (!res.ok) {
+ throw new Error('API call fail');
+ }
+
+ return await res.json();
+ } catch (error) {
+ alert(error.message);
+ }
+};
diff --git a/Random quote generator/src/main.js b/Random quote generator/src/main.js
new file mode 100644
index 0000000..eacb67a
--- /dev/null
+++ b/Random quote generator/src/main.js
@@ -0,0 +1,5 @@
+import App from './js/App.js';
+
+const $target = document.querySelector('.quotes-container');
+
+new App({$target});