Coding Examples

Netmatters Client Section

Description

In the process of creating the Netmatters website facsimile the page's client section offered 2 challenges: The image has to change colour when hovered over, and the tooltip describing the client has to appear above the client's image when the image is being hovered over.

The solution that I used for the first challenge was using 2 images in the same div, where one of them is not displayed depending on whether or not the image's container is hovered over. See comments 1-3 in the code for more details.

The solution for the second challenge was solved by setting the position of the discription's container and arrow to absolute so it can be placed outside the flow of the page, extra width is added so the description can be fully displayed and the box has the correct dimensions and the "arrow" under the box is placed correctly by using transform: translateX to center it under the description. See code comments 4-8 for more details.


<!-- HTML ------------------------------------------------------------------------------------------------------------------>

<div class="client">
  <div class="client-descr-box">
    <div class="client-descr">
      <h3>Busseys</h3>
      <p>One of the UK's leading Ford dealerships.</p>
      <div class="arrow"></div>
    </div>
  </div>
  <a class="img-link" href="#">
    <img src="https://www.netmatters.co.uk/uploads/page/1/home-T5gi.jpg" alt="">
    <img src="https://www.netmatters.co.uk/uploads/page/1/home-gZQR.png" alt="">
  </a>
</div>

<!-- CSS ------------------------------------------------------------------------------------------------------------------>

<!-- 1. Makes it so that the second image (the coloured version of the logo) is not displayed -->
.img-link img:nth-child(2) {
  display: none;
}

<!-- 2. Makes it so that the second image (the coloured version of the logo) is displayed on :hover -->
.img-link:hover img:nth-child(2) {
  display: block;
}

<!-- 3. Makes it so that the first image (the grey version of the logo) is not displayed on :hover -->
.img-link:hover img:nth-child(1) {
  display: none;
}

<!-- 4. Displays the client's description box when the box' parent div is hovered over -->
.client:hover > .client-descr-box {
  display: block;
}

<!-- 5. Sets the description box to not show by default,
  its position to absolute so it can be made to appear above the actual client image,
  adds width so the description box has the right dimensions,
  and a margin at the bottom so there's room for the "arrow" at the bottom does not overlap the client image -->
.client-descr-box {
  display: none;
  bottom: 100%;
  left: -100px;
  right: -100px;
  position: absolute;
  margin-bottom: 50px;
}

<!-- 6. Sets the background, text alignment and colour,
   padding, margin and width for the client description -->
.client-descr {
  display: block;
  background: colours.$dark-grey;
  text-align: center;
  color: white;
  padding: 20px;
  max-width: 260px;
  margin: 0 auto;
}

<!-- 7. Sets the positon for the "arrow" that points to the client's image -->
.arrow {
  top: 100%;
}

<!-- 8. Sets the shape of the "arrow" element,
 the border-width dictates the shape of the arrow with 35px being the width of the top and 36px the sides of the triangle,
 its positon to absolute so it can be placed correctly outside the client image,
and the transform property makes it so the arrow is centered above its client image  -->
.arrow:after {
  content: "";
  display: inline-block;
  border-width: 35px 36px 0;
  border-color: #333645 transparent transparent;
  border-style: solid;
  position: absolute;
  left: 50%;
  top: 100%;
  transform: translateX(-50%);
}
  

Portfolio Typewriter Effect

Description

One of the tasks, that were part of my JavaScript learning process, was to add a typewriter effect to my portfolio's hero image.

I decided that in order to help become more proficient in JavaScript, I wanted to write my own typewriter script instead of using a pre-made plugin or code snippet.

After studying examples and analysing how exactly they work I decided on the above approach. The code is commented for a more detailed explanation of how it works.


// Declares the text to write
const text = [
  " I'm a Web Developer",
  " I'm a Software Developer",
  " I'm a Game Developer",
  " I'm a Designer"
];

// Declares counters for the typing effect, what sentence gets typed and set erasing to false, causing the script to type by default
let i = 0;
let textIndex = 0;
erasing = false;

