Portfolio - kosterm14/portfolio GitHub Wiki

Brainstormen

De laatste opdracht waarin ik alles heb laten zien wat ik in me had was mijn we love web website. Hier heb ik gebruik gemaakt van een parallax effect en verschillende scroll animaties doormiddel van GSAP Scrolltrigger en SVG paths.

Voor mijn portfolio wil ik hierop uitbreiden door weer GSAP Scrolltrigger te gebruiken en dit te koppelen met verschillende animaties. Ik had, toen het af was, bij mijn we love web website het gevoel te veel animaties gebruikt te hebben. Ik kon maar niet stoppen met alles animeren en dit zorgde er naar mijn gevoel voor dat het er een beetje onprofessioneel uit ging zien. Ik wil erop letten dat ik mijn portfolio minimalistisch houd om een professioneler gevoel over te brengen.

Een klasgenoot (Trisjan) heeft me een youtube kanaal genaamd Codegrid doorgestuurd waarin er heel veel prachtige animatie tutorials te vinden zijn. Ik ga hier gebruik van maken en meerdere van deze toepassen op mijn portfolio.

Ik denk eraan om de website te beginnen met een animatie om de aandacht te trekken. Hierna scroll je naar beneden en zie je de, met de GitHub API opgehaalde, repo's waarin je misschien van links naar rechts kan scrollen door een carrousel. Hier zet ik ook een zoekbalk voor als je specifiek iets zoekt. Ik wil graag mijn repo's een soort van embedded op de pagina hebben zodat je ze ook echt kunt zien in plaats van gewoon een titel description en link. Hierna eindig ik met een footer waarmee je me kan contacteren. Ik wil deze footer speciaal maken en niet een basic footer hebben die iedereen heeft dus daar moet ik ook wat voor bedenken.

Mijn website is dus opgedeeld in drie aparte secties:

  1. De landingspage met een animatie die de aandacht trekt
  2. De horizontal carousel waarin je door de GitHub repo's scrolt
  3. De unieke footer

De website

GSAP Installatie

Ik vond hier in de GSAP docs welke stappen ik moest nemen om te installeren wat ik nodig had. Ik begon door GSAP te installeren in de terminal.

npm install gsap

Ik importeer daarna GSAP en de ScrollTrigger plugin in een <script> tag

import { gsap } from "gsap";

import { ScrollTrigger } from "gsap/dist/ScrollTrigger";

Ten slot register ik de plugin om ervoor te zorgen dat het goed samen werkt met de GSAP core.

gsap.registerPlugin(ScrollTrigger);

<script>
    import { gsap } from 'gsap';
    import { ScrollTrigger } from 'gsap/dist/ScrollTrigger';

    gsap.registerPlugin(ScrollTrigger);
</script>

De tweens schrijf je uiteindelijk in de onMount (als je in svelte werkt)

Landingspage

Ik heb een tutorial gebruikt van het YouTube kanaal Codegrid. Deze tutorial was doorgestuurd door mijn klasgenoot Trisjan en zo vond ik ook dit kanaal. Ik heb doormiddel van deze tutorial en GSAP Scrolltrigger een animatie gemaakt waarmee je seamlessly kunt transitionen tussen tekst en een image.

Je doet dit doormiddel van een scrolltrigger op de website content die zich onder de letters bevind. Deze zelfde trigger zet je op 4 (2 voor de letters, 2 voor de img) tweens waarin je aangeeft dat de animatie start als de top van het element de top van de viewport raakt en end na 200%. Ook geef je een scrub 1 aan de tween waarmee je aangeeft dat de animatie mee moet bewegen met de scrollbar in plaats van gewoon 1x afspelen wat het by default zou doen.

ScrollTrigger.create({
    trigger: '.website-content',
    start: '-0.1% top',
    end: 'bottom bottom',
    onEnter: () => {
        gsap.set('.website-content', { position: 'absolute', top: '195%' });
    },
    onLeaveBack: () => {
	gsap.set('.website-content', { position: 'fixed', top: '0' });
    }
});

Ik maak 2 sections aan waarin ik de letters apart zet. Ik spel zo het woord portfolio uit.

<section class="letters">
    <div>p</div>
    <div>o</div>
    <div>r</div>
    <div>t</div>
