diff --git a/calculator/cover.png b/calculator/cover.png new file mode 100644 index 0000000..58b6b36 Binary files /dev/null and b/calculator/cover.png differ diff --git a/calculator/index.html b/calculator/index.html new file mode 100644 index 0000000..1661d7e --- /dev/null +++ b/calculator/index.html @@ -0,0 +1,49 @@ + + + + + Simple Calculator - Practical JavaScript + + + +
+
+
+
+

0

+
+
+ +
+
+
+

C

+

%

+

x

+

1

+

2

+

3

+

-

+

4

+

5

+

6

+

/

+

7

+

8

+

9

+

+

+

0

+

.

+

=

+
+
+ +
+ + + diff --git a/calculator/script-solved.js b/calculator/script-solved.js new file mode 100644 index 0000000..55120b6 --- /dev/null +++ b/calculator/script-solved.js @@ -0,0 +1,78 @@ +// প্রয়োজনীয় সব ইলিমেন্ট সিলেক্ট করে নিন +const selectKeypad = document.querySelector('.keypad'); +const selectInput = document.querySelector('input[name=input]'); +const selectEqualBtn = document.querySelector('.btn-equal'); +const selectResult = document.querySelector('.result p'); + +// ইনপুট ডাটা +let data = ''; + +// ইনপুট ফিল্ডের চেঞ্জ ইভেন্ট +selectInput.addEventListener('change', (e) => { + // ইনপুট ফিল্ডের ইনপুট ডাটাতে স্টোর করে ফেলা + data = e.target.value; + // ডাটা অনুযায়ী ইকুয়্যাল বাটনের অবস্থা দেখা + equalBtnState(e.target.value); +}) + +// ক্যালকুলেটরের কীপ্যাড বাটনের ইভেন্ট, পুরোটা কীপ্যাডের উপ ইভেন্ট লাগানো হয়েছে +selectKeypad.addEventListener('click', (e) => { + // ইলিমেন্ট যদি বাটনই হয় তাহলে অ্যাকশন নেওয়া + if(e.target.tagName==='P') { + // আমাদের বাটনের কাজ অনুযায়ী ডাটা সেট করা + switch (e.target.textContent) { + case 'C': + // এই কেস হলে ডাটা ক্লিয়ার করা ফেলা + data = ''; + break; + case '=': + // এই কেস হলে ডাটাতে এটার কোনো ইফেক্ট পড়বে না + break; + case 'x': + // এই কেস হলে এটাকে আসল ম্যাথ অপারেটর * এ কনভার্ট করে ফেলা + data += '*'; + break; + case '%': + // এই কেস হলে মূল ক্যালকুলেশনের জন্যে তৈরী করে একটা এক্সপ্রেশন তৈরী করা + data += '/100*' + break; + default: + // বাই ডিফল্ট বাটনের ভ্যালু ডাটাতে অ্যাড করা + data += e.target.textContent; + } + // ইনপুট ফিল্ডে ডাটা দেখানো + selectInput.value = data; + + // ডাটা অনুযায়ী ইকুয়্যাল বাটনের অবস্থা দেখা + equalBtnState(selectInput.value); + } +}) + +// ইকুয়্যাল বাটনের ক্লিক হ্যান্ডেল করা +selectEqualBtn.addEventListener('click', () => { + // আগে শিউর হওয়া ইকুয়্যাল বাটন ডিসাবল না এনাবল + if(!selectEqualBtn.classList.contains('disabled')) { + // আমাদের ম্যাথমেটিক্যাল এক্সপ্রেশন তৈরী, এখন এটাকে ইভালিউট করা + const result = eval(data); + // এবার রেসাল্ট ইউজারকে দেখানো + selectResult.textContent = result; + } +}) + +// ইকুয়্যাল বাটনের অবস্থার ফাংশন +const equalBtnState = (value) => { + // ইনপুট ফিল্ডের ডাটা ভ্যালিডেট করা + if(validateInput(value)) { + // ইকুয়্যাল বাটন একমাত্র ইনপুট ক্যালকুলেট করার মতো হলেই ক্লিক এনাবল করা + selectEqualBtn.classList.remove('disabled'); + } else { + // নাইলে বাটন ডিসাবল করে রাখা + selectEqualBtn.classList.add('disabled'); + } +} + +// ইনপুট ভ্যালিডেট করা, ইনপুট ক্যালকুলেশন করার মতো কিনা +const validateInput = input => { + // রেগুলার এক্সপ্রেশন দিয়ে ইনপুট যাচাই + return (/^[-+]?[0-9\.]+?([-+*/x%]+[-+]?[0-9\.]+)*$/).test(input); +} diff --git a/calculator/script.js b/calculator/script.js new file mode 100644 index 0000000..bc23d40 --- /dev/null +++ b/calculator/script.js @@ -0,0 +1,72 @@ +// Write your code here +const selectKeypad = document.querySelector('.keypad'); +const selectInput = document.querySelector('input[name=input]'); +const selectEqualBtn = document.querySelector('.btn-equal'); +const selectResult = document.querySelector('.result p'); + +let data = ''; + +selectInput.addEventListener('change', (e) => { + // ইনপুট ফিল্ডের ইনপুট ডাটাতে স্টোর করে ফেলা + data = e.target.value; + // ডাটা অনুযায়ী ইকুয়্যাল বাটনের অবস্থা দেখা + equalBtnState(e.target.value); +}) + +selectKeypad.addEventListener('click', (e) => { + // ইলিমেন্ট যদি বাটনই হয়(যেখানে P ট্যাগ হচ্ছে বাটন) তাহলে অ্যাকশন নেওয়া + if(e.target.tagName==='P') { + // আমাদের বাটনের কাজ অনুযায়ী ডাটা সেট করা + switch (e.target.textContent) { + case 'C': + // এই কেস হলে ডাটা ক্লিয়ার করা ফেলা + data = ''; + break; + case '=': + // এই কেস হলে ডাটাতে এটার কোনো ইফেক্ট পড়বে না + break; + case 'x': + // এই কেস হলে এটাকে আসল ম্যাথ অপারেটর * এ কনভার্ট করে ফেলা + data += '*'; + break; + case '%': + // এই কেস হলে মূল ক্যালকুলেশনের জন্যে তৈরী করে একটা এক্সপ্রেশন তৈরী করা + data += '/100*' + break; + default: + // উপরের কোনো কেস না মিললে বাটনের ভ্যালু ডাটাতে অ্যাড করা + data += e.target.textContent; + } + // সবশেষে ইনপুট ফিল্ডে সেই ডাটা দেখানো + selectInput.value = data; + + // আবার ডাটা অনুযায়ী ডাটা অনুযায়ী ইকুয়্যাল বাটনের অবস্থা দেখা + equalBtnState(selectInput.value); + } +}) + +selectEqualBtn.addEventListener('click', () => { + // আগে শিউর হওয়া ইকুয়্যাল বাটন ডিসাবল না এনাবল + if(!selectEqualBtn.classList.contains('disabled')) { + // আমাদের ম্যাথমেটিক্যাল এক্সপ্রেশন তৈরী, এখন এটাকে ইভালিউট করা + const result = eval(data); + // এবার রেসাল্ট ইউজারকে দেখানো + selectResult.textContent = result; + } +}) + +const equalBtnState = (value) => { + // ইনপুট ফিল্ডের ডাটা ভ্যালিডেট করা + if(validateInput(value)) { + // ইকুয়্যাল বাটন একমাত্র ইনপুট ক্যালকুলেট করার মতো হলেই ক্লিক এনাবল করা + selectEqualBtn.classList.remove('disabled'); + } else { + // নাইলে বাটন ডিসাবল করে রাখা + selectEqualBtn.classList.add('disabled'); + } +} + +const validateInput = (input) => { + // রেগুলার এক্সপ্রেশন দিয়ে ইনপুট যাচাই + return (/^[-+]?[0-9\.]+?([-+*/x%]+[-+]?[0-9\.]+)*$/).test(input); +} diff --git a/calculator/style.css b/calculator/style.css new file mode 100644 index 0000000..b21de73 --- /dev/null +++ b/calculator/style.css @@ -0,0 +1,143 @@ +@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,900'); + +* { + box-sizing: border-box; + margin: 0; +} + +html, body { + margin: 0; + padding: 0; + line-height: 1; +} + +body { + min-height: 100vh; + width: 100%; + font-family: 'Roboto', sans-serif; + font-weight: 300; + text-align: center; + display: flex; + color: #333; + align-items: center; + background-image: url(cover.png); + background-color: #f2f2f2; + background-size: cover; + background-position: center; +} + +body>div { + flex: 1; +} + +.calculator { + width: 320px; + margin: 0 auto; + background: #fff; + border-radius: 4px; + box-shadow: 0 0 20px -10px rgba(0, 0, 0, 0.5); +} + +.display { + color: #4b4c4c; + padding: 30px 25px; + font-size: 42px; + text-align: right; + background-color: #efefef; +} + +.display .result { + overflow: hidden; +} + +.display .inputs input { + font-size: 22px; + font-weight: 900; + width: 100%; + background: transparent; + border: none; + text-align: right; + color: rgba(0, 0, 0, 0.5); + letter-spacing: 3px; + font-family: 'Roboto', sans-serif; + font-weight: 900; +} + +.keypad { + display: flex; + flex-wrap: wrap; + padding: 20px 10px; +} + +.keypad>p { + flex-basis: calc(100% / 4 - 30px); + margin: 10px 15px; + font-weight: 900; + padding: 15px 10px; + border-radius: 50px; +} + +.keypad .big { + flex: 2; + flex-basis: calc(100% / 3) +} + +.keypad .function { + background: #efefef; + box-shadow: 0 5px 13px -5px rgba(0, 0, 0, 0.5); +} + +.keypad .col-purple { + background: #9C27B0; + color: #fff; +} + +.keypad .col-orange { + background: #FF9800; + color: #fff; +} + +.keypad .col-deepgreen { + background: #1B5E20; + color: #fff; +} + +.keypad .col-red { + background-color: #F44336; + color: #fff; +} + +.keypad .col-green { + background: #4CAF50; + color: #fff; +} + + +.keypad .disabled { + cursor: not-allowed; + background: #E0E0E0; +} + +.copyright { + margin-top: 45px; +} + +.copyright ul { + margin: 0; + list-style: none; + padding: 0; +} + +.copyright ul li { + display: inline-block; + margin: 0 5px; + font-weight: 900; + font-size: 13px; +} + +.copyright ul li a { + text-decoration: none; + padding: 3px 8px; + border-radius: 4px; + background: #fff; +} diff --git a/index.html b/click-game/index.html similarity index 100% rename from index.html rename to click-game/index.html diff --git a/script-solved.js b/click-game/script-solved.js similarity index 100% rename from script-solved.js rename to click-game/script-solved.js diff --git a/click-game/script.js b/click-game/script.js new file mode 100644 index 0000000..69af50b --- /dev/null +++ b/click-game/script.js @@ -0,0 +1,56 @@ +// Write your code here +const stats = document.querySelector('.stats'); // যেখানে ক্লিকের কাউন্ট দেখাবে +const btnStart = document.querySelector('button[name=start]'); // স্টার্ট বাটন +const btnClick = document.querySelector('button[name=click]'); // ক্লিক বাটন + +const winScore = 10; // উইন স্কোর +let count = 0; // কাউন্ট করার ভ্যারিয়েবল + +btnStart.addEventListener('click', () => { + start(); +}); + +btnClick.addEventListener('click', () => { + // কাউন্ট এক করে বাড়ানো + count++; + // কাউন্টটা ইউআইতে দেখানো + stats.textContent = count; +}); + +const start = () => { + // কাউন্ট জিরোতে সেট করা + count = 0; + // এখন এই কাউন্টটাকে ইউআইতে দেখানো + stats.textContent = count; + // ক্লিক বাটন থেকে ডিসাবল্ড অবস্থা সরিয়ে ফেলা + btnClick.removeAttribute('disabled'); + // কাউন্ট শুরু করা + startCounting(); +} + +const startCounting = () => { + // সেট টাইম আউট ফাংশন ২ সেকেন্ড এর জন্যে অপেক্ষা করবে + setTimeout(() => { + // উইন হয়েছে দেখবো + if(isWin()) { + // উইন হলে উইনের টেক্সট দেখাবো + stats.textContent = 'You Won!'; + } else { + // উইন না হলে উইন হয়নি সে টেক্সট দেখাবো + stats.textContent = 'You Lost!'; + } + // ফলাফল দেখানো হয়ে গেলে ক্লিক বাটন ডিসাবল করে ফেলবো + btnClick.setAttribute('disabled', true); + }, 2000); +} + +const isWin = () => { + // স্কোর চেক করা + if(count < winScore) { + // কাউন্ট উইনস্কোর থেকে ছোটো হলে উইন হয়নি + return false; + } else { + // কাউন্ট উইনস্কোর থেকে বড় হলে উইন হয়েছে + return true; + } +} \ No newline at end of file diff --git a/style.css b/click-game/style.css similarity index 100% rename from style.css rename to click-game/style.css diff --git a/script.js b/script.js deleted file mode 100644 index b55091c..0000000 --- a/script.js +++ /dev/null @@ -1 +0,0 @@ -// Write your code here diff --git a/tip-calculator/cover.jpg b/tip-calculator/cover.jpg new file mode 100644 index 0000000..84ef43c Binary files /dev/null and b/tip-calculator/cover.jpg differ diff --git a/tip-calculator/index.html b/tip-calculator/index.html new file mode 100644 index 0000000..0fcb75e --- /dev/null +++ b/tip-calculator/index.html @@ -0,0 +1,50 @@ + + + + + Simple Tip Calculator - Practical JavaScript + + + +
+
+

