Skip to content

🐦I learned to build the ninth website to duplicate the Twitter's function, and learned to organize the large project.

Notifications You must be signed in to change notification settings

shiuandai/Twitter-Clone

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Twitter-Clone

The twitter clone is my ninth project of Scrimba Front-End course, in this course I build the duplication of twitter from scratch and structure the code to finish the layout design.

PRs Welcome Join the chat at https://gitter.im/Front-End-Checklist/Front-End-Design-Checklist CC0

Table of Contents


The Twitter Clone is my ninth static website, building the small features step by step and make sure the code is easily to read.

I start the Scrimba Module 5 course- Essential JavaScript Concepts and learn how to use advanced JavaScript. At the end of the course, I follow the instruction to finish the Twitter Clone, take a look at the → Twitter Clone.

How I start the project?

  • Learn how to set the textarea for user to input their replies, and render the replies.
  • Insert the icons from the "Font Awesome CDN" website.
  • Increase & Decrease the number of the "likes" and "tweets" icons.
  • Change the color of icons when clicking.
  • Render the replies by getting their UUID, and improving the UX.

1. - Create a new tweet

Designing a twitter clone social media website requires following some rules and taking into consideration about each scrum tutorial. This project can be split into several small parts.

1.1 - Add the textarea

  • Take control of the data from Textarea when clicking button, then make sure the size of textarea fixed.

    ℹ️ [TEXTAREA] GET to know more about the element. → W3School

  • resize for textarea element.

textarea{
    border: none;
    padding: 10px;
    margin: 0 0 20px 0;
    height: 60px;
    width: 100%;
    font-size: 20px;
    line-height: 30px;
    resize: none;   //keeps textarea the same size
}

⬆ back to top

1.2 - For each method to iterate the array

Look through how to use .forEach() → .forEach()

const characters = [
    {
        title: 'Ninja',
        emoji: '🥷',
        powers: ['agility', 'jsstealth', 'aggression'],
    },
    {
        title: 'Sorcerer',
        emoji: '🧙',
        powers: ['magic', 'invisibility', 'necromancy'],
    },
    { 
        title: 'Ogre',
        emoji: '👹',
        powers: ['power', 'stamina', 'shapeshifting'],
    },  
    { 
        title: 'Unicorn',
        emoji: '🦄',
        powers: [ 'flight', 'power', 'purity'],
    }
]