</section>
<section class="letters">
    <div>f</div>
    <div>o</div>
    <div>l</div>
    <div>i</div>
    <div>o</div>
</section>

De tween hieronder is voor de letters zoals je ziet aan de classname. Letters:first-child zijn de eerste helft van de letters en letters:last-child de tweede helft. Deze tween zorgt ervoor dat de x positie en de scale aangepast worden als de trigger bereikt wordt. Dit wordt gedaan met een power2 ease in-out effect. Hierdoor krijg je het effect in de gif hieronder. Het enige verschil is dat de x waarde van de eerste letters positief is en de x waarde van de laatste letter negatief waardoor ze een andere kant op zullen gaan.

gsap.to('.header .letters:first-child', {
    x: () => -innerWidth * 3,
    scale: 10,
    ease: 'power2.inOut',
    scrollTrigger: {
        start: 'top top',
	end: `+=200%`,
	scrub: 1
    }
});

gsap.to('.header .letters:last-child', {
    x: () => innerWidth * 3,
    scale: 10,
    ease: 'power2.inOut',
    scrollTrigger: {
        start: 'top top',
	end: `+=200%`,
	scrub: 1
    }
});

Dit ziet er dan zo uit

letters

Na het animeren van de letters schrijf je tweens om de img te animeren. Ik heb clippy gebruikt om een square clip-path te maken om de img te hervormen. Clippy is een clip-path visualizer die ik ken doordat Cyd me dit had laten zien vorig schooljaar en dat was me bijgebleven. Deze square bepaalt hoeveel van de afbeelding zichtbaar is voor de gebruiker. Je rotate deze met een ease in-out effect terwijl je hem groter maakt waardoor de img achter de tekst steeds zichtbaarder wordt.

gsap.to('.img-holder', {
    rotation: 0,
    clipPath: 'polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)',
    ease: 'power2.inOut',
    scrollTrigger: {
        start: 'top top',
	end: '+=200%',
	scrub: 1
    }
});

gsap.to('.img-holder img', {
    scale: 1,
    ease: 'power2.inOut',
    scrollTrigger: {
        start: 'top top',
	end: '+=200%',
	scrub: 1
    }
});

Alles samen gaat er zo uit zien! (img is gewoon een placeholder)

portfolio landings page

(Als je goed oplet zie je de letter F nog op het scherm rechts. Ik ga dit moeten fixen)

Letter animatie

Ik heb doormiddel van twee arrays een animatie gemaakt waarin de letters van de eerste startarray cyclen door het alfabet naar de letters in het tweede array. De code hieronder maakt twee lege arrays aan, starttext en endtext. Deze twee arrays kun je doordat ik dit in een component heb gezet startwaardes geven maar hier komen we later op terug. De currenttext is wat uiteindelijk geanimeerd wordt naar targettext en deze zijn gelijk aan starttext en endtext.

In de code hieronder wordt gekeken welk ASCII karakter er nu is en welke het moet worden. Er wordt gekeken naar deze waarde en als het te laag is (het verkeerde karakter) wordt het +1 gedaan tot het karakter juist is. Als het te hoog is wordt het juist omlaag gedaan tot het juist is.

export let startText = '';
export let endText = '';
let currentText = Array.from(startText);
const targetText = Array.from(endText);
let intervals = [];

function startAnimation() {
    currentText.forEach((_, index) => {
        intervals[index] = setInterval(() => {
            let currentCharCode = currentText[index].charCodeAt(0);
            let targetCharCode = targetText[index].charCodeAt(0);
            if (currentCharCode < targetCharCode) {
                currentText[index] = String.fromCharCode(currentCharCode + 1);
            } else if (currentCharCode > targetCharCode) {
                currentText[index] = String.fromCharCode(currentCharCode - 1);
            } else {
                clearInterval(intervals[index]);
            }
            currentText = currentText.slice();
        }, 50 * (index + 1));
    });
}

Ik heb hier een component van gemaakt waarmee ik makkelijk de starttext en eindtext kan veranderen. In onderstaand voorbeeld cyclen de letters door het alfabet van aaaa aaaaa naar port folio maar deze waarden kunnen alles zijn wat je maar wilt. Dit zorgt ervoor dat je makkelijk de tekst aan kunt passen.

