3. Bouwen - RayanSp/Portfolio-Rayan GitHub Wiki

Popover target

Popover target is een attribuut die je kan toepassen om een hamburger menu te maken in je navbar. Het mooie hiervan is dat je enkel html en css nodig hebt om dit te realiseren, verder wordt dit sinds kort ondersteund op elke browser en zijn er geen nadelen op basis van accessibility en performance.

Dit is hoe ik het heb gebruikt:

  <nav popover role="menu" id="menu">
    <button class="close-btn" popovertarget="menu" popovertargetaction="hide">
      <svg
        xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        version="1.1"
        width="256"
        height="256"
        viewBox="0 0 256 256"
        xml:space="preserve"
      >
        <defs> </defs>
        <g
          style="stroke: none; stroke-width: 0; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: none; fill-rule: nonzero; opacity: 1;"
          transform="translate(1.4065934065934016 1.4065934065934016) scale(2.81 2.81)"
        >
          <path
            d="M 3 90 c -0.768 0 -1.536 -0.293 -2.121 -0.879 c -1.172 -1.171 -1.172 -3.071 0 -4.242 l 84 -84 c 1.172 -1.172 3.07 -1.172 4.242 0 c 1.172 1.171 1.172 3.071 0 4.242 l -84 84 C 4.536 89.707 3.768 90 3 90 z"
            style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: white; fill-rule: nonzero; opacity: 1;"
            transform=" matrix(1 0 0 1 0 0) "
            stroke-linecap="round"
          />
          <path
            d="M 87 90 c -0.768 0 -1.535 -0.293 -2.121 -0.879 l -84 -84 c -1.172 -1.171 -1.172 -3.071 0 -4.242 c 1.171 -1.172 3.071 -1.172 4.242 0 l 84 84 c 1.172 1.171 1.172 3.071 0 4.242 C 88.535 89.707 87.768 90 87 90 z"
            style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; fill: white; fill-rule: nonzero; opacity: 1;"
            transform=" matrix(1 0 0 1 0 0) "
            stroke-linecap="round"
          />
        </g>
      </svg>
    </button>
    <ul>
      <li><a href="#about" data-text="&nbsp;ABOUT">&nbsp;About&nbsp;</a></li>
      <li><a href="#skills" data-text="&nbsp;SKILLS">&nbsp;Skills&nbsp;</a></li>
      <li><a href="#work" data-text="&nbsp;MY WORK">&nbsp;My Work&nbsp;</a></li>
      <li><a href="/contact" data-text="&nbsp;CONTACT">&nbsp;Contact&nbsp;</a></li>
    </ul>
  </nav>
  <div class="overlay" id="overlay"></div>

Form enhancement

Voor mijn portfolio heb ik natuurlijk ook een contact formulier gemaakt. Deze heb ik helemaal enhanced met svelte en geoptimaliseerd met css. Verder heb ik mijn formulier ook gekoppeld aan een email server.

