diff options
Diffstat (limited to 'htdocs/src/js')
| -rw-r--r-- | htdocs/src/js/app.js | 382 | ||||
| -rw-r--r-- | htdocs/src/js/config/projects.js | 224 | ||||
| -rw-r--r-- | htdocs/src/js/i18n/i18n.js | 42 | ||||
| -rw-r--r-- | htdocs/src/js/i18n/locales/en.js | 36 | ||||
| -rw-r--r-- | htdocs/src/js/i18n/locales/fr.js | 36 | ||||
| -rw-r--r-- | htdocs/src/js/utilities/animations.js | 45 | ||||
| -rw-r--r-- | htdocs/src/js/utilities/helpers.js | 19 |
7 files changed, 0 insertions, 784 deletions
diff --git a/htdocs/src/js/app.js b/htdocs/src/js/app.js deleted file mode 100644 index 38aee0e..0000000 --- a/htdocs/src/js/app.js +++ /dev/null @@ -1,382 +0,0 @@ -import projects from './config/projects'; -import { - translate, - setLocale, - currentLocale, - supportedLanguages, -} from './i18n/i18n'; -import { - hideToBottom, - hideToLeft, - showFromBottom, - showFromLeft, -} from './utilities/animations'; -import { isSmallVw, isStyleJsExists } from './utilities/helpers'; - -/** - * Show/hide header and footer with slide animation (left). - */ -function toggleHeaderFooter() { - const header = document.querySelector('header'); - const footer = document.querySelector('footer'); - const elements = [header, footer]; - - elements.forEach((el) => { - if (el.classList.contains('hide')) { - showFromLeft(el); - } else { - hideToLeft(el); - } - }); -} - -/** - * Show/hide project details with slide animation (bottom). - */ -function toggleProjectDetails() { - const details = document.querySelector('.project-details'); - - if (details.classList.contains('hide')) { - showFromBottom(details); - } else { - hideToBottom(details); - } -} - -/** - * Add an event listener to show or hide header and footer. - */ -function listenMenuBtn() { - const menuBtn = document.querySelector('.btn--menu'); - menuBtn.addEventListener('click', toggleHeaderFooter); -} - -/** - * Show or hide the project details button depending on current location. - */ -function toggleProjectDetailsBtn() { - const button = document.querySelector('.btn--details'); - const currentPath = window.location.hash; - - if (currentPath) { - button.style.display = ''; - } else { - button.style.display = 'none'; - } -} - -/** - * Update the visibility of some DOM elements depending on viewport. - */ -function updateView() { - const header = document.querySelector('header'); - const footer = document.querySelector('footer'); - const toolbar = document.querySelector('.toolbar'); - const details = document.querySelector('.project-details'); - - if (isSmallVw()) { - header.classList.add('hide'); - footer.classList.add('hide'); - toolbar.classList.remove('hide'); - details?.classList.add('hide'); - details?.classList.remove('fade-in'); - } else { - showFromLeft(header); - showFromLeft(footer); - toolbar.classList.add('hide'); - details?.classList.remove('hide'); - details?.classList.add('fade-in'); - } - - toggleProjectDetailsBtn(); -} - -/** - * Update view when the window size changes. - */ -function listenWindowSize() { - window.addEventListener('resize', updateView); -} - -/** - * Retrieve a project by id. - * @param {Integer} id - The project id. - * @returns {Object} The current project. - */ -function getCurrentProject(id) { - return projects.find((project) => project.id === id); -} - -/** - * Get a list item for the given repo. - * @param {String} name - The repository name. - * @param {String} url - The repository URL. - * @returns {HTMLElement} A list item. - */ -function getRepoItem(name, url) { - const item = document.createElement('li'); - const link = document.createElement('a'); - const span = document.createElement('span'); - span.classList.add('screen-reader-text'); - span.textContent = name; - link.classList.add('list__link', `list__link--${name.toLocaleLowerCase()}`); - link.href = url; - link.appendChild(span); - item.classList.add('list__item'); - item.appendChild(link); - return item; -} - -/** - * Get the repos list wrapped inside ul element and the title. - * @param {Object[]} repos - An array of repo with name and URL. - * @returns {[title, list]} An array of HTMLElements for title and list. - */ -function getRepos(repos) { - if (repos.length === 0) return []; - - const wrapper = document.createElement('div'); - const title = document.createElement('h3'); - const list = document.createElement('ul'); - const items = repos.map((repo) => getRepoItem(repo.name, repo.url)); - title.classList.add('project-details__title'); - title.textContent = translate('main.project.details.repo', { - count: repos.length, - }); - list.classList.add('list', 'list--repos'); - list.append(...items); - wrapper.append(title, list); - return [title, list]; -} - -/** - * Get the technologies list wrapped inside ul element and the title. - * @param {String[]} technologies - An array of technology names. - * @returns {[title, list]} An array of HTMLElements for title and list. - */ -function getTechs(technologies) { - if (technologies.length === 0) return []; - - const title = document.createElement('h3'); - title.classList.add('project-details__title'); - title.textContent = translate('main.project.details.tech', { - count: technologies.length, - }); - const list = document.createElement('ul'); - const items = technologies.map((technology) => { - const item = document.createElement('li'); - item.textContent = technology; - return item; - }); - list.classList.add('list', 'list--tech'); - list.append(...items); - return [title, list]; -} - -/** - * Retrieve the project details. - * @param {Object} project - The project. - * @returns {HTMLElement} The project details wrapped in a div. - */ -function getProjectDetails(project) { - const details = document.createElement('div'); - const title = document.createElement('h2'); - const techList = project?.technologies ? getTechs(project.technologies) : []; - const reposList = getRepos(project.repo); - const locale = currentLocale(); - let description; - - if (project.description) { - description = document.createElement('div'); - description.classList.add('project-details__description'); - description.textContent = project.description[locale] || ''; - } else { - description = ''; - } - - title.classList.add('project-details__title'); - title.textContent = translate('main.project.details.about', { - name: project.name, - }); - details.classList.add('project-details'); - if (!isSmallVw()) details.classList.add('fade-in'); - details.replaceChildren(title, description, ...techList, ...reposList); - - return details; -} - -/** - * Get an iframe for the given path/url. - * @param {String} src - The path/url to use as source. - * @returns {HTMLElement} The iframe. - */ -function getIframe(src) { - const iframe = document.createElement('iframe'); - iframe.src = src; - return iframe; -} - -/** - * Retrieve the project preview. - * @param {String} projectPath - The project path. - * @returns {HTMLElement} The project preview wrapped in a div. - */ -function getProjectPreview(projectPath) { - const preview = document.createElement('div'); - const iframe = getIframe(projectPath); - preview.classList.add('project-preview', 'fade-in'); - preview.replaceChildren(iframe); - return preview; -} - -/** - * Display the targeted project. - * @param {String} id - The project id. - */ -function showProject(id) { - const currentProject = getCurrentProject(id); - const main = document.querySelector('.main'); - const details = getProjectDetails(currentProject); - const preview = getProjectPreview(currentProject.path); - const detailsBtn = document.querySelector('.btn--details'); - - if (isSmallVw()) details.classList.add('hide'); - - detailsBtn.textContent = translate('main.project.details.about', { - name: currentProject.name, - }); - detailsBtn.addEventListener('click', toggleProjectDetails); - window.history.pushState({}, currentProject.name, `/#${id}`); - document.title = `${currentProject.name} | Demo | Armand Philippot`; - main.replaceChildren(preview, details); -} - -/** - * Add a CSS class to the current project in projects nav. - * @param {String} id - The project id. - */ -function setSelectedProject(id) { - const links = document.querySelectorAll('.nav__link'); - links.forEach((link) => { - if (link.id === id) { - link.classList.add('nav__link--selected'); - } else { - link.classList.remove('nav__link--selected'); - } - }); -} - -/** - * Create a list item for a project. - * @param {String} id - The project id. - * @param {String} name - The project name. - * @returns {HTMLElement} The list item. - */ -function getProjectsNavItem(id, name) { - const item = document.createElement('li'); - const link = document.createElement('a'); - link.classList.add('nav__link'); - link.href = `/#${id}`; - link.id = id; - link.textContent = name; - link.addEventListener('click', (e) => { - e.preventDefault(); - showProject(id); - setSelectedProject(id); - toggleProjectDetailsBtn(); - if (isSmallVw()) toggleHeaderFooter(); - }); - item.classList.add('nav__item'); - item.appendChild(link); - return item; -} - -/** - * Print the list of available projects. - */ -function printProjectsNav() { - const ul = document.querySelector('.nav .nav__list'); - - projects.forEach((project) => { - const item = getProjectsNavItem(project.id, project.name); - ul.appendChild(item); - }); -} - -/** - * Add style.js script for development purposes. - */ -function loadWebpackStyles() { - if (isStyleJsExists()) { - const head = document.querySelector('head'); - const script = document.createElement('script'); - script.src = 'assets/js/style.js'; - head.appendChild(script); - } -} - -/** - * Load corresponding project if the requested page contains a hash. - */ -function printRequestedPage() { - const currentPath = window.location.hash; - - if (currentPath) { - const id = currentPath.replace('#', ''); - showProject(id); - setSelectedProject(id); - } -} - -/** - * Replace the legal notice link and text. - */ -function replaceLegalNoticeLink() { - const link = document.querySelector('.nav__link--legal'); - link.href = translate('footer.legalNotice.link'); - link.textContent = translate('footer.legalNotice.txt'); -} - -/** - * Translate all text available in HTML templates. - */ -function translateHTMLContent() { - const brandingDesc = document.querySelector('.branding__description'); - const navLabel = document.querySelector('.nav__label'); - const license = document.querySelector('.copyright__license'); - const instructions = document.querySelector('.instructions'); - brandingDesc.textContent = translate('branding.description'); - navLabel.textContent = translate('nav.title'); - license.title = translate('footer.license'); - if (instructions) instructions.textContent = translate('main.instructions'); -} - -/** - * Translate the website according to the user preferred language. - */ -function setAppLocale() { - const preferredLanguage = navigator.language; - const supportedLanguage = supportedLanguages.find( - (lang) => preferredLanguage.startsWith(lang.code) - // eslint-disable-next-line function-paren-newline -- Conflict with Prettier - ); - const locale = supportedLanguage?.code || 'en'; - setLocale(locale); -} - -/** - * Initialize the website with the projects list. - */ -function init() { - setAppLocale(); - translateHTMLContent(); - replaceLegalNoticeLink(); - loadWebpackStyles(); - printProjectsNav(); - updateView(); - listenWindowSize(); - listenMenuBtn(); - printRequestedPage(); -} - -init(); diff --git a/htdocs/src/js/config/projects.js b/htdocs/src/js/config/projects.js deleted file mode 100644 index 53f1af8..0000000 --- a/htdocs/src/js/config/projects.js +++ /dev/null @@ -1,224 +0,0 @@ -const projects = [ - { - id: 'bin2dec', - name: 'Bin2Dec', - description: { - en: 'Convert a binary string to a decimal number.', - fr: 'Convertit un nombre binaire en un nombre décimal.', - }, - path: './projects/js-small-apps/bin2dec/index.html', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/bin2dec', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/bin2dec', - }, - ], - technologies: ['Vanilla Javascript'], - }, - { - id: 'budget-app', - name: 'Budget App', - description: { - en: 'By selecting a language in the initialization form, only the currency is converted (the app is not translated). Also, no data is saved on page reload.', - fr: "En sélectionnant une langue dans le formulaire d'initialisation, seul le format des nombres change (l'application n'est pas traduite). Aucune donnée n'est conservée après rechargement de la page.", - }, - path: './projects/js-small-apps/budget-app/index.html', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/budget-app', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/budget-app', - }, - ], - technologies: ['Vanilla Javascript'], - }, - { - id: 'calculator', - name: 'Calculator', - description: { - en: 'A basic calculator. Decimal part is limited to 3 digits. The first part is limited to 8 digits. If the result does not respect these limits, you will see an error.', - fr: 'Une simple calculette. La partie décimale est limitée à 3 chiffres. La première partie est limitée à 8 chiffres. Si le résultat ne respecte pas ces limites, vous verrez une erreur.', - }, - path: './projects/js-small-apps/calculator/index.html', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/calculator', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/calculator', - }, - ], - technologies: ['Vanilla Javascript'], - }, - { - id: 'clock', - name: 'Clock', - description: { - en: 'What time is it? You can have the current hour in three formats: an analogic clock, a numeric display or a text.', - fr: "Quelle heure est-il ? Vous pouvez voir l'heure actuelle dans trois formats différents : une horloge analogique, un affichage numérique et sous forme de texte.", - }, - path: './projects/js-small-apps/clock/index.html', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/clock', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/clock', - }, - ], - technologies: ['Vanilla Javascript', 'SVG'], - }, - { - id: 'color-cycle', - name: 'Color cycle', - description: { - en: 'Play with hexadecimal colors. Set a color, then choose one or more increment values and start the preview.', - fr: "Jouez avec les couleurs hexadécimales. Définissez une couleur, puis choisissez une ou plusieurs valeurs d'incrémentation et démarrez l'aperçu.", - }, - path: './projects/js-small-apps/color-cycle/index.html', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/color-cycle', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/color-cycle', - }, - ], - technologies: ['Vanilla Javascript'], - }, - { - id: 'css-border-previewer', - name: 'CSS Border Previewer', - description: { - en: 'Play with CSS borders (style, width, radius). Then, you can copy the generated code if the preview suits you.', - fr: "Jouez avec les bordures CSS (style, largeur, radius). Ensuite, vous pouvez copier le code généré si l'aperçu vous satisfait.", - }, - path: './projects/js-small-apps/css-border-previewer/index.html', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/css-border-previewer', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/css-border-previewer', - }, - ], - technologies: ['Vanilla Javascript'], - }, - { - id: 'meme-generator', - name: 'Meme Generator', - description: { - en: 'Choose a random image, set one or more texts then position them. Your meme is ready!', - fr: 'Choisissez une image aléatoire, définissez un ou plusieurs textes et positionnez-les. Votre meme est prêt !', - }, - path: './projects/react-small-apps/meme-generator/build/index.html', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/react-small-apps/tree/main/meme-generator', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/react-small-apps/-/tree/main/meme-generator', - }, - ], - technologies: ['React', 'Fetch'], - }, - { - id: 'notebook', - name: 'Notebook', - description: { - en: 'Create as many pages as you want and fill them. You can define a title and a body. Then you can easily navigate between your pages with the nav.', - fr: 'Créez autant de pages que vous le souhaitez et remplissez-les. Vous pouvez définir un titre et un corps de texte. Ensuite, vous pouvez facilement naviguer entre vos pages grâce à la navigation.', - }, - path: './projects/react-small-apps/notebook/build/', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/react-small-apps/tree/main/notebook', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/react-small-apps/-/tree/main/notebook', - }, - ], - technologies: ['React', 'React router'], - }, - { - id: 'rps-game', - name: 'Rock Paper Scissors', - description: { - en: 'A basic implementation of the game. Try to beat your friend or the computer.', - fr: "Une implémentation du jeu. Essayez de battre votre ami ou l'ordinateur.", - }, - path: './projects/js-small-apps/rock-paper-scissors/index.html', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/rock-paper-scissors', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/rock-paper-scissors', - }, - ], - technologies: ['Vanilla Javascript'], - }, - { - id: 'todos', - name: 'Todos', - description: { - en: 'You can add, remove or mark as done your todos. For each todos, you can add some details in addition to the title.\n\nLogin: demo@email.com\nPassword: demo', - fr: 'Vous pouvez ajouter, supprimer ou marquer comme fait vos "todo". Pour chaque "todo", vous pouvez ajouter des détails en plus du titre.\n\nLogin : demo@email.com\nMot de passe : demo', - }, - path: './projects/react-small-apps/todos/build/', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/react-small-apps/tree/main/todos', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/react-small-apps/-/tree/main/todos', - }, - ], - technologies: ['React', 'React router', 'Redux'], - }, - { - id: 'users-list', - name: 'Users list', - description: { - en: 'You can see a list of username. By clicking on it, the next column display information about the selected user.', - fr: "Vous pouvez voir une liste de noms d'utilisateur. En cliquant sur l'un d'eux, la colonne suivante affiche les informations à propos de cet utilisateur.", - }, - path: './projects/js-small-apps/users-list/index.html', - repo: [ - { - name: 'Github', - url: 'https://github.com/ArmandPhilippot/js-small-apps/tree/main/users-list', - }, - { - name: 'Gitlab', - url: 'https://gitlab.com/ArmandPhilippot/js-small-apps/-/tree/main/users-list', - }, - ], - technologies: ['Vanilla Javascript', 'Fetch'], - }, -]; - -export default projects; diff --git a/htdocs/src/js/i18n/i18n.js b/htdocs/src/js/i18n/i18n.js deleted file mode 100644 index 6bdc7cd..0000000 --- a/htdocs/src/js/i18n/i18n.js +++ /dev/null @@ -1,42 +0,0 @@ -import I18n from 'i18n-js'; -import en from './locales/en'; -import fr from './locales/fr'; - -const supportedLanguages = [ - { - code: 'en', - label: 'English', - translations: en, - }, - { - code: 'fr', - label: 'Français', - translations: fr, - }, -]; - -supportedLanguages.forEach((locale) => { - I18n.translations[locale.code] = locale.translations; -}); - -function setLocale(locale) { - I18n.locale = locale; -} - -function currentLocale() { - return I18n.currentLocale(); -} - -function translate(name, params = {}) { - return I18n.t(name, params); -} - -const { defaultLocale } = I18n; - -export { - supportedLanguages, - setLocale, - translate, - defaultLocale, - currentLocale, -}; diff --git a/htdocs/src/js/i18n/locales/en.js b/htdocs/src/js/i18n/locales/en.js deleted file mode 100644 index 9717528..0000000 --- a/htdocs/src/js/i18n/locales/en.js +++ /dev/null @@ -1,36 +0,0 @@ -const en = { - branding: { - description: 'Front-end developer', - }, - nav: { - title: 'Apps list:', - }, - main: { - instructions: - 'Select an app inside menu to see a live preview and app details (description, technologies, repositories).', - project: { - details: { - about: 'About {{name}}', - repo: { - one: 'Repository:', - other: 'Repositories:', - zero: 'Repositories:', - }, - tech: { - one: 'Technology:', - other: 'Technologies:', - zero: 'Technologies:', - }, - }, - }, - }, - footer: { - legalNotice: { - txt: 'Legal notice', - link: 'legal-notice.html', - }, - license: 'License MIT', - }, -}; - -export default en; diff --git a/htdocs/src/js/i18n/locales/fr.js b/htdocs/src/js/i18n/locales/fr.js deleted file mode 100644 index 9c93012..0000000 --- a/htdocs/src/js/i18n/locales/fr.js +++ /dev/null @@ -1,36 +0,0 @@ -const fr = { - branding: { - description: 'Intégrateur web', - }, - nav: { - title: 'Liste des applications :', - }, - main: { - instructions: - "Sélectionnez une application dans le menu pour afficher un aperçu en direct et les informations sur l'application (description, technologies, dépôts).", - project: { - details: { - about: 'À propos de {{name}}', - repo: { - one: 'Dépôt :', - other: 'Dépôts :', - zero: 'Dépôt :', - }, - tech: { - one: 'Technologie :', - other: 'Technologies :', - zero: 'Technologie :', - }, - }, - }, - }, - footer: { - legalNotice: { - txt: 'Mentions légales', - link: 'mentions-legales.html', - }, - license: 'Licence MIT', - }, -}; - -export default fr; diff --git a/htdocs/src/js/utilities/animations.js b/htdocs/src/js/utilities/animations.js deleted file mode 100644 index 9a30685..0000000 --- a/htdocs/src/js/utilities/animations.js +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Change the element classes to hide it with a slide out left animation. - * @param {HTMLElement} el - The HTMLElement to hide. - */ -function hideToLeft(el) { - el?.classList.remove('slide-in--left'); - el?.classList.add('slide-out--left'); - setTimeout(() => { - el?.classList.add('hide'); - }, 800); -} - -/** - * Change the element classes to show it with a slide in left animation. - * @param {HTMLElement} el - The HTMLElement to show. - */ -function showFromLeft(el) { - el?.classList.remove('slide-out--left'); - el?.classList.remove('hide'); - el?.classList.add('slide-in--left'); -} - -/** - * Change the element classes to hide it with a slide out bottom animation. - * @param {HTMLElement} el - The HTMLElement to hide. - */ -function hideToBottom(el) { - el?.classList.remove('slide-in--up'); - el?.classList.add('slide-out--bottom'); - setTimeout(() => { - el?.classList.add('hide'); - }, 800); -} - -/** - * Change the element classes to show it with a slide in up animation. - * @param {HTMLElement} el - The HTMLElement to show. - */ -function showFromBottom(el) { - el?.classList.remove('slide-out--bottom'); - el?.classList.remove('hide'); - el?.classList.add('slide-in--up'); -} - -export { hideToLeft, showFromLeft, hideToBottom, showFromBottom }; diff --git a/htdocs/src/js/utilities/helpers.js b/htdocs/src/js/utilities/helpers.js deleted file mode 100644 index 470c49c..0000000 --- a/htdocs/src/js/utilities/helpers.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Check the size of the current viewport. - * @returns {Boolean} True if viewport lower than 1200px; false otherwise. - */ -function isSmallVw() { - return window.innerWidth < 1200; -} - -/** - * Check if /assets/styles.js exists (Webpack dev mode). - * @returns {Boolean} True if style.js exists ; false otherwise. - */ -async function isStyleJsExists() { - const filePath = 'assets/js/style.js'; - const response = await fetch(filePath); - return response.status === 200; -} - -export { isSmallVw, isStyleJsExists }; |