Tip Calculator

+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+

Tip

+

BDT 0.00

+

Per Person

+
+
+

Total

+

BDT 0.00

+

Per Person

+
+
+
+ +
+ + + diff --git a/tip-calculator/script-solved.js b/tip-calculator/script-solved.js new file mode 100644 index 0000000..c5215bc --- /dev/null +++ b/tip-calculator/script-solved.js @@ -0,0 +1,51 @@ +// প্রয়োজনীয় সব ইলিমেন্ট সিলেক্ট করে নিন +const tipCalculator = document.querySelector('.tip-calculator'); +const selectTotal = document.querySelector('.amount_total span'); +const selectTipPerPerson = document.querySelector('.tip_per_person span'); + +// ডাটা স্ট্রাকচার, ইনপুট ফিল্ডের নামের সাথে মিল রেখে +const data = { + bill: 0, + tip: 0, + person: 1 +} + +// ইনপুট ভ্যালিডেট করা, ইনপুট আসলেই নাম্বার কিনা +const validateInput = input => { + return (/^\d+$/).test(input); +} + +// ফর্মের ইনপুট ফিল্ডে কোনোরকম পরিবর্তন আসলেই আমরা অ্যাকশন নিবো +tipCalculator.addEventListener('change', (e) => { + // ফর্মের ইনপুট ঠিক আছে কি নেই সেটার উপর ভিত্তি করে এখানে অ্যাকশন নিবো + if(validateInput(e.target.value)) { + // ইনপুট ঠিক থাকলে আমরা আমাদের এরর ক্লাসটা সরিয়ে নিবো ইনপুট থেকে + e.target.classList.remove('err'); + + // এখন আমরা আমাদের টার্গেগেটেড ইলিমেন্টটার ভ্যালু অ্যাসাইন করবো(এজন্যেই ডাটা স্ট্রাকচারের কীগুলোর নাম ইনপুট ফিল্ডের নামের সাথে মিল রেখেছি), আর সেই ভ্যালো যাতে ফ্লোট নাম্বার হয় সেটাও খেয়াল রাখবো + data[e.target.name] = parseFloat(e.target.value); + + // টোটাল টিপ কতো আসে সেটা হিসেব করা + const tip = (data.bill * data.tip) / 100; + + // টোটাল হিসেব করবো + let total = data.bill + tip; + // পার পার্সন হিসেব করা + total = total / data.person; + // টোটালটার দশমিককে ফিক্সড করে দেওয়া + total = total.toFixed(2); + // টোটালটা আমাদের ডকুমেন্ট এ শো করাবো + selectTotal.textContent = total; + + // পার পার্শনের টিপ কতো আসে সেটা হিসেব করা + let tip_per_person = tip / data.person; + // দশমিককে ফিক্সড করে দেওয় + tip_per_person = tip_per_person.toFixed(2); + // ডকুমেন্ট এ শো করানো + selectTipPerPerson.textContent = tip_per_person; + + } else { + // ইনপুট ভ্যালিড না হলে এরর ক্লাস লাগাবো ইউজারকে সুন্দর একটা ভুল হয়েছে ইফেক্ট দেওয়ার জন্যে + e.target.classList.add('err'); + } +}); diff --git a/tip-calculator/script.js b/tip-calculator/script.js new file mode 100644 index 0000000..b662155 --- /dev/null +++ b/tip-calculator/script.js @@ -0,0 +1,50 @@ +// Write your code here +const tipCalculator = document.querySelector('.tip-calculator'); +const selectTotal = document.querySelector('.amount_total span'); +const selectTipPerPerson = document.querySelector('.tip_per_person span'); + +const data = { + bill: 0, + tip: 0, + person: 1 +} + +tipCalculator.addEventListener('change', (e) => { + // ইনপুট ঠিক আছে কি নেই সেটার উপর ভিত্তি করে এখানে অ্যাকশন নিবো + if(validateInput(e.target.value)) { + // ইনপুট ঠিক থাকলে আমরা আমাদের এরর ক্লাস(যদি থাকে) সরিয়ে নিবো + // ইনপুট থেকে। এই অতিরিক্ত ক্লাসের সাহায্যে এরর থাকলে আমরা আলাদা + // সিএসএস দিয়ে স্টাইলিং করতে পারবো + e.target.classList.remove('err'); + + // এখন আমরা আমাদের টার্গেগেটেড ইলিমেন্টটার ভ্যালু অ্যাসাইন করবো + // (এজন্যেই ডাটা স্ট্রাকচারের কীগুলোর নাম ইনপুট ফিল্ডের নামের সাথে + // মিল রেখেছি), আর সেই ভ্যালো যাতে ফ্লোট নাম্বার হয় সেটাও খেয়াল রাখবো + data[e.target.name] = parseFloat(e.target.value); + // টোটাল টিপ কতো আসে সেটা হিসেব করবো + const tip = (data.bill * data.tip) / 100; + // টোটাল হিসেব করবো + let total = data.bill + tip; + // পার পার্সন হিসেব করবো + total = total / data.person; + // টোটালটার দশমিককে ফিক্সড করে দিবো + total = total.toFixed(2); + // টোটালটা আমাদের ডকুমেন্ট এ শো করাবো + selectTotal.textContent = total; + + // পার পার্শনের টিপ কতো আসে সেটা হিসেব করবো + let tip_per_person = tip / data.person; + // দশমিককে ফিক্সড করে দিবো + tip_per_person = tip_per_person.toFixed(2); + // ডকুমেন্ট এ শো করাবো + selectTipPerPerson.textContent = tip_per_person; + } else { + // ইনপুট ভ্যালিড না হলে এরর ক্লাস লাগাবো ইউজারকে সুন্দর একটা + // ভুল হয়েছে ইফেক্ট দেওয়ার জন্যে + e.target.classList.add('err'); + } +}); + +const validateInput = input => { + return (/^\d+$/).test(input); +} diff --git a/tip-calculator/style.css b/tip-calculator/style.css new file mode 100644 index 0000000..9a3a95f --- /dev/null +++ b/tip-calculator/style.css @@ -0,0 +1,124 @@ +@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,900'); + +* { + box-sizing: border-box; + margin: 0; +} + +html, body { + margin: 0; + padding: 0; + line-height: 1; +} + +body { + min-height: 100vh; + width: 100%; + font-family: 'Roboto', sans-serif; + font-weight: 300; + text-align: center; + display: flex; + align-items: center; + background: url(cover.jpg); + background-size: cover; + background-position: center; +} + +body>div { + flex: 1; +} + +.header h2 { + color: #fff; + margin-bottom: 25px; +} + +.calculator { + display: flex; + color: rgba(0, 0, 0, 0.75); + padding: 25px; + width: 600px; + margin: 0 auto; + border-radius: 4px; + background: #fff; +} + +.calculator>div, +.calculator>form { + flex: 1; + padding: 0 10px; +} + +.result { + align-self: center; +} + +.tip_per_person { + border-bottom: solid 1px rgba(255, 255, 255, 0.25); +} + +.result div { + padding: 15px 0; +} + +.result div p { + font-size: 18px; + text-transform: uppercase; +} + +.result div .amount_tip, +.result div .amount_total { + font-size: 36px; + font-weight: 900; + margin: 5px 0; +} + +input { + border: solid 2px rgba(0, 0, 0, 0.2); + padding: 15px 10px; + font-size: 15px; + width: 100%; + border-radius: 4px; +} + +input.err { + border: solid 2px #F44336; +} + +.input-group { + margin: 10px 0; +} + +.input-group label { + color: rgba(0, 0, 0, 0.75); + display: block; + text-align: left; + font-weight: 900; + text-transform: uppercase; + margin-bottom: 5px; +} + +.copyright { + margin-top: 45px; + color: #fff; +} + +.copyright ul { + margin: 0; + list-style: none; + padding: 0; +} + +.copyright ul li { + display: inline-block; + margin: 0 5px; + font-weight: 900; + font-size: 13px; +} + +.copyright ul li a { + text-decoration: none; + padding: 3px 8px; + border-radius: 4px; + background: #fff; +} diff --git a/to-do-list/cover.jpg b/to-do-list/cover.jpg new file mode 100644 index 0000000..86ab480 Binary files /dev/null and b/to-do-list/cover.jpg differ diff --git a/to-do-list/index.html b/to-do-list/index.html new file mode 100644 index 0000000..5ef3cc2 --- /dev/null +++ b/to-do-list/index.html @@ -0,0 +1,38 @@ + + + + + Simple To Do List - Practical JavaScript + + + +
+
+
+