Hieronder staat de HTML van mijn formulier, zoals je kan zien maak ik gebruik van svelte enhancements en gebruik ik een svg loader die animeert als een formulier wordt verstuurd.

  <form
    method="POST"
    use:enhance={handleEnhance}
    on:submit={() => (isSubmitting = true)}
    class="contact-form"
  >
    <h1>Contact</h1>
    <fieldset class="form-wrapper">
      <label for="name" class="form-label"><span>Name</span></label>
      <input
        type="text"
        name="name"
        id="name"
        required
        placeholder="Your name..."
        class="input-field"
      />

      <label for="email" class="form-label"><span>Email</span></label>
      <input
        type="email"
        name="email"
        id="email"
        required
        placeholder="Your email..."
        class="input-field"
      />

      <label for="message" class="form-label"><span>Message</span></label>
      <textarea
        name="message"
        id="message"
        required
        placeholder="Your message..."
        class="input-field"
      ></textarea>
    </fieldset>

    {#if successMessage}
      <p class="success-message">{successMessage}</p>
    {/if}

    {#if errorMessage}
      <p class="error-message">{errorMessage}</p>
    {/if}

    <button type="submit" class="btn btn-primary" disabled={isSubmitting}>
      {#if isSubmitting}
      <Loader />
      {:else}
        Verstuur
      {/if}
    </button>
  </form>

Hieronder zie je hoe ik mijn formulier heb enhanced:

  import Header from "$lib/components/Header.svelte";
  import Loader from "$lib/components/svg/loader.svelte";
  import { enhance } from "$app/forms";

  let isSubmitting = false;
  let successMessage = "";
  let errorMessage = "";

  function handleEnhance({ formElement }) {
    const handleSubmit = async ({ result }) => {
      isSubmitting = false;
      successMessage = "";
      errorMessage = "";

      if (result.type === "failure") {
        errorMessage = result.data.error;
      } else if (result.type === "success") {
        formElement.reset();
        successMessage = result.data.message;
      }
    };
    return handleSubmit;
  }

View-transition-api

In mijn website maak ik ook gebruik van de view-transition-api, hieronder zie je hoe ik hier gebruik van maak:

In de code hieronder te zien zie je dat bij het navigeren tussen pagina's er een klein fade transition te zien is.

  import "../lib/style/global.css";
  import { onNavigate } from "$app/navigation";

  onNavigate((navigation) => {
    if (!document.startViewTransition) return;

    return new Promise((resolve) => {
      document.startViewTransition(async () => {
        resolve();
        await navigation.complete;
      });
    });
  });
</script>

Deze transition heb ik aangepast in css, dat is hieronder te zien:

::view-transition-old(root),
::view-transition-new(root) {
        animation-duration: 4s;
    } 

@keyframes fade-in {
  from { opacity: 0; }
}

@keyframes fade-out {
  to { opacity: 0; }
}

@keyframes slide-from-right {
  from { transform: translateX(80px); }
}

@keyframes slide-to-left {
  to { transform: translateX(-80px); }
}

::view-transition-old(root) {
  animation: 90ms cubic-bezier(0.4, 0, 1, 1) both fade-out,
    300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-to-left;
}

::view-transition-new(root) {
  animation: 210ms cubic-bezier(0, 0, 0.2, 1) 90ms both fade-in,
    300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-from-right;
} 

Web3forms

Zoals ik hierboven al had aangegeven werk ik met een email service zodat als het formulier wordt ingevuld, ik een mail ontvang. Met Web3Forms is dit goed te implementeren in svelte, hieronder zie je hoe ik dat heb gedaan:

    const payload = {
      access_key: "{ ACCES_KEY }",
      name: name,
      email: email,
      message: message,
    };

    try {
      const response = await fetch("https://api.web3forms.com/submit", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(payload),
      });

Website beveiliging

Ik ben naar Fatih toegegaan gezien ik geintresseerd was in wat hou nou precies allemaal heeft gedaan bij cybersecurity. Ik had namelijk wat gehoord over het beveiligen van je website of hoe je je website kan testen om uiteindelijk beter te beveiligen. Wij hebben toen een gesprek gehad over het beveiligen van je website. Hij liet toen zien dat je met bepaalde meta tags je website kan beveiligen.

Verder vertelde hij ook wat de functie was van elke meta tag, ik zet zie hieronder even op een rijtje:

Voorkomt dat browsers de MIME-type raden

  • < meta http-equiv="X-Content-Type-Options" content="nosniff" />

Blokkeert cross-domain verzoeken naar onze content

  • < meta http-equiv="X-Permitted-Cross-Domain-Policies" content="none" />

Verplicht het gebruik van HTTPS

  • < meta http-equiv="Strict-Transport-Security" content="max-age=31536000; includeSubDomains; preload" />

Verhindert dat referrer-informatie wordt gedeeld

  • < meta name="referrer" content="no-referrer" />

Blokkeert weergave van onze pagina's in frames of iframes

  • < meta http-equiv="X-Frame-Options" content="DENY"/>

Activeert de XSS-filter in browsers

  • < meta http-equiv="X-XSS-Protection" content="1; mode=block"/>

Beperkt de hoeveelheid referrer-informatie die wordt gedeeld

  • < meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin"/>

GitHub API

In mijn portfolio wil ik natuurlijk mijn 'frontend' werk laten zien. Hiervoor maak ik gebruik van de GitHub API, met de github api kan ik mijn repositories ophalen om die te vertonen op mijn website.

Standaard haal je wel gelijk alle repositories op, in mijn geval zijn dat er 60. Hier moest ik dus in code wat dingen aanpassen zodat hij alleen de repositories ophaalt die ik wil laten zien. Hieronder zie je hoe ik dat heb gedaan:

	// GitHub API variables
	const username = "RayanSp";
	const apiUrl = `https://api.github.com/users/${username}/repos?sort=updated&per_page=50`;
  
	// Store for repositories
	let repos = writable([]);
  
	onMount(async () => {
	  // Fetch and set repositories
	  try {
		const response = await fetch(apiUrl);
		let data = await response.json();
		data.sort((a, b) => b.stargazers_count - a.stargazers_count);
		repos.set(filterRepos(data));
	  } catch (error) {
		console.error("Error fetching repos:", error);
	  }
  <div class="cards">
	{#each $repos as repo}
	 
			<ul>
			  <li>⭐ {repo.stargazers_count}</li>
			  <li>👁️ {repo.watchers_count}</li>
			  <li>🍴 {repo.forks_count} |</li>
			  <li>💻 {repo.language}</li>
			</ul>
  
	
			<h3>
			  {repo.name}
			</h3>
  
			<p>
			  {repo.description || "No description available."}
			</p>
			<p>
			  <a href={repo.homepage} target="_blank"> Website </a>
			</p>
  
			<p><a href={repo.html_url} target="_blank"> GitHub</a></p>

	{/each}
  </div>

En dit is hoe ik specifiek bepaalde repositories ophaal:

	// Function to filter repositories based on specific names
	function filterRepos(repos) {
	  const specificRepos = [
		"vervoerregio-amsterdam",
	  ];
	  return repos.filter((repo) =>
		specificRepos.includes(repo.name.toLowerCase())
	  );
	}

Contact form

Hieronder is mijn formulier te zien:

Schermafbeelding 2024-06-10 om 12 36 44

Ik heb erg veel aanpassingen gedaan om mijn formulier zo goed mogelijk te maken, ik zal het hieronder even op een rijtje zetten:

  • Als alle inputs valid zijn, krijgt de button een kleur (standaard is hij grijs en niet klikbaar) zie code
  • Inputs krijgen een groene border als ze correct zijn ingevuld zie code
  • Bij het versturen van het formulier veranderd te button in een loader (animated svg) totdat het formulier is verzonden zie code
  • Er wordt een succesmessage gegeven aan de gebruiker zodra het formulier is verzonden zie code
  • Er wordt een error message gegeven aan de gebruiker als er iets mis is gegaan bij het versturen zie code
  • Als het formulier wordt verstuurd, komt dit aan in mijn mailbox door het gebruik van een email service. zie code

Hieronder laat ik even zien dat het werkt en dat ik daadwerkelijk een email binnen krijg: Schermafbeelding 2024-06-10 om 12 45 06

Schermafbeelding 2024-06-10 om 12 45 23
⚠️ **GitHub.com Fallback** ⚠️