<section class="letters">
    <div><TextAnimation startText="aaaa" endText="port" /></div>
</section>
<section class="letters">
    <div><TextAnimation startText="aaaaa" endText="folio" /></div>
</section>

letters animation

De geanimeerde letters zorgen er om een of andere reden voor dat het bovenstaande voorbeeld niet scrollbaar is. Ik heb dit uiteindelijk gefixt maar nu heb ik het probleem dat de img veel lager begint dan de bedoeling was. Het hoort achter de letters te zijn zoals hierboven maar zoals hieronder te zien is komt de img pas als je al gescrollt hebt.

low ani

Ik ben er uiteindelijk achter gekomen waar het probleem lag. De img container hoort standaard een waarde van top: 0px te hebben tot de scrolltrigger geactiveerd werdt. Als de scrolltrigger actief was moest de top waarde 195% worden. Dit is hieronder nogmaals te zien. Het probleem was dat het nu altijd 195% was en dus de img standaard onder de text was in plaats van erachter. Ik heb de startwaarde veranderd om dit te fixen.

ScrollTrigger.create({
    trigger: '.website-content',
    start: '-0.1% top',
    end: 'bottom bottom',
    onEnter: () => {
        gsap.set('.website-content', { position: 'absolute', top: '195%' });
    },
    onLeaveBack: () => {
	gsap.set('.website-content', { position: 'fixed', top: '0' });
    }
});

landingspage final

Horizontal carousel

Mijn idee was om een carousel te maken waarin je horizontaal langs alle repo's kunt gaan. Als de gebruiker scrolt zal dit carousel vastgepint blijven en horizontaal meescrollen. Ik animeer dit carousel hierna om het wat extra kick te geven.

ScrollMagic Installatie

Ik heb ScrollMagic gebruikt om op een relatief simpele manier interactie met het carousel te animeren

Je installeert de ScrollMagic library door de volgende command in je terminal uit te voeren.

npm install scrollmagic

Naast de installatie van ScrollMagic moet je de library ook importeren. Dit doe je door de volgende regel in je script te zetten.

import ScrollMagic from 'scrollmagic';

Om dit te combineren met GSAP heb je hiernaast ook de ScrollMagic GSAP plugin nodig. Deze installeer je met dit command.

npm install scrollmagic-plugin-gsap

Deze importeer je hierna met dit command.

import { ScrollMagicPluginGsap } from 'scrollmagic-plugin-gsap';

Vergeet natuurlijk niet ook GSAP te installeren en importeren als je deze optie wil gebruiken. Ik heb hier een uitleg hoe je dat doet.

<script>
    import ScrollMagic from 'scrollmagic';
    import { ScrollMagicPluginGsap } from 'scrollmagic-plugin-gsap';

    import { gsap } from 'gsap';
</script>

Ik heb hier voorheen al mee gewerkt in mijn we love web website. Ik had toen met ScrollMagic een simpel carousel gemaakt en deze gepint zodat het op het scherm bleef als de gebruiker verder scrolde. Ik heb ervoor gezorgd dat de x posities van de elementen 20% naar links verschoven elke scroll zodat het volgende element in de carousel in beeld kwam. Zo leek het voor de gebruiker alsof het carousel meescrolde.

var controller = new ScrollMagic.Controller();

var horizontalSlide = new TimelineMax()
    .to(".timeline", 1, { x: "-20%" })
    .to(".timeline", 1, { x: "-40%" })
    .to(".timeline", 1, { x: "-60%" })
    .to(".timeline", 1, { x: "-80%" })

new ScrollMagic.Scene({
    triggerElement: ".timeline-container",
    triggerHook: 0.2,
    duration: "200%"
})
    .setPin(".timeline-container")
    .setTween(horizontalSlide)
    .addTo(controller);

Zo zag het er uiteindelijk uit

wlwscrollmagic2