To Do List

+
+ + +
+
+
+
    +
  • X7 minutes exercise
  • +
  • XBuy some chocolates
  • +
  • XMake a Project
  • +
  • XBuy a Jacket
  • +
  • XMath Homework
  • +
  • XStart React Native
  • +
+
+
+ +
+ + + diff --git a/to-do-list/script-solved.js b/to-do-list/script-solved.js new file mode 100644 index 0000000..1f64c7e --- /dev/null +++ b/to-do-list/script-solved.js @@ -0,0 +1,79 @@ +// প্রয়োজনীয় সব ইলিমেন্ট সিলেক্ট করে নিন +const selectItem = document.querySelector('.body ul'); +const selectForm = document.querySelector('.todo'); + +// আইটেমে ক্লিক করলে, ক্লিক হ্যান্ডেলারটা লাগিয়েছি আন-অর্ডার লিস্টের উপরে যাতে সবগুলো চাইল্ড লিস্টকে আমরা অ্যাক্সেস করতে পারি +selectItem.addEventListener('click', (e) => { + // আইটেমটটা লিস্ট হলেও অ্যাকশন নেওয়া হবে + if(e.target.tagName==='LI') { + // লিস্ট কি অলরেডি ডান করা আছে? + if(e.target.classList.contains('done')) { + // ডান করা লিস্টে ক্লিক করলে সেটা আন-ডান হয়ে যাবে + e.target.classList.remove('done'); + } else { + // ডান নাই এমন লিস্টে ক্লিক করলে সেটা ডান হবে + e.target.classList.add('done'); + } + } + + // লিস্টের ভিতরে রিমুভ বাটনে ক্লিক করা হয়েছে কিনা দেখার জন্যে + if(e.target.classList.contains('remove')) { + // রিমুভ বাটনে ক্লিক করা হলে সেটার প্যারেন্ট নোডে গিয়ে রিমুভ করে ফেলা + e.target.parentNode.remove() + } +}) + +// ফর্ম সাবমিশন হ্যান্ডেল করার জন্যে +selectForm.addEventListener('submit', (e) => { + // ফর্মের ডিফল্ট আচরণ বন্ধ করার জন্যে + e.preventDefault(); + // ইনপুট ফিল্ড থেকে ভ্যালুটা বের করে নিয়ে আসলাম + const input = e.target.task.value; + // ইনপুট ভ্যালিডেট করা হচ্ছে, ভ্যালিডেট ফাংশন দিয়ে + if(validateInput(input, e.target.task)) { + // ইনপুট ভ্যালিডেট হলে আমাদের লিস্টের প্রথম দিকে নতুন আইটেমটা ঢুকাবো নতুন আইটেমের একটা ফাংশন দিয়ে(পরে ডিফাইন করা হয়েছে) + selectItem.insertAdjacentElement('afterbegin', newItem(e.target.task.value)); + // সব কাজ শেষে ইনপুট ফিল্ড খালি করে ফেলা + e.target.task.value = ''; + } +}); + +// ইনপুট ভ্যালিডেট করা, ইনপুট ক্যালকুলেশন করার মতো কিনা +const validateInput = (input, element) => { + // ইনপুট ফিল্ডে ইনপুট আছে কিনা? + if(input) { + // ইনপুট ফিল্ডে ইনপুট থাকলে যদি এরর ক্লাস থাকে তাহলে সেটা সরিয়ে ফেলা, আর এরর ক্লাস না থাকলেও কোনো সমস্যা নাই + element.parentNode.classList.remove('error'); + // সত্য রিটার্ণ করা + return true; + } else { + // ইনপুট ফিল্ডে কোনো ইনপুট না থাকলে এরর ক্লাস অ্যাড করা + element.parentNode.classList.add('error'); + // মিথ্যা রিটার্ণ করা + return false; + } +} + +// নতুন আইটেম তৈরী করা +const newItem = (content) => { + // নতুন লিস্ট নেওয়া + const createAItem = document.createElement('li'); + // কন্টেন্টটা লিস্ট এর ভিতরে দেওয়া + createAItem.textContent = content; + // লিস্ট এ রিমুভ বাটন রিমুভ ফাংশনের সাহায্যে অ্যাড করা + createAItem.insertAdjacentElement('afterbegin', removeButton()); + // এবার নতুন এই ইলিমেন্ট রিটার্ণ করা + return createAItem; +} + +// রিমুভ বাটন তৈরী করা +const removeButton = () => { + // নতুন একটা ইলিমেন্ট বানানো + const createRemoveBtn = document.createElement('span'); + // ইলিমেন্ট এ রিমুভ এর ক্লাস লাগানো + createRemoveBtn.classList.add('remove'); + // ইলিমেন্ট এর ভিতরে ক্রস বাটন অ্যাড করা + createRemoveBtn.textContent = 'X'; + // এবার নতুন এই ইলিমেন্টটা রিটার্ন করা + return createRemoveBtn; +} diff --git a/to-do-list/script.js b/to-do-list/script.js new file mode 100644 index 0000000..d6d7a04 --- /dev/null +++ b/to-do-list/script.js @@ -0,0 +1,75 @@ +// Write your code here +const selectItem = document.querySelector('.body ul'); +const selectForm = document.querySelector('.todo'); + +selectItem.addEventListener('click', (e) => { + // আইটেমটটা লিস্ট হলেই অ্যাকশন নেওয়া হবে + if(e.target.tagName==='LI') { + // লিস্ট কি অলরেডি কমপ্লিট করা আছে? + if(e.target.classList.contains('done')) { + // কমপ্লিট করা লিস্টে ক্লিক করলে সেটা ইন- কমপ্লিট হয়ে যাবে + e.target.classList.remove('done'); + } else { + // কমপ্লিট নাই এমন লিস্টে ক্লিক করলে সেটা কমপ্লিট হবে + e.target.classList.add('done'); + } + } + + // লিস্টের ভিতরে রিমুভ বাটনে ক্লিক করা হয়েছে কিনা দেখার জন্যে + if(e.target.classList.contains('remove')) { + // রিমুভ বাটনে ক্লিক করা হলে সেটার প্যারেন্ট নোডে গিয়ে রিমুভ করে ফেলবো + e.target.parentNode.remove() + } +}) + +selectForm.addEventListener('submit', (e) => { + // ফর্মের ডিফল্ট আচরণ বন্ধ করবো + e.preventDefault(); + // ইনপুট ফিল্ড থেকে ভ্যালুটা বের করে নিয়ে আসবো + const input = e.target.task.value; + // ইনপুট ভ্যালিডেট করা হচ্ছে, ভ্যালিডেট ফাংশন দিয়ে যেটা একটা পরেই ডিফাইন করবো + if(validateInput(input, e.target.task)) { + // ইনপুট ভ্যালিডেট হলে আমাদের লিস্টের প্রথম দিকে নতুন আইটেমটা ঢুকাবো নতুন আইটেমের একটা ফাংশন দিয়ে যেটা আমরা পরে ডিফাইন করবো + selectItem.insertAdjacentElement('afterbegin', newItem(e.target.task.value)); + // সব কাজ শেষে ইনপুট ফিল্ড খালি করে ফেলবো + e.target.task.value = ''; + } +}); + +const validateInput = (input, element) => { + // ইনপুট ফিল্ডে ইনপুট আছে কিনা সেটা দেখবো + if(input) { + // ইনপুট ফিল্ডে ইনপুট থাকলে যদি এরর ক্লাস থাকে তাহলে সেটা সরিয়ে ফেলবো + element.parentNode.classList.remove('error'); + // এবং সত্য রিটার্ণ করবো + return true; + } else { + // ইনপুট ফিল্ডে কোনো ইনপুট না থাকলে এরর ক্লাস অ্যাড করবো + element.parentNode.classList.add('error'); + // এবং মিথ্যা রিটার্ণ করা + return false; + } +} + + +const newItem = (content) => { + // নতুন লিস্ট ইলিমেন্ট তৈরী করবো + const createAItem = document.createElement('li'); + // কন্টেন্টটা আমাদের তৈরীকৃত লিস্ট আইটেমে দিবো + createAItem.textContent = content; + // লিস্ট এর ভিতরে সবার আগে রিমুভ বাটন রিমুভ ফাংশনের সাহায্যে অ্যাড করবো, এই রিমুভ ফাংশন আমরা একটু পরেই ডিফাইন করবো + createAItem.insertAdjacentElement('afterbegin', removeButton()); + // এবার নতুন এই ইলিমেন্টটা রিটার্ণ করবো + return createAItem; +} + +const removeButton = () => { + // নতুন একটা span ইলিমেন্ট তৈরী করবো + const createRemoveBtn = document.createElement('span'); + // ইলিমেন্ট এ রিমুভ এর ক্লাস লাগাবো + createRemoveBtn.classList.add('remove'); + // ইলিমেন্ট এর ভিতরে একটা ক্রস বাটন অ্যাড করবো + createRemoveBtn.textContent = 'X'; + // এবার নতুন এই ইলিমেন্টটা রিটার্ন করবো + return createRemoveBtn; +} diff --git a/to-do-list/style.css b/to-do-list/style.css new file mode 100644 index 0000000..5153914 --- /dev/null +++ b/to-do-list/style.css @@ -0,0 +1,154 @@ +@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,900'); + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html, body { + margin: 0; + padding: 0; + line-height: 1; +} + +body { + min-height: 100vh; + width: 100%; + font-family: 'Roboto', sans-serif; + font-weight: 300; + text-align: center; + display: flex; + color: #333; + align-items: center; + background-image: url(cover.jpg); + background-color: #f2f2f2; + background-size: cover; + background-position: center; +} + +ul { + list-style: none; +} + +body>div { + flex: 1; +} + +.todolist { + background: #fff; + padding: 30px 15px; + width: 320px; + margin: 0 auto; + border-radius: 15px; + box-shadow: 2px 2px 15px -5px rgba(0, 0, 0, 0.5); +} + +.head h3 { + font-size: 26px; + text-transform: uppercase; + margin-bottom: 25px; + color: rgba(0, 0, 0, 0.5); +} + +.todo { + display: flex; + border-radius: 40px; + margin-bottom: 25px; + padding: 8px; + box-shadow: 0 0 30px -10px rgba(0, 0, 0, 0.5); +} + +.todo.error { + box-shadow: 0 0 30px -5px #F44336; +} + +.todo>* { + flex: 5; +} + +.todo input { + padding: 10px 15px; + font-family: 'Roboto', sans-serif; + border: none; + font-size: 16px; +} + +.todo input:focus { + outline: none; +} + +.todo button[name=submit] { + flex: 1; + background: #4CAF50; + font-size: 38px; + border: none; + cursor: pointer; + color: #fff; + border-radius: 40px; +} + +.remove { + visibility: hidden; + position: absolute; + left: 0; + display: inline-block; + background: #F44336; + color: #fff; + font-size: 13px; + padding: 2px 5px; + border-radius: 34px; + margin-right: 10px; + cursor: pointer; + transition: 0.2s all; +} + +.body ul { + padding: 0 20px; +} + +.body ul li { + position: relative; + font-size: 18px; + padding: 10px 0; + text-align: left; + transition: all 0.5s; +} + +.body ul li:hover { + padding-left: 30px; +} + +.body ul li:hover .remove { + visibility: visible; +} + +.body ul li.done { + color: rgba(0, 0, 0, 0.3); + text-decoration: line-through; +} + +.copyright { + margin-top: 45px; +} + +.copyright ul { + margin: 0; + list-style: none; + padding: 0; +} + +.copyright ul li { + display: inline-block; + margin: 0 5px; + font-weight: 900; + font-size: 13px; +} + +.copyright ul li a { + text-decoration: none; + padding: 3px 8px; + border-radius: 4px; + background: #333; + color: #fff; +}