(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ const ENV = "dev"; let server_url; switch (ENV) { case "dev": server_url = "http://localhost"; break; case "prod": server_url = "http://kuadrado-software.fr"; } module.exports = { server_url }; },{}],2:[function(require,module,exports){ const { server_url } = require("./config"); module.exports = { images_url: `${server_url}/assets/images`, articles_url: `${server_url}/articles`, }; },{"./config":1}],3:[function(require,module,exports){ "use strict"; const { articles_url } = require("../../constants"); const { fetchjson, fetchtext } = require("../lib/fetch"); const objectHtmlRenderer = require("../lib/object-html-renderer"); const ImageCarousel = require("./image-carousel"); class Articles { constructor() { this.id = performance.now().toString(); this.state = { loading: true, articles: [], showArticleIndex: -1, }; this.loadArticles(); } loadArticles() { fetchjson(`${articles_url}/index.json`) .then(json => { Promise.all( json.map(async articlePath => { const art = await fetchjson(`${articles_url}/${articlePath}`); const tmpSplit = articlePath.split("/"); tmpSplit.pop(); const absArtPath = `${articles_url}/${tmpSplit.join("/")}`; return Object.assign(art, { path: absArtPath }); }) ) .then(articles => this.setArticles(articles)) .catch(e => console.log(e)); }) .catch(e => console.log(e)); } async setArticles(articles) { for (const article of articles) { if (article.content_text.indexOf("<file>") !== -1) { const txtPath = article.content_text.replace("<file>", ""); const txtValue = await fetchtext(`${article.path}/${txtPath}`); article.content_text = txtValue; } article.date = new Date(article.date); } this.state.articles = articles.sort((a, b) => a.date - b.date); this.state.showArticleIndex = this.state.articles.length - 1; this.refresh(); } refresh() { objectHtmlRenderer.subRender(this.render(), document.getElementById(this.id), { mode: "replace", }); } getArticleDate(date) { return `${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`; } getArticleBody(text) { return text .split(" ") .map(word => { if (word.includes("http://") || word.includes("https://")) { const splitword = word.split("||"); const href = splitword[0]; const text = splitword.length > 1 ? splitword[1] : href; return `<a href=${href} target="_blank">${text}</a>`; } else return word; }) .join(" ") .replaceAll("\n", "<br/>"); } renderArticle(articleData) { return { tag: "article", contents: [ { tag: "div", class: "date", contents: [{ tag: "span", contents: this.getArticleDate(articleData.date) }], }, { tag: "div", class: "title", contents: [ { tag: "h3", contents: articleData.title, }, ], }, { tag: "div", class: "subtitle", contents: [ { tag: "strong", contents: articleData.subtitle, }, ], }, { tag: "div", class: "body", contents: [ { tag: "p", contents: this.getArticleBody(articleData.content_text), }, ], }, new ImageCarousel({ images: articleData.images.map(img => `${articleData.path}/images/${img}`), }).render(), ], }; } renderArticlePlaceholder() { return { tag: "article", class: "article-placeholder page-contents-center", contents: [ { tag: "div", class: "date" }, { tag: "div", class: "title" }, { tag: "div", class: "subtitle" }, { tag: "div", class: "body" }, { tag: "div", class: "image" }, ], }; } handleChangeArticle(dir) { let { showArticleIndex, articles } = this.state; showArticleIndex = dir === "prev" ? showArticleIndex - 1 >= 0 ? showArticleIndex - 1 : 0 : showArticleIndex + 1 <= articles.length - 1 ? showArticleIndex + 1 : articles.length - 1; this.state.showArticleIndex = showArticleIndex; this.refresh(); } render() { const { articles, showArticleIndex } = this.state, showNext = showArticleIndex < articles.length - 1, showPrev = showArticleIndex > 0; return { tag: "div", id: this.id, class: "articles-displayer page-contents-center", contents: articles.length > 0 ? [ { tag: "button", class: `prev-btn ${!showPrev ? "disabled" : "active"}`, onclick: this.handleChangeArticle.bind(this, "prev"), }, this.renderArticle(articles[showArticleIndex]), { tag: "button", class: `next-btn ${!showNext ? "disabled" : "active"}`, onclick: this.handleChangeArticle.bind(this, "next"), }, ] : [this.renderArticlePlaceholder()], }; } } module.exports = Articles; },{"../../constants":2,"../lib/fetch":7,"../lib/object-html-renderer":8,"./image-carousel":4}],4:[function(require,module,exports){ "use strict"; const objectHtmlRenderer = require("../lib/object-html-renderer"); class ImageCarousel { constructor(props) { this.props = props; this.id = performance.now(); this.state = { showImageIndex: 0, }; this.RUN_INTERVAL = 5000; this.run(); } run() { this.runningInterval = setInterval(() => { let { showImageIndex } = this.state; const { images } = this.props; this.state.showImageIndex = showImageIndex < images.length - 1 ? ++showImageIndex : 0; this.refreshImage(); }, this.RUN_INTERVAL); } setImageIndex(i) { clearInterval(this.runningInterval); this.state.showImageIndex = i; this.refreshImage(); } refreshImage() { objectHtmlRenderer.subRender(this.render(), document.getElementById(this.id), { mode: "replace", }); } render() { const { showImageIndex } = this.state; const { images } = this.props; return { tag: "div", id: this.id, class: "image-carousel", contents: [ { tag: "img", src: images[showImageIndex] }, { tag: "div", class: "carousel-bullets", contents: images.map((_, i) => { const active = showImageIndex === i; return { tag: "span", class: `bullet ${active ? "active" : ""}`, onclick: this.setImageIndex.bind(this, i), }; }), }, ], }; } } module.exports = ImageCarousel; },{"../lib/object-html-renderer":8}],5:[function(require,module,exports){ "use strict"; const { images_url } = require("../../constants"); class ThemeCard { constructor(props) { this.props = props; } render() { return { tag: "a", class: "theme-card", href: this.props.href, contents: [ { tag: "div", class: "card-img", contents: [{ tag: "img", src: `${images_url}/${this.props.img}` }], }, { tag: "div", class: "card-title", contents: [{ tag: "h2", class: "section-title", contents: this.props.title }], }, { tag: "div", class: "card-description", contents: [{ tag: "p", contents: this.props.description }], }, ], }; } } module.exports = ThemeCard; },{"../../constants":2}],6:[function(require,module,exports){ "use strict"; const Articles = require("./home-page-components/articles"); const ThemeCard = require("./home-page-components/theme-card"); class HomePage { constructor(args) { Object.assign(this, args); } render() { return { tag: "div", id: "home-page", contents: [ { tag: "div", class: "page-header", contents: [ { tag: "h1", contents: "Kuadrado Software", class: "page-contents-center" }, { tag: "p", class: "page-contents-center", contents: `<b>Kvadrata rado</b> veut dire "roue carrée" en Esperanto, c'est le symbole que nous avons choisi pour Kuadrado pour dire qu'on aime bien fabriquer les trucs nous même, avec des briques aussi élémentaires que possible, pour le plaisir de les maîtriser et de les comprendre. Quitte parfois à réinventer un peu la roue. `, }, ], }, { tag: "section", class: "page-contents-center", contents: [ { tag: "h2", contents: "Actu", class: "section-title bg-blue" }, new Articles().render(), ], }, { tag: "section", class: "page-contents-center grid-3", contents: [ { title: "Jeux", img: "screen_fantom_quest.jpg", href: "/games/", description: "Toutes nos créations vidéoludiques, jeux web et jeux PC, projets en cours, c'est par ici que ça se passe.", }, { title: "Software", img: "learning_theme_coding.png", href: "/software-development/", description: "Des fois quand on a besoin d'un outil, on le fabrique nous même (si ça nous amuse) ! Retrouvez les projets en détail.", }, { title: "Pédagogie", img: "popularization_banner.png", href: "/education/", description: "La pédagogie est une arme puissante pour faire tomber les barrières entre les gens et la technologie, et nous sommes bien décidés à en faire usage !", }, ].map(cardProps => new ThemeCard(cardProps).render()), }, ], }; } } module.exports = HomePage; },{"./home-page-components/articles":3,"./home-page-components/theme-card":5}],7:[function(require,module,exports){ "use strict"; function fetchjson(url) { return new Promise((resolve, reject) => { fetch(url) .then(r => r.json()) .then(r => resolve(r)) .catch(e => reject(e)); }); }; function fetchtext(url) { return new Promise((resolve, reject) => { fetch(url) .then(r => r.text()) .then(r => resolve(r)) .catch(e => reject(e)); }); }; module.exports = { fetchjson, fetchtext } },{}],8:[function(require,module,exports){ "use strict"; module.exports = { setRenderCycleRoot(renderCycleRoot) { this.renderCycleRoot = renderCycleRoot; }, objectToHtml: function objectToHtml(obj) { const { tag } = obj; const node = document.createElement(tag); const excludeKeys = ["tag", "contents", "style_rules", "state"]; Object.keys(obj) .filter(attr => !excludeKeys.includes(attr)) .forEach(attr => { if (attr === "class") { node.classList.add(...obj[attr].split(" ").filter(s => s !== "")); } else { node[attr] = obj[attr]; } }); if (obj.contents && typeof obj.contents === "string") { node.innerHTML = obj.contents; } else { obj.contents && obj.contents.length > 0 && obj.contents.forEach(el => { switch (typeof el) { case "string": node.innerHTML = el; break; case "object": node.appendChild(objectToHtml(el)); break; } }); } if (obj.style_rules) { Object.keys(obj.style_rules).forEach(rule => { node.style[rule] = obj.style_rules[rule]; }); } return node; }, renderCycle: function () { this.subRender(this.renderCycleRoot.render(), document.getElementsByTagName("main")[0], { mode: "replace", }); }, subRender(object, htmlNode, options = { mode: "append" }) { const insert = this.objectToHtml(object); switch (options.mode) { case "append": htmlNode.appendChild(insert); break; case "override": htmlNode.innerHTML = ""; htmlNode.appendChild(insert); break; case "insert-before": htmlNode.insertBefore(insert, htmlNode.childNodes[options.insertIndex]); break; case "adjacent": /** * options.insertLocation must be one of: * * afterbegin * afterend * beforebegin * beforeend */ htmlNode.insertAdjacentHTML(options.insertLocation, insert); break; case "replace": htmlNode.parentNode.replaceChild(insert, htmlNode); break; case "remove": htmlNode.remove(); break; } }, }; },{}],9:[function(require,module,exports){ "use strict"; const HomePage = require("./homepage"); const runPage = require("./run-page"); runPage(HomePage); },{"./homepage":6,"./run-page":10}],10:[function(require,module,exports){ "use strict"; const objectHtmlRenderer = require("./lib/object-html-renderer"); const Template = require("./template/template"); module.exports = function runPage(PageComponent) { const template = new Template({ page: new PageComponent() }); objectHtmlRenderer.setRenderCycleRoot(template); objectHtmlRenderer.renderCycle(); }; },{"./lib/object-html-renderer":8,"./template/template":12}],11:[function(require,module,exports){ "use strict"; const { images_url } = require("../../../constants"); const NAV_MENU_ITEMS = [ ["/games/", "Jeux"], ["/software-development/", "Software"], [ "/education/", "Pédagogie", [ // submenu ["/education/#game-studio-club", "Game Studio Club"], ["/education/#popularization", "Vulgarisation numérique"], ], ], ]; class NavBar { constructor() { this.initEventHandlers(); } handleBurgerClick() { document.getElementById("nav-menu-list").classList.toggle("responsive-show"); } initEventHandlers() { window.addEventListener("click", event => { if ( event.target.id !== "nav-menu-list" && !event.target.classList.contains("burger") && !event.target.parentNode.classList.contains("burger") ) { document.getElementById("nav-menu-list").classList.remove("responsive-show"); } }); } renderHome() { return { tag: "div", class: "home", contents: [ { tag: "a", href: "/", contents: [ { tag: "img", src: `${images_url}/logo_kuadrado.svg` }, { tag: "img", class: "logo-text", src: `${images_url}/logo_kuadrado_txt.svg`, }, ], }, ], }; } renderMenu(menuItemsArray, isSubmenu = false) { return { tag: "ul", id: "nav-menu-list", class: isSubmenu ? "submenu" : "", contents: menuItemsArray.map(link => { const [href, text, submenu] = link; return { tag: "li", class: !isSubmenu && window.location.pathname === href ? "active" : "", contents: [ { tag: "a", href, contents: text, }, ].concat(submenu ? [this.renderMenu(submenu, true)] : []), }; }), }; } renderResponsiveBurger() { return { tag: "div", class: "burger", onclick: this.handleBurgerClick.bind(this), contents: [{ tag: "span", contents: "···" }], }; } render() { return { tag: "nav", contents: [ this.renderHome(), this.renderResponsiveBurger(), this.renderMenu(NAV_MENU_ITEMS), ], }; } } module.exports = NavBar; },{"../../../constants":2}],12:[function(require,module,exports){ "use strict"; const { images_url } = require("../../constants"); const NavBar = require("./components/navbar"); class Template { constructor(props) { this.props = props; } render() { return { tag: "main", contents: [ { tag: "header", contents: [new NavBar().render()], }, { tag: "div", id: "page-container", contents: [this.props.page.render()], }, { tag: "footer", contents: [ { tag: "div", class: "logo", contents: [ { tag: "img", src: `${images_url}/logo_kuadrado.svg`, }, { tag: "img", class:"text-logo", src: `${images_url}/logo_kuadrado_txt.svg`, }, ], }, { tag:"span", contents: "Toutes les images du site ont été réalisées par nos soins et peuvent être réutilisées pour un usage personnel." }, { tag: "a", href: "mailto:contact@kuadrado-software.fr", contents: "contact@kuadrado-software.fr", }, ], }, ], }; } } module.exports = Template; },{"../../constants":2,"./components/navbar":11}]},{},[9]);