In mijn portfolio wou ik dus ook zoiets doen. Dit heb ik geprobeerd met de volgende code. Hier was het de bedoeling dat je zoals hierboven horizontaal door het carousel kunt scrollen. Ik gaf de repo's een kleine animatie waar ze van scale 1.75 naar scale 0.5 gingen zodat ze kleiner werden als je langs ze ging.

    onMount(() => {
        const controller = new ScrollMagic.Controller();

        repos.forEach((slide, index) => {
            const tween = gsap.timeline()
                .to(repo, { scale: 1.75, x: 300 })
                .to(repo, { scale: 0.5, x: 0 });

            new ScrollMagic.Scene({
                triggerElement: repo,
                duration: '100%',
                triggerHook: 0.5
            })
                .setPin(".repo-container")
                .setTween(tween)
                .addTo(controller);
        });
    });

Jammer genoeg werkte dit na veel trial en error niet dus moest ik iets anders gaan zoeken.

Repo cards

Ik was aan het experimenteren met kleine cards waar ik mijn repo's in zou zetten. Deze zou de gebruiker kunnen selecteren om meer info over de repo te krijgen.

Dit zou er zo uitzien

repocards

Ik liep tegen heel veel issues aan zoals het heel moeilijk kunnen positioneren van de kaartjes. Ook na het sluiten van de kaartjes returnen ze niet naar hun oorspronkelijke positie. Ik heb het geprobeerd te verbergen voor de video maar je kunt in de video hierboven ook een beetje zien hoe de website shift door de kaartjes. Hiernaast zijn er zelfs nog meer issues.

Deze issues zijn de reden dat ik ervoor kies dit idee ook te laten vallen en weer iets anders ga zoeken.

Cyd's grid

Ik zat te scrollen op Cyd's portfolio website en kwam zo op haar twitter. Ik vond hier een tweet over een CSS only grid wat ze gemaakt heeft waarin ze foto's animeert. Ik heb de codepen bekeken en heb de keuze gemaakt dit als inspiratie te gebruiken om ook mijn repo's op een soortgelijke manier te weergeven.

Ik begin door een array te maken waarin ik een image 42 keer loop. Dit omdat ik 42 repo's heb op mijn github en een img wil voor elke repo.

<script>
    let images = ['img1.webp'];
    let repetitions = 42;
</script>

<section class="grid">
    {#each Array(repetitions) as _, i (i)}
        {#each images as image (image)}
            <div class="img">
                <button>
                    <img src={image} alt={`Image ${image}`} />
                </button>
            </div>
        {/each}
    {/each}
</section>

Ik zet hier Cyd's CSS op en het komt er dan zo uit te zien.

42 grid

Ik ga hier in plaats van deze placeholder images mijn repo's laten zien door mijn data op te halen met behulp van de GitHub api.

Data ophalen in VS Code

Met onderstaande code fetch ik alle public repos van mijn GitHub account kosterm14 doormiddel van de GitHub api url. Deze apiUrl is dezelfde url als degene die ik aan het testen was in Postman in mijn vooronderzoek in de analyse fase. Als iemand deze code zou willen gebruiken zouden ze alleen mijn GitHub naam moeten vervangen met hun eigen.

<script>
    import { onMount } from 'svelte';

    onMount(() => {
        const username = 'kosterm14';
	const apiUrl = `https://api.github.com/users/${username}/repos`;

	fetch(apiUrl)
		.then((response) => response.json())
		.then((repos) => {
			console.log(repos);
		});
});
</script>

Ik console.log de repos en krijg ze zo allemaal te zien.

Ik haal hierna alle repo.url's, repo.names en repo.descriptions op uit de array en zet ik deze in een unordered list.

Dit is wat je nu te zien krijgt op de website:

Het probleem is dat dit gewoon een lijst is met links die naar de GitHub pagina van de repo's verwijzen. Ik wil de repo's het liefst embedded op de website hebben. Ook heb ik 42 repo's op mijn GitHub maar dit laat er maar 30 zien.

Ik ben er, na wat googlen, achter gekomen dat de GitHub API automatisch pagination voor je doet en er expres maar 30 laat zien tenzij anders aangegeven. Ik heb de apiUrl query aangepast om er 50 te tonen door ?per_page=50 toe te voegen.

Footer

Ik heb op google wat websites bekeken om inspiratie op te doen voor een coole unieke footer en vond zo deze website. Ik wil dit effect ook maken voor mijn footer. Ik denk dat ik dit kan doen met een parallax.

footer parallax

Nieuw idee! Na een presentatie van Joost over forms heb ik besloten een form in mijn footer te zetten. Je kunt dan de footer in en uitklappen om deze form te verbergen of te laten zien.

Ik begon door een simpele, maar wel semantische, form te maken

<form action="">
	<fieldset>
        <h1>Leave a message:)</h1>
		<legend>Gegevens</legend>
		<label for="name">Name</label>
		<input type="text" required name="name" id="name" />

		<label for="email">Email</label>
		<input type="email" required name="email" id="email" />

        <legend>Opdracht</legend>
        <label for="text">Message</label>
        <textarea name="text" required id="text"></textarea>

        <button type="submit">Submit</button>
	</fieldset>
</form>

image

Popover

Ik heb de form wat styling gegeven en deze doormiddel van de popover API verborgen. Tijdens css day leerde ik wat de popover api was. Dit is hier een beetje gedocumenteerd.

Ik heb dit semantisch geprobeerd te doen zonder het gebruik van div's

<article>
    <button popovertarget="footer-popover">Leave a Message</button>
    <aside popover id="footer-popover">
        <form method="POST">
            <fieldset>
                <legend>Gegevens</legend>
                <h1>Leave a message:)</h1>
                
                <label for="name">Name</label>
                <input type="text" required name="name" id="name" />

                <label for="email">Email</label>
                <input type="email" required name="email" id="email" />

                <legend>Opdracht</legend>
                <label for="text">Message</label>
                <textarea name="text" required id="text"></textarea>

                <button type="submit">Submit</button>
            </fieldset>
        </form>
    </aside>