function typeWriter(){

// Default state, erasing = false implicitly means typing = true
  if (erasing === false){
    // Checks if value of the counter i is lower the sentence's length, and if it is it will:
    if (i < text[textIndex].length) {
      // Adds letters to the element, where:
        // The i in charAt(i) stands for the number of the letter in the sentence
        // The i is increased by 1 so the script will type out the next letter
        // The script then waits 100ms before running again
      document.querySelector(".typewriterItem").textContent += text[textIndex].charAt(i);
      i++;
      setTimeout(typeWriter, 100);
    }
    // If the counter is not lower than the sentence, it will:
    else {
      // Set the erasing state to true, which will trigger the script to start deleting
      // Before proceeding, the script waits for 1 second
      erasing = true;
      setTimeout(typeWriter, 1000);
    }

  }
// Erasing state
  else if (erasing = true){
    // Checks if value of the counter i is is not 0, and if it is not it will:
    if (i !== 0) {
      // Removes letters from the element, where:
        // The i in slice(0, i) stands for the number of the last letter in the sentence
        // The i is decreased by 1 so the script will remove the next letter
        // The script then waits 100ms before running again
      document.querySelector(".typewriterItem").textContent = text[textIndex].slice(0, i);
      i--;
      setTimeout(typeWriter, 75);
    }
    // If the counter is 0, depending on the textIndex counter that tells what sentence to type out, it will:
    else {
      // Ïf the text array counter is 3 (the last sentence in the array) it will:
      if (textIndex === 3) {
          // Sets erasing to false, which will cause the script to start typing again
          // Waits 0.1 second
          // Sets the textIndex counter to 0, which will make the script type out the first sentence again
        erasing = false;
        setTimeout(typeWriter, 100);
        textIndex = 0;
      }
      // Ïf the text array counter is not 3 (the last sentence in the array) it will:
      else {
          // Sets erasing to false, which will cause the script to start typing again
          // Waits 0.1 second
          // Adds 1 to the textIndex counter, which will make the script type out the next sentence
        erasing = false;
        setTimeout(typeWriter, 100);
        textIndex++;
      }
    }
  }

}

// Runs the script when it's loaded in
typeWriter();
  

SQL Database Challenge

Description

In order to learn SQL I had to complete the SQL Database Challenge where I had to write a query that includes a sub query with formatted outputs that are sorted by a value.

We were given the choice of 3 databases and I picked a movie database that holds data on movies, their cast, director, genre, ratings and reviewers.

I used the following tables

Database Table Structure

The above image shows the structure of the database used for this project, and all the relations between the different datasets.

Master Table
mov_id mov_title mov_year mov_time mov_lang mov_dt_rel mov_rel_country
901 Vertigo 1958 128 English 1958-08-24 UK
902 The Innocents 1961 100 English 1962-02-19 SW
903 Lawrence of Arabia 1962 216 English 1962-12-11 UK
904 The Deer Hunter 1978 183 English 1979-03-08 UK
905 Amadeus 1984 160 English 1985-01-07 UK
906 Blade Runner 1982 117 English 1982-09-09 UK
907 Eyes Wide Shut 1999 159 English   UK
908 The Usual Suspects 1995 106 English 1995-08-25 UK
909 Chinatown 1974 130 English 1974-08-09 UK
910 Boogie Nights 1997 155 English 1998-02-16 UK
911 Annie Hall 1977 93 English 1977-04-20 USA
912 Princess Mononoke 1997 134 Japanese 2001-10-19 UK
913 The Shawshank Redemption 1994 142 English 1995-02-17 UK
914 American Beauty 1999 122 English   UK
915 Titanic 1997 194 English 1998-01-23 UK
916 Good Will Hunting 1997 126 English 1998-06-03 UK
917 Deliverance 1972 109 English 1982-10-05 UK
918 Trainspotting 1996 94 English 1996-02-23 UK
919 The Prestige 2006 130 English 2006-11-10 UK
920 Donnie Darko 2001 113 English   UK
921 Slumdog Millionaire 2008 120 English 2009-01-09 UK
922 Aliens 1986 137 English 1986-08-29 UK
923 Beyond the Sea 2004 118 English 2004-11-26 UK
924 Avatar 2009 162 English 2009-12-17 UK
926 Seven Samurai 1954 207 Japanese 1954-04-26 JP
927 Spirited Away 2001 125 Japanese 2003-09-12 UK
928 Back to the Future 1985 116 English 1985-12-04 UK
925 Braveheart 1995 178 English 1995-09-08 UK

The above table contains the main movie information, and connects directly or indirectly to all other tables by the mov_id key, where the other tables show detailed information.

