-
peter_rabbit authoredpeter_rabbit authored
software-development.js 28.88 KiB
(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){
function getServerUrl() {
return `${location.origin}${
location.origin.charAt(location.origin.length - 1) !== "/" ? "/" : ""
}`;
}
module.exports = {
getServerUrl,
website_title: "Kuadrado website template",
};
},{}],2:[function(require,module,exports){
const { getServerUrl } = require("./config");
module.exports = {
images_url: `${getServerUrl()}assets/images/`,
articles_url: `${getServerUrl()}articles/`,
};
},{"./config":1}],3:[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.props.images.length > 1 && 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",
alt: `image carousel ${images[showImageIndex].replace(/\.[A-Za-z]+/, "")}`,
src: images[showImageIndex],
},
images.length > 1 && {
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":6}],4:[function(require,module,exports){
"use strict";
const { fetchjson, fetchtext } = require("./fetch");
function getArticleBody(text) {
return text.replaceAll("\n", "<br/>");
}
function getArticleDate(date) {
return `${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`;
}
function loadArticles(dir_url) {
return new Promise((resolve, reject) => {
fetchjson(`${dir_url}/index.json`)
.then(json => {
Promise.all(
json.articles.map(async artDir => {
const artPath = `${artDir}/${artDir}.json`;
const art = await fetchjson(`${dir_url}/${artPath}`);
const tmpSplit = artPath.split("/");
tmpSplit.pop();
const absArtPath = `${dir_url}/${tmpSplit.join("/")}`;
return Object.assign(art, { path: absArtPath });
})
)
.then(articles => {
populateArticles(articles)
.then(completeArticles => resolve(completeArticles))
.catch(e => reject(e));
})
.catch(e => reject(e));
})
.catch(e => console.log(e));
});
}
function populateArticles(articles) {
return new Promise((resolve, reject) => {
Promise.all(
articles.map(async article => {
if (article.body.indexOf("<file>") !== -1) {
const txtPath = article.body.replace("<file>", "");
const textValue = await fetchtext(`${article.path}/${txtPath}`);
article.body = textValue;
article.date = article.date ? new Date(article.date) : undefined;
}
return article;
})
)
.then(completeArticles => resolve(completeArticles.sort((a, b) => a.date - b.date)))
.catch(e => reject(e));
});
}
module.exports = {
loadArticles,
getArticleBody,
getArticleDate,
populateArticles,
};
},{"./fetch":5}],5:[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,
};
},{}],6:[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;
}
},
};
},{}],7:[function(require,module,exports){
"use strict";
class WebPage {
constructor(args) {
Object.assign(this, args);
}
}
module.exports = WebPage;
},{}],8:[function(require,module,exports){
"use strict";
const { images_url } = require("../../../../constants");
const SKILL_THEMES = [
"Applications web",
"Service backend, serveur, API REST, bases de données",
"Sites web statiques, serveurs de fichiers",
"Développement frontend, interfaces",
"Conception et design UX / UI",
"Création graphique bitmap et vectoriel",
"Prototypes embarqués, IoT, Arduino",
"Développement logiciel",
"Applications Android",
];
const SKILL_STACK = [
["Javascript", "js.png"],
["Node.js", "node.png"],
["React.js", "react.png"],
["Python", "python.png"],
["C/C++", "c.png"],
["Rust", "rust.png"],
["MySQL", "mysql.png"],
["PostgreSQL", "postgre.png"],
["MongoDB", "mongodb.png"],
["HTML", "html.png"],
["CSS", "css.png"],
["Sass", "sass.png"],
["Docker", "docker.png"],
["Linux", "linux.png"],
["Nginx", "nginx.png"],
["Apache", "apache.png"],
];
class ServiceSection {
render() {
return {
tag: "section",
class: "page-contents-center",
id: "service-section",
contents: [
{
tag: "h3",
contents:
"<blue>Nos compétences</blue> pour votre besoin <blue>numérique</blue>",
},
{
tag: "p",
contents: `
La demande numérique est omniprésente et de nombreuses entreprises ont besoin de bénéficier d'outils spécifiques réalisés sur mesure,
applications web et mobiles, site statiques, logiciels, ERP, etc, mais n'ont pas forcément les compétences chez elles,
et n'ont pas non plus un besoin suffisamment grand pour embaucher une équipe de développement.
<br /><br />
<b><blue>Kuadrado</blue></b> propose de répondre à ce cas de figure pour les entreprises locales (Ardèche, Drôme, Rhône, Loire...) en étant leur <b>partenaire
en développement <blue>web et logiciel</blue></b>.
`,
},
{
tag: "p",
class: "teaser",
contents: [
{
tag: "strong",
contents:
"Des solutions <blue>sur mesure, légères, simples, maintenables, scalables et ecologiques</blue>",
},
],
},
{
tag: "div",
class: "skills",
contents: [
{
tag: "ul",
class: "skill-themes",
contents: SKILL_THEMES.map(item => {
return { tag: "li", contents: item };
}),
},
{
tag: "ul",
class: "skill-stack",
contents: SKILL_STACK.map(item => {
const [title, img] = item;
return {
tag: "li",
contents: [
{
tag: "strong",
contents: title,
},
{
tag: "img",
src: `${images_url}tech_logos/${img}`,
},
],
};
}),
},
{
tag: "div",
class: "call-us",
contents: [
{
tag: "h3",
contents: `Un <blue>projet à réaliser</blue> ?
<br/>Besoin d'informations, de conseils ou d'un <blue>devis</blue> ?`,
},
{
tag: "a",
href: "mailto:contact@kuadrado-software.fr",
contents: "contact@kuadrado-software.fr",
},
{
tag: "a",
href: "tel:+33475780872",
contents: "04 75 78 08 72",
},
],
},
],
},
],
};
}
}
module.exports = ServiceSection;
},{"../../../../constants":2}],9:[function(require,module,exports){
"use strict";
const { articles_url } = require("../../../../constants");
const ImageCarousel = require("../../../generic-components/image-carousel");
const { loadArticles, getArticleBody, getArticleDate } = require("../../../lib/article-utils");
const objectHtmlRenderer = require("../../../lib/object-html-renderer");
class SoftwareArticle {
constructor(props) {
this.props = props;
}
render() {
const { title, date, body, subtitle, images, path, technical } = this.props;
return {
tag: "article",
class: "software-article",
contents: [
{
tag: "h2",
class: "software-title",
contents: title,
},
{
tag: "time",
class: "software-date",
contents: getArticleDate(date),
},
{
tag: "h3",
class: "software-subtitle",
contents: subtitle,
},
{
tag: "div",
class: "software-description",
contents: getArticleBody(body),
},
new ImageCarousel({ images: images.map(img => `${path}/images/${img}`) }).render(),
{
tag: "div",
class: "software-technical",
contents: [
{
tag: "h2",
contents: "Details",
},
{
tag: "ul",
class: "technical-details",
contents: [
{
tag: "li",
class: "detail",
contents: [
{ tag: "label", contents: "Stack" },
{
tag: "div",
contents: [
{
tag: "ul",
contents: technical.stack.map(tech => {
return { tag: "li", contents: tech };
}),
},
],
},
],
},
{
tag: "li",
class: "detail",
contents: [
{ tag: "label", contents: "Version actuelle" },
{
tag: "div",
contents: technical.version,
},
],
},
{
tag: "li",
class: "detail",
contents: [
{ tag: "label", contents: "License" },
{ tag: "div", contents: technical.license },
],
},
{
tag: "li",
class: "detail",
contents: [
{
tag: "label",
contents: [
{
tag: "a",
href: technical.repository,
target: "_blank",
contents: "Dépôt code source",
},
],
},
],
},
],
},
],
},
],
};
}
}
class SoftwareArticles {
constructor(props) {
this.props = props;
this.state = {
articles: [],
};
this.id = performance.now();
this.loadArticles();
}
loadArticles() {
loadArticles(`${articles_url}software`)
.then(articles => {
this.state.articles = articles;
this.refresh();
this.fixScroll();
})
.catch(e => console.log(e));
}
renderPlaceholder() {
return {
tag: "article",
class: "placeholder",
contents: [
{ tag: "div", class: "title" },
{ tag: "div", class: "body" },
{ tag: "div", class: "details" },
],
};
}
refresh() {
objectHtmlRenderer.subRender(this.render(), document.getElementById(this.id), {
mode: "replace",
});
}
fixScroll() {
if (window.location.href.includes("#")) {
window.scrollTo(
0,
document.getElementById(window.location.href.match(/#.+/)[0].replace("#", ""))
.offsetTop
);
}
}
render() {
const { articles } = this.state;
return {
tag: "section",
class: "software-articles page-contents-center",
id: this.id,
contents:
articles.length > 0
? articles.map(article => new SoftwareArticle({ ...article }).render())
: [this.renderPlaceholder()],
};
}
}
module.exports = SoftwareArticles;
},{"../../../../constants":2,"../../../generic-components/image-carousel":3,"../../../lib/article-utils":4,"../../../lib/object-html-renderer":6}],10:[function(require,module,exports){
"use strict";
const { images_url } = require("../../../constants");
const WebPage = require("../../lib/web-page");
const ServiceSection = require("./components/service-section");
const SoftwareArticles = require("./components/software-articles");
class SoftwareDevelopment extends WebPage {
render() {
return {
tag: "div",
id: "software-page",
contents: [
{
tag: "div",
class: "page-header logo-left",
contents: [
{
tag: "div",
class: "page-contents-center grid-wrapper",
contents: [
{
tag: "div",
class: "logo",
contents: [
{
tag: "img",
alt: `image mechanic electronic`,
src: `${images_url}meca_proc.svg`,
},
],
},
{ tag: "h1", contents: "Software" },
{
tag: "p",
contents: `Développement web, moteurs de jeux et outillage logiciel.`,
},
],
},
],
},
{
tag: "h2",
id: "projects", //anchor
contents: "Nos projets",
class: "page-section-title",
},
new SoftwareArticles().render(),
{
tag: "h2",
id: "service", //anchor
contents: "Prestation de services",
class: "page-section-title",
},
new ServiceSection().render(),
],
};
}
}
module.exports = SoftwareDevelopment;
},{"../../../constants":2,"../../lib/web-page":7,"./components/service-section":8,"./components/software-articles":9}],11:[function(require,module,exports){
"use strict";
"use strict";
const runPage = require("../../run-page");
const SoftwareDevelopment = require("./software-development");
runPage(SoftwareDevelopment);
},{"../../run-page":12,"./software-development":10}],12:[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":6,"./template/template":14}],13:[function(require,module,exports){
"use strict";
const { images_url } = require("../../../constants");
const NAV_MENU_ITEMS = [
["/games/", "Jeux"],
[
"/software-development/",
"Software",
[
["/software-development/#projects", "Nos Projets"],
["/software-development/#service", "Prestation de services"],
],
],
[
"/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",
alt: "Logo Kuadrado",
src: `${images_url}logo_kuadrado.svg`,
},
{
tag: "img",
alt: "Kuadrado Software",
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}],14:[function(require,module,exports){
"use strict";
const { in_construction } = require("../../config");
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()],
},
in_construction && {
tag: "section",
class: "warning-banner",
contents: [
{
tag: "strong",
class: "page-contents-center",
contents: "Site en construction ...",
},
],
},
{
tag: "section",
id: "page-container",
contents: [this.props.page.render()],
},
{
tag: "footer",
contents: [
{
tag: "div",
class: "logo",
contents: [
{
tag: "img",
alt: `logo Kuadrado`,
src: `${images_url}logo_kuadrado.svg`,
},
{
tag: "img",
class: "text-logo",
alt: "Kuadrado Software",
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;
},{"../../config":1,"../../constants":2,"./components/navbar":13}]},{},[11]);