</article>

Zo heb je een knop die zich altijd rechtsonder het scherm bevind waarmee de gebruiker ten alle tijden een bericht achter kan laten.

Hygraph

Ik heb met hulp van Ivar mijn form gelinked met Hygraph. Dit is gedaan doormiddel van mutations.

Mutations zorgen ervoor dat je kunt interacten met content buiten Hygraph doormiddel van GraphQL. Bij het maken van een model in Hygraph wordt er automatisch een mutatie aangemaakt in je GraphQL schema. Mijn Hygraph model heet 'Message' dus mijn mutatie werd createMessage genoemd. Deze mutaties accepteren inputs die overeen komen met de inputs in je Hygraph. Dit zorgt ervoor dat ik de name, email en text waarden vanuit mijn form naar mijn Message model in Hygraph kan sturen.

Hieronder heb ik ook gebruik gemaakt van interpolation. Dit is een principe wat ik geleerd heb ik de Javascript club. Ik heb er hier een stukje over geschreven.

let name = formData.get("name");
let email = formData.get("email");
let text = formData.get("text");

const mutation = `
      mutation {
        createMessage(data: { name: "${name}", email: "${email}", text: "${text}"}) {
          id
          name
          email
          text
        }
      }
    `;

Hieronder is mijn schema in Hygraph te zien. Zoals je ziet heb ik de velden name, email en text. Dit komt overeen met de input velden in mijn form.

Na het verzenden van een message komen deze waarden in Hygraph te staan.

Progressive enhancement

Ik heb met behulp van de svelte docs mijn form progressively enhanced gemaakt. Ik heb dit gedaan doormiddel van form actions en de use:enhance svelte functionaliteit.

import { enhance } from '$app/forms';

<form method="POST" action="/animation" use:enhance>

</form>

use:enhance zorgt voor veel verschillende dingen. Het zorgt er onder anderen voor dat:

  • De pagina niet herlaad nadat het form gebruikt is
  • Het form, $page.form en $page.status geupdate worden als het formulier wel of juist niet successvol is
  • Het form element gereset wordt na gebruik

Hiernaast heb ik de use:enhance gecustomized door een aparte functie aan te roepen als de use:enhance gebruikt wordt. Deze handleForm functie zorgt ervoor er een loading state komt terwijl de formdata naar hygraph gepost wordt. na de 1000ms delay wordt het form geupdate en is de loading state uitgezet.

function handleForm() {
    loading = true;

    return async ({ result, update }) => {
        await setTimeout(() => {
	    update();

	    loading = false;
	}, 1000);
    };
}

<form method="POST" action="/animation" use:enhance={handleForm}>

</form>

Als er een error is bij het verzenden van de formdata krijgt de gebruiker daar feedback van