Director Tables
Director Details
dir_id dir_fname dir_lname
201 Alfred Hitchcock
202 Jack Clayton
203 David Lean
204 Michael Cimino
205 Milos Forman
206 Ridley Scott
207 Stanley Kubrick
208 Bryan Singer
209 Roman Polanski
210 Paul Thomas Anderson
211 Woody Allen
212 Hayao Miyazaki
213 Frank Darabont
214 Sam Mendes
215 James Cameron
216 Gus Van Sant
217 John Boorman
218 Danny Boyle
219 Christopher Nolan
220 Richard Kelly
221 Kevin Spacey
222 Andrei Tarkovsky
223 Peter Jackson
Directors Table
dir_id mov_id
201 901
202 902
203 903
204 904
205 905
206 906
207 907
208 908
209 909
210 910
211 911
212 912
213 913
214 914
215 915
216 916
217 917
218 918
219 919
220 920
218 921
215 922
221 923

The Director Details table connects to the Director Table by dir_id, and the Director Table then connects to the master table by mov_id, the query joins them to the master table in the order they're shown.

Genre Tables
Genre Table
mov_id gen_id
922 1001
917 1002
903 1002
912 1003
911 1005
908 1006
913 1006
926 1007
928 1007
918 1007
921 1007
902 1008
923 1009
907 1010
927 1010
901 1010
914 1011
906 1012
904 1013
Genre Details
gen_id gen_title
1001 Action
1002 Adventure
1003 Animation
1004 Biography
1005 Comedy
1006 Crime
1007 Drama
1008 Horror
1009 Music
1010 Mystery
1011 Romance
1012 Thriller
1013 War

The Genre table contains genre IDs and connects to the master table through mov_id, the Genre Details table contains the genre titles, connected to the Genre table by gen_id. The query joins them to the master table in the order shown.

Movie Ratings Table
mov_id rev_id rev_stars num_o_ratings
901 9001 8.40 263575
902 9002 7.90 20207
903 9003 8.30 202778
906 9005 8.20 484746
924 9006 7.30  
908 9007 8.60 779489
909 9008   227235
910 9009 3.00 195961
911 9010 8.10 203875
912 9011 8.40  
914 9013 7.00 862618
915 9001 7.70 830095
916 9014 4.00 642132
925 9015 7.70 81328
918 9016   580301
920 9017 8.10 609451
921 9018 8.00 667758
922 9019 8.40 511613
923 9020 6.70 13091

The Ratings table contains data on ratings and reviews, it connects to the Master table through mov_id. The query places it at the very end of the results table.


<!-- Selects the following:
  movie title and year from the Master table,
  director first and last name, from the Director Details obtained through the Directors table and concatenated to display as a single value,
  genre title from the Genre Details table, obtained through the Genre table, and
  rating from the Movie Ratings table-->

  SELECT mov_title AS "Movie", mov_year AS "Year",
    CONCAT(director.dir_fname, director.dir_lname) AS "Director",
    genres.gen_title AS "Genre",
    rating.rev_stars AS "Stars (Rating)"
  FROM movie

<!-- Joins the tables in the following configuration:
  director - movie_direction - movie - movie_genres - genres - rating -->

  LEFT OUTER movie_direction ON movie_direction.mov_id = movie.mov_id
  LEFT OUTER director ON director.dir_id = movie_direction.dir_id
  LEFT OUTER movie_genres ON movie_genres.mov_id = movie.mov_id
  LEFT OUTER genres ON genres.gen_id = movie_genres.gen_id
  LEFT OUTER rating ON rating.mov_id = movie.mov_id

<!-- Filters the results to only display results where the movie's language is English,
  a subquery that filters for the movie's year of release being before 1990 -->

  WHERE movie.mov_lang = 'English'
    AND movie.mov_year IN (SELECT mov_year FROM movie WHERE mov_year < 1990)

<!-- Orders the results by movie title in an ascending order -->

  ORDER BY movie.mov_title ASC;
    

This SQL query joins the Director tables, Master table, Genre tables and Rating tables together. It then displays all movies where the language is English, were released before 1990 and are alphabetically ordered by title.

The results are displayed below:

Results Table
Movie Year Director Genre Stars (Rating)
Aliens 1986 James Cameron Action 8.40
Amadeus 1984 Milos Forman    
Annie Hall 1977 Woody Allen Comedy 8.10
Back to the Future 1985   Drama  
Blade Runner 1982 Ridley Scott Thriller 8.20
Chinatown 1974 Roman Polanski    
Deliverance 1972 John Boorman Adventure  
Lawrence of Arabia 1962 David Lean Adventure 8.30
The Deer Hunter 1978 Michael Cimino War  
The Innocents 1961 Jack Clayton Horror 7.90
Vertigo 1958 Alfred Hitchcock Mystery 8.40