Skip to content

kaas #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 88 additions & 80 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,112 +1,120 @@
# API @cmda-minor-web 2024 - 2025
Het web is een geweldige plek en de beschikbare technologieën ervan zijn vandaag de dag krachtiger dan ooit tevoren.
De kracht van het web ligt in het feit dat het een platform is dat voor iedereen beschikbaar is en dat het gebaseerd is
op open standaarden. De technologieën worden ontworpen en gespecificeerd op basis van consensus en zijn niet in handen
van één enkele entiteit.
# API

Desondanks zijn er veel mensen en bedrijven die vinden dat het internet niet voldoet aan hun behoeften. Dit blijkt uit
de pogingen van grote techbedrijven om hun eigen afgesloten ecosystemen te creëren. Ze streven hiermee naar controle over
zowel de gebruikerservaring als de gegenereerde data.
Maker: **Tymo Smids**

**In dit vier weken durende vak zullen we de kracht van het web ervaren en kijken hoe we (mobiele) web apps kunnen maken die
net zo aantrekkelijk zijn als native mobiele apps. We beginnen met het maken van een server-side gerenderde applicatie
waarbij we geleidelijk de gebruikerservaring verbeteren met relevante beschikbare web API's.**
Datum: *2025/03/25* - *2025/04/29*