{#if form?.error}
    <p class="message fail">{form.message}</p>
{/if}

Ook als het goedgaat krijgt de gebruiker daar feedback van

{#if form?.success}
    <p class="message succes" class:active={form?.success}>
        Bedankt voor je bericht:)
    </p>
{/if}

Lighthouse

Ik heb een lighthouse test gedaan en kwam zo achter de stats van mijn portfolio:

  • Performance 91
  • Accessibility 84
  • Best practices 100
  • SEO 80

Ik heb actie genomen om dit te verbeteren en kwam zo op deze stats:

  • Performance 94
  • Accessibility 90
  • Best practices 100
  • SEO 91

Dit heb ik gedaan door bijvoorbeeld jpg's te vervangen door webp's, onnodige Javascript te verwijderen, contrast te verbeteren en labels te veranderen.

Validatie

Ik heb mijn HTML gevalideerd met de hulp van de W3C Markup Validation Service.

Ook heb ik mijn CSS gevalideerd met de W3C CSS Validation Service.

Ik heb de feedback die ik hieruit kreeg verwerkt in mijn code.

Responsive

Ik heb mijn portfolio responsive gemaakt doormiddel van mediaquery's. Hieronder zijn een paar te zien waar ik bijvoorbeeld de font size van een header verander of het aantal afbeeldingen per row aanpas zodat het beter past op mobiel formaat.

@media screen and (max-width: 768px) {
		h1 {
			font-size: 2rem;
		}
	}

@media screen and (max-width: 768px) {
		:root {
			--images-per-row: 1;
		}
	}

Zo ziet de website er dus uit op mobiel

mobiel port

Server side

Het ophalen van de repo data doe ik nu nog client side in een onMount in mijn +page.svelte.

<script>
import { onMount } from 'svelte';

onMount(() => {
    const username = 'kosterm14';
    const apiUrl = `https://api.github.com/users/${username}/repos?sort=updated&per_page=50`;

    fetch(apiUrl)
        .then((response) => response.json())
        .then((repos) => {
            repos.sort((a, b) => b.stargazers_count - a.stargazers_count);

        })

	.catch((error) => console.error('Error fetching repos:', error));
});
</script>

Ik heb dit server side gedaan door de volgende code in mijn +page.server.js te zetten:

export async function load() {
  const username = 'kosterm14';
  const apiUrl = `https://api.github.com/users/${username}/repos?sort=updated&per_page=50`;

  try {
    const response = await fetch(apiUrl);
    const repos = await response.json();

    repos.sort((a, b) => b.stargazers_count - a.stargazers_count);

    return {
      status: 200,
      props: {
        repos,
      },
    };
  } catch (error) {
    console.error('Error fetching repos:', error);
    return {
      status: 500,
      error: 'Failed to load repos',
    };
  }
}

Map/Filter

Maandag 22 april gaf Justus een minicursus over de map(), filter() en reduce() functies in Javascript. Dit past perfect bij wat ik wil bereiken in mijn portfolio!

Ik haal op dit moment alle repo's op uit mijn Github profiel. Ik wil map() en filter() gebruiken om alleen de beste repo's te laten zien.

Met map() kun je een nieuwe, maar aangepaste, kopie van je array aanmaken om zo data aan te passen en met filter() kun je door weer een nieuwe, maar aangepaste, kopie van je array te maken data filteren. Hieronder is de code die ik nu heb om de repo's op te halen.

const username = 'kosterm14';
const apiUrl = `https://api.github.com/users/${username}/repos?sort=updated&per_page=50`;

fetch(apiUrl)
    .then((response) => response.json())
    .then((repos) => {

Ik heb met filter() een kopie gemaakt van de huidige array om alleen de repo's te laten zien die minimaal 1 ster hebben. Ik heb dit gedaan door repos = repos.filter((repo) => repo.stargazers_count > 0); toe te voegen en hiermee te filteren op alle repo's met een stargazer_count groter dan 0.

const username = 'kosterm14';
const apiUrl = `https://api.github.com/users/${username}/repos?sort=updated&per_page=50`;

fetch(apiUrl)
    .then((response) => response.json())
    .then((repos) => {
        repos = repos.filter((repo) => repo.stargazers_count > 0);

Omdat ik de repo namen uit de Github API haal bevatten ze allemaal streepjes in plaats van spaties. Ik ga de map() functie gebruiken om dit te veranderen.

Ik heb met map() een kopie gemaakt van de huidige array waarin alle dashes vervangen zijn met spaties. Ik heb deze nieuwe array gebruikt om de data te weergeven.

const username = 'kosterm14';
const apiUrl = `https://api.github.com/users/${username}/repos?sort=updated&per_page=50`;

fetch(apiUrl)
    .then((response) => response.json())
    .then((repos) => {
        repos = repos.map((repo) => {
            return {
                ...repo,
		name: repo.name.replace(/-/g, ' ')
	    };
	});
	repos = repos.filter((repo) => repo.stargazers_count > 0);

Dit ziet er dan zo uit

Knelpunten

tijdens het maken van deze website

  • Documentatie: Ik documenteer echt veelste veel heb ik gemerkt. Ja, natuurlijk is het handig om grondig te documenteren en ik heb er ook echt veel aan. Ik heb bijvoorbeeld de GSAP uitleg van mijn oude wiki (mijn we love web) kunnen gebruiken om deze website te maken. Het documenteren van alles kost wel heel erg veel tijd die ik ook zou kunnen gebruiken om de code te verbeteren.
  • Te simpel: Voor ik begon aan deze opdracht was ik van plan om iets geweldigs neer te zetten. Hoewel ik opzich wel tevreden ben met wat ik gemaakt heb had ik meer van mezelf verwacht.
  • Oneindig werk: Je maakt een taak aan voor jezelf maar die taak blijkt veel groter dan verwacht en je bent er veel meer tijd aan kwijt. Zo voel je je heel onproductief terwijl je eigenlijk gewoon hard aan het werk bent voor je website.

Knelpunten

voor als ik ooit nog verder zou gaan met deze website

  • Planning: Ik heb voor dit project geen project board gebruikt en ik heb hier spijt van. Ik loop tegen tijdsdruk aan omdat ik de taken helemaal niet goed ingeplanned heb de eerste 7 weken. De laatste 3 weken van de sprint heb ik strict ingeplanned en dit heeft me echt super veel geholpen met het visualiseren van wat ik moet doen en het afkrijgen van taken.
  • Schetsen: Voor mijn we love web website had ik heel veel schetsen gemaakt en dit had me super veel geholpen om te visualiseren wat ik moest maken en hoe ik dat ging doen. Ik heb voor dit project nauwelijks geschetst en ik merk echt het verschil.

Mogelijke oplossingen

tijdens het maken van deze website

  • Documentatie: Ik moet, of minder gaan documenteren, of de documentatie simpeler maken. Het simpeler maken zie ik niet echt zitten maar op het gebied van minder documenteren kan ik wel nadenken. Zo kan ik bijvoorbeeld alleen de belangrijkste aspecten van de website documenteren in plaats van alles.
  • Te simpel: Ik moet realistischer zijn. Mijn website is helemaal niet te simpel. Ik ben nog aan het leren, ik moet niet de beste website op aarde van mezelf verwachten.
  • Oneindig werk: Voor het OBA teamproject had ik precies hetzelfde probleem en hier heb ik, na een gesprek met joost, de taken samen met mijn teamlid gemaakt en verdeeld in kleine hapbare taken. Dit helpt om realistisch en tijdsgebonden taken te maken die je ook echt af krijgt.

Mogelijke oplossingen

voor als ik ooit nog verder zou gaan met deze website

  • Planning: Ik denk dat het probleem hier is dat ik gewoon op gevoel zat te werken. Ik heb voor de drie twee weken van deze sprint een stricte planning gemaakt en dit heeft me echt onmens veel geholpen met het af krijgen van taken. Voor het teamproject werk ik met taken in een projectboard waarin ik ook goed kan plannen. Ik ga dit voor toekomstige individuele projecten ook toepassen vanaf nu.
  • Schetsen: Voor een toekomstig project ga ik weer, net als mijn we love web project, een grote prioriteit leggen op het schetsen.

Inspiratie

Data ophalen

Letter animatie

Repo's weergeven

Footer

⚠️ **GitHub.com Fallback** ⚠️