characters.forEach(function(character){   //The purpose of using forEach is to make the code easy to read.
    console.log(character)
//The result shows below.
//{title: "Ninja", emoji: "🥷", powers: ["agility", "stealth", "aggression"]}
//{title: "Sorcerer", emoji: "🧙", powers: ["magic", "invisibility", "necromancy"]}
//{title: "Ogre", emoji: "👹", powers: ["power", "stamina", "shapeshifting"]}
//{title: "Unicorn", emoji: "🦄", powers: ["flight", "power", "purity"]}

⬆ back to top

2. - Control the icons

2.1 - CDN

Explaination why should we use CDN. → AWS The icon examples which we can get from here. → FONT-AWESOME-CDN

⚠️ The first step to use the CDN, copy code and paste the link into then paste “class” details into the section

<section class="icons-bar">
     <i class="fa-solid fa-house"></i>
     <i class="fa-solid fa-location-dot"></i>  //Get icon resource class name //Have to understand the concept of the data attribute.
     <i class="fa-regular fa-envelope"></i>
     <i class="fa-regular fa-calendar-days"></i>   //This is the example of how to use the data-attribute in the class.
</section>

⚠️ The defination of the Data Attribute: deta-unique-name="your data"

⬆ back to top

2.2 - Get value of data-attribute

document.addEventListener('click', function(e) {
		if (e.target.dataset.share){
    			console.log(e.target.dataset.share)   //output is image-1, review the code above,after clicking: output shows "image"
		}     //if return T then the data-share inside data element   //The output is DOMStringMap {share: "image-1"}
})

⬆ back to top

2.3 - Find the tweet obj and increase the like number

import { tweetsData } from './data.js'
const tweetInput = document.getElementById('tweet-input')
const tweetBtn = document.getElementById('tweet-btn')

tweetBtn.addEventListener('click', function(){
    console.log(tweetInput.value)
})

document.addEventListener('click', function(e){
    if(e.target.dataset.like){
       handleLikeClick(e.target.dataset.like) 
    }
})

function handleLikeClick(tweetId){
    const targetTweetObj = tweetsData.filter(function(tweet){
        return tweet.uuid === tweetId  //if the tweet id is the same of the loop id,then return true
    })[0]  //The output is object, not array
    targetTweetObj.likes++  //increase the like number when clicking
    console.log(tweetsData)
}

⬆ back to top

2.4 - Flip the boolean to control the like and dislike

//Make sure to listen to the button
document.addEventListener('click', function(e){
    if(e.target.dataset.like){
       handleLikeClick(e.target.dataset.like) 
    }

function handleLikeClick(tweetId){ 
    const targetTweetObj = tweetsData.filter(function(tweet){
        return tweet.uuid === tweetId
    })[0]

    if (targetTweetObj.isLiked){
        targetTweetObj.likes--
    }
    else{
        targetTweetObj.likes++ 
    }
    targetTweetObj.isLiked = !targetTweetObj.isLiked   //The goal is to flip the boolean.
    render()
}

⬆ back to top

2.5 - Conditionally Render CSS

const galleryContainer = document.getElementById('gallery-container')

let isLiked = false
let isShared = false

document.addEventListener('click', function(e){
    if(e.target.dataset.heart){
        isLiked = !isLiked  //flip the boolean short-hand
        render()
    }
    else if(e.target.dataset.share){
        isShared = !isShared  //flip the boolean short-hand
        render()
    }
})

function render(){ 
    
    let heartClass = ''  //initialize the variable
    let shareClass = ''
    
    if(isLiked){
        heartClass = 'liked'  //if "isLiked" is true then set up the Class to "liked"
    }
    
    if(isShared){
        shareClass = 'shared'   
    }
       
    let imageHtml = `
    		<div id="image-1" class="img-container">
			<img src="dino2.jpeg" alt="Man in front of dinosaur">
			<div class="social-icons-container">
				<i class="fa-solid fa-heart ${heartClass}" data-heart="image-1"></i>
				<i class="fa-solid fa-share ${shareClass}" data-share="image-1"></i>
			</div>
    `
    galleryContainer.innerHTML = imageHtml
}

render()
<section class="gallery-container" id="gallery-container">
</section>
.liked{
    color: #f80000; /* red */
}

.shared{
    color: limegreen; 
}

⬆ back to top

3. - Replies setup

3.1 - Get the UUID of replies

function getFeedHtml(){
    let feedHtml = ``
    
    tweetsData.forEach(function(tweet){  //loop through the object
        
        let likeIconClass = ''
        
        if (tweet.isLiked){
            likeIconClass = 'liked'
        }
        
        let retweetIconClass = ''
        
        if (tweet.isRetweeted){
            retweetIconClass = 'retweeted'
        }
        
        if(tweet.replies.length > 0){
            console.log(tweet.uuid)   //check the length of the tweet if there is any replies then output its UUID
        }
}

⬆ back to top

3.2 - Provide each reply unique UUID

import { v4 as uuidv4 } from 'https://jspm.dev/uuid'; //import the UUID JS 
  
const cars = [
    {
    brand: 'Nissan',
    model: 'Leaf',
    price: 3000,
    uuid: '4fb2b6b7-c7ee-4c80-8de1-390e89f43d7f'
    }, 
    {
    brand: 'Toyota',
    model: 'Prius',
    price: 6000,
    uuid: '82a13f62-d239-46a2-a94f-020189338e1a'
    }, 
] 

cars.push({
    brand: 'Tesla',
    model: 'Model S',
    price: '🤦‍♂️',
    uuid: uuidv4()  //Input function
})

console.log(cars)
<html>
    <head>
        <link rel="stylesheet" href="index.css">
    </head>
    <body>
        <script src="index.js" type="module"></script>  //setting to module
    </body>
</html>

⬆ back to top

3.3 - Push the new tweet to the dataset

function handleTweetBtnClick(){
    tweetsData.unshift({   //tweet the post in the beginning of the object
        handle: `@Scrimba`,
        profilePic: `images/scrimbalogo.png`,
        likes: 0,
        retweets: 0,
        tweetText: tweetInput.value,
        replies: [],
        isLiked: false,
        isRetweeted: false,
        uuid: uuidv4()
    })
    render()    
}

⬆ back to top

3.4 - Improve the UX

function handleTweetBtnClick(){
    const tweetInput = document.getElementById('tweet-input')
    if(tweetInput.value){       //If the value in the textarea exists then push the data into the array.
        tweetsData.unshift({
            handle: `@Scrimba`,
            profilePic: `images/scrimbalogo.png`,
            likes: 0,
            retweets: 0,
            tweetText: tweetInput.value,
            replies: [],
            isLiked: false,
            isRetweeted: false,
            uuid: uuidv4()
        })
    render()
    tweetInput.value = ''
    }
}

⬆ back to top


Author

Shiuan Dai

⬆ back to top

About

🐦I learned to build the ninth website to duplicate the Twitter's function, and learned to organize the large project.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published