[TLDR; hoe zet ik mijn project op?](#Inrichten-ontwikkelomgeving)
## Randvoorwaarden

## Doelen
- Minimaal een overzichts- en detailpagina;
- Gebouwd in TinyHTTP + Liquid;
- Minimaal een content API;
- Minimaal twee Web API's.

Na deze cursus zul je:
## Mijn project

- In staat zijn om een server-side gerenderde applicatie te maken.
- In staat zijn om een enerverende gebruikerservaring te creëren.
- Een breder begrip hebben van het web en zijn mogelijkheden.
De pagina's die ik heb zijn: een homepagina, detailpagina en een favorieten pagina. Het project is gebouwd in **TinyHTTP** en **Liquid** is de templating taal die is gebruikt. De **content API** die is gebruikt is de `MovieDB API`. De **Web API's** die gebruikt worden zijn: de `Localstorage API` en de `View transition API`.

## Opdracht
### Verbinden met de API

In dit vak zullen we een van de meest voorkomende app-concepten van vandaag
gebruiken en ontdekken dat we deze kunnen maken met moderne webtechnologie
met als doel om een rijke gebruikerservaring creëeren.
De API key is opgeslagen in het `.env` bestand. Dit bestand staat in de `.gitignore`. Dit zorgt ervoor dat de key veilig wordt opgeslagen want de bestanden in de .gitignore worden niet meegestuurd naar Github. Als dit niet wordt gedaan kan iedereen bij de api key en zelf request afvuren.

Randvoorwaarden:
```js
// ApiKey and URL for The Movie Database API
const apiKey = process.env.movieDB_APIKey;
const apiUrl = 'https://api.themoviedb.org/3/discover/movie';
```

- Minimaal een overzichts- en detailpagina
- Gebouwd in TinyHTTP + Liquid
- Minimaal een content API
- Minimaal twee Web API's
Als de `apiUrl` direct in de browser zou worden gezet krijg je een Json bestand terug. Dit bestand is ook wat je krijgt als je een `Fetch()` afvuurt.

Voorbeelden:
```js
const response = await fetch(movieDetailsUrl);
const item = await response.json();
```

- Maak je eigen streamingplatform (Netflix/Spotify).
- Maak je eigen doom-scroll-app (Instagram/TikTok).
- Maak je eigen chatapplicatie (WhatsApp/Signal).
- Een andere app die je zelf leuk vindt...
De data die je terugkrijgt kan je nu gebruiken om de website te vullen.

Voorbeeld content API's die je kan gebruiken:
```js
<article class="card">
<img class="card__image" id="movie_{{ item.id }}" style="view-transition-name: movie_{{ item.id }}"
src="https://image.tmdb.org/t/p/original{{ item.poster_path }}"
alt="{{ item.title }}"
title="{{ item.title }}"
loading="lazy"/>
<h2 class="h2">{{ item.title }}</h2>
</article>
```

- [MovieDB API](https://developer.themoviedb.org/reference/intro/getting-started)
- [Rijksmuseum API](https://data.rijksmuseum.nl/object-metadata/api/)
- [Spotify API](https://developer.spotify.com/documentation/web-api)
- ...
## Favorieten

Voorbeelden van Web API's die je kan gebruiken:
Om favorieten toe te voegen heb ik gebruik gemaakt van localstorage. Dit zorgt ervoor dat de films die worden toegevoegd aan de favorieten ook daar blijven tot deze worden verwijderd. Om naar de favorieten te gaan heb ik een link naar de favorieten pagina gemaakt zodat je een lijst hebt van je favorieten lijst.

- [Page Transition API voor animaties tusse npagina's](https://developer.mozilla.org/en-US/docs/Web/API/Page_Transitions_API)
- [Web Animations API voor complexe animaties](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API)
- [Service Worker API voor installable web apps](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API)
- [Web Push API voor push notifications](https://developer.mozilla.org/en-US/docs/Web/API/Push_API)
- [Server sent events voor realtime functionaliteit](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events)
- [Geolocation API](https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API)
- [Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API)
- [Web Share API voor sharen van content binnen de context van de gebruiker](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/share)
- ...
```js
// Pad naar de favorieten pagina
app.get('/favorites', async (req, res) => {
const ids = req.query.ids ? req.query.ids.split(',') : [];

De lijst is eindeloos, laat je vooral inspireren op de overzichtspagina van [MDN](https://developer.mozilla.org/en-US/docs/Web/API).
// Check of er geen favorieten zijn
if (!ids.length) {
return res.send(renderTemplate('server/views/favorites.liquid', {
title: 'Favorites',
items: []
}));
}

## Beoordeling
De beoordelingscriteria zijn te vinden op [DLO](https://dlo.mijnhva.nl/d2l/le/content/609470/Home)
const items = [];

## Planning
// Haal de de details op van de films met de opgegeven ids
for (const id of ids) {
const url = `https://api.themoviedb.org/3/movie/${id}?api_key=${apiKey}&language=en-US`;
const response = await fetch(url);
const movie = await response.json();

| Planning | Maandag | Dinsdag | Vrijdag |
|----------------------------|-----------------------|--------------------|---------------------------------------------|
| Week 1 - Kickoff & concept | Introductie ne uitleg | Workshops | Feedback gesprekken |
| Week 2 - The baseline | College + workshops | Workshops | Feedback gesprekken |
| Week 3 - Enhance | College + workshops | Workshops | Feedback gesprekken(*DONDERDAG*) |
| Week 4 - Enhance & wrap up | Tweede paasdag | Individuele vragen | Beoordelingsgesprekken(*DONDERDAG/VRIJDAG*) |
// voeg de films toe aan de items array
items.push(movie);
}

## Bronnen
// Render de template met de opgehaalde films
return res.send(renderTemplate('server/views/favorites.liquid', {
title: 'Favorites',
items
}));
});
```

- [Nodejs.org](https://nodejs.org/en/), voor de installatie van NodeJS op jouw systeem, kies voor NodeJS 22.13.1 Long Term Support. Dit is de meest stabiele versie van NodeJS, welke ondersteund wordt met goede documentatie.
- [VSCode How To Open Terminal](https://www.youtube.com/watch?v=OmQhOnBzg_k), om iemand de terminal te zien openen en gebruiken op Youtube.
- [Introduction to NodeJS](https://nodejs.dev/en/learn/), voor een in depth introductie met de NodeJS ontwikkelomgeving. Let op: dit is best een technisch verhaal. De eerste zes pagina’s zijn interessant.
- Om serverside te kunnen renderen maken we gebruik van [TinyHttp](https://github.com/tinyhttp).
- Voor templating maken we gebruik van [LiquidJS](https://liquidjs.com/).
- [Liquid Filters](https://liquidjs.com/filters/overview.html)
- Voor build tooling(CSS en JS) maken we gebruik [Vite](https://vitejs.dev/).
- [Using the Fetch API @ MDN](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
- [JSON.parse() @ MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse)
- [Partial commits in GitHub Desktop](https://github.blog/news-insights/product-news/partial-commits-in-github-for-windows/)
- [Committing and reviewing changes to your project in GitHub Desktop](https://docs.github.com/en/desktop/making-changes-in-a-branch/committing-and-reviewing-changes-to-your-project-in-github-desktop)
## Zoeken

## Inrichten ontwikkelomgeving
Om te kunnen zoeken wordt er getest of **search** in de URL zit. Als dit zo is wordt de API url veranderd zodat alle films worden opgehaald relevant zijn voor de zoekterm.

1. Navigeer naar [nodejs.org](https://nodejs.org/en/) en installeer de NodeJS ontwikkelomgeving. Kies voor _NodeJS 22.13.1 with long-term support_, download de benodigde bestanden en doorloop het installatieproces.
```js
const searchQuery = req.query.search;

2. Fork daarna [deze repository](https://github.com/cmda-minor-web/API-2425) en *clone* deze op jouw computer.
let apiUrl;

3. Open deze repository in je code editor.
// Als search in de URL zit
if (searchQuery) {
// Gebruik de zoekendpoint van de API
apiUrl = `https://api.themoviedb.org/3/search/movie?api_key=${apiKey}&language=en-US&page=${page}&query=${encodeURIComponent(searchQuery)}`;
} else {
// Standaard ontdekking API
const genreQuery = selectedGenre ? `&with_genres=${selectedGenre}` : '';
apiUrl = `https://api.themoviedb.org/3/discover/movie?api_key=${apiKey}&language=en-US&page=${page}&sort_by=${sort}${genreQuery}`;
}
```

4. Open de _Terminal_ in Visual Studio Code door de toetscombinatie `` ^` `` (control + `) te gebruiken. Er opent een terminalscherm in de hoofdmap van jouw project.
## CSS

5. Voer in de terminal het commando `npm install` uit, door het in te typen en op enter te drukken. Je gebruikt _NPM_, de _NodeJS Package Manager_ om alle _afhankelijkheden_ voor dit project te installeren. NPM is een veelgebruikte package manager in frontend land. Voor dit project gebruiken we _TinyHTTP_ (om een _server_ te maken) en _Liquid_ (om HTML te _renderen_).
- (Optioneel) Na de installatie is de map `node_modules` aangemaakt, en gevuld met allerlei _packages_. Scroll eens door deze map heen; vele honderden *open source* ontwikkelaars hebben de packages die je ziet gebouwd en die mag je gratis gebruiken. Ontwikkelen in NodeJS is *standing on the shoulders of giants*.
Alle `liquid` bestanden hebben een los CSS bestand zodat het compact en los van elkaar staat. De kaarten worden via een render template.

### Project starten en stoppen
Start het voorbeeldproject op door in de terminal het commando `npm run dev` uit te voeren. Als het goed is, komt een melding te staan over het opstarten van de server: `Server available on http://localhost:3000` — Open deze URL in je browser. Let op: Vite draait op een andere poort dan TinyHTTP, dus je moet de poort van TinyHTTP gebruiken: http://localhost:3000
Om de css die ik wil aanroepen voor elk bestand zet ik een algemene class die alleen voorkomt bij die pagina. Dit zorgt ervoor dat de css alleen wordt aangeroepen als dit nodig is.

Als het werkt, zet je je server weer uit door in de terminal de toetscombinatie `^c` (control + c) in te voeren. Deze toetsencombinatie wordt in de terminal gebruikt om de huidige taak te stoppen en *controle* (vandaar de c) terug te krijgen van het programma.
```css
/* Detail pagina */
.movieDetails {}
```

- Optioneel: Volg het [NodeJS ‘Hello World’ voorbeeld](https://medium.com/@mohammedijas/hello-world-in-node-js-b333275ddc89)
- Optioneel, iets technischer: Lees de eerste vijf delen van [Introduction to Node](https://nodejs.dev/en/learn/) als je een meer in-depth introductie wilt met de NodeJS ontwikkelomgeving.
## Link

[Link naar project](tymonl.github.io/API-2425/)

[Link naar website](https://api-2425-rpyo.onrender.com/)
31 changes: 31 additions & 0 deletions client/fonts.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* Light Weight */
@font-face {
font-family: "Poppins";
src: local("Poppins"), url("/fonts/Quicksand-Light.ttf") format("truetype");
font-weight: 300;
font-style: normal;
}

/* Regular Weight */
@font-face {
font-family: "Poppins";
src: local("Poppins"), url("/fonts/Quicksand-Regular.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}

/* Medium Weight */
@font-face {
font-family: "Poppins";
src: local("Poppins"), url("/fonts/Quicksand-Medium.ttf") format("truetype");
font-weight: 500; /* Medium weight */
font-style: normal;
}

/* Bold Weight */
@font-face {
font-family: "Poppins";
src: local("Poppins"), url("/fonts/Quicksand-Bold.ttf") format("truetype");
font-weight: bold;
font-style: normal;
}
56 changes: 53 additions & 3 deletions client/index.css
Original file line number Diff line number Diff line change
@@ -1,20 +1,70 @@
/* global styles */
@import 'reset.css';
@import "typography.css";
@import 'typography.css';
@import 'fonts.css';

/*.layout and view styling */
@import '../server/layouts/base.css';
@import '../server/views/index.css';
@import '../server/views/details.css';

/* component styling */
@import '../server/components/card/card.css';

html {
scroll-behavior: smooth;
}

body {
color: black;
max-width: 1440px;
color: #fff;
margin: 0 auto;
}

* {
box-sizing: border-box;
font-family: "Quicksand", sans-serif;
}

main {
padding: 1rem;
}

.container {
max-width: 1440px;
}

:root {
view-transition-name: root;
}

@view-transition {
navigation: auto;
}

html::view-transition {
animation-duration: 0.4s;
}

::view-transition-old(movie_*) {
opacity: 1;
}

::view-transition-new(movie_*) {
opacity: 0;
animation: fadeIn 0.5s ease forwards;
}

@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}

.fade-transition {
opacity: 1;
transition: opacity 0.4s ease-in-out;
}

.fade-transition.fade-out {
opacity: 0;
}

56 changes: 55 additions & 1 deletion client/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,57 @@
import './index.css';

console.log('Hello, world!');
document.querySelectorAll('.card_image').forEach(card => {
card.addEventListener('click', (e) => {
e.preventDefault();

const movieId = card.getAttribute('id');
const targetUrl = `/movies/${movieId}`; // adjust depending on your site

if (document.startViewTransition) {
document.startViewTransition(() => {
window.location.href = targetUrl;
});
} else {
window.location.href = targetUrl;
}
});
});

var favoritesLink = document.querySelector('.goToFavorites');

if (favoritesLink) {
favoritesLink.addEventListener('click', () => {
window.location.href = '/favorites'; // no query needed anymore
});
}

document.addEventListener('DOMContentLoaded', async () => {
const btn = document.querySelector('.addToFavorites');
if (!btn) return;

const id = btn.dataset.id;
const icon = btn.querySelector('i');
if (!id || !icon) return;

// Get current favorite status from server
const response = await fetch(`/api/favorites/${id}`);
const data = await response.json();

if (data.isFavorite) {
icon.classList.remove('fa-regular');
icon.classList.add('fa-solid');
}

btn.addEventListener('click', async () => {
const res = await fetch(`/api/favorites/${id}`, { method: 'POST' });
const result = await res.json();

if (result.status === 'added') {
icon.classList.remove('fa-regular');
icon.classList.add('fa-solid');
} else {
icon.classList.remove('fa-solid');
icon.classList.add('fa-regular');
}
});
});
3 changes: 2 additions & 1 deletion client/reset.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
v2.0 | 20110126
License: none (public domain)
*/

/*
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
Expand All @@ -23,6 +23,7 @@ time, mark, audio, video {
font: inherit;
vertical-align: baseline;
}
*/
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
Expand Down
1 change: 1 addition & 0 deletions favorites/favorites
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
["1197306","950387"]
Binary file added fonts/Quicksand-Bold.ttf
Binary file not shown.
Binary file added fonts/Quicksand-Light.ttf
Binary file not shown.
Binary file added fonts/Quicksand-Medium.ttf
Binary file not shown.
Binary file added fonts/Quicksand-Regular.ttf
Binary file not shown.
Binary file added fonts/Quicksand-SemiBold.ttf
Binary file not shown.
Binary file added images/noImage.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading