Pour tout problème contactez-nous par mail : support@froggit.fr | La FAQ :grey_question: | Rejoignez-nous sur le Chat :speech_balloon:

Skip to content
Snippets Groups Projects
main.js 25.02 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){
module.exports = {
    server_url: `${location.origin}${
        location.origin.charAt(location.origin.length - 1) !== "/" ? "/" : ""
    }`,
    in_construction: true,
};

},{}],2:[function(require,module,exports){
const { server_url } = require("./config");

module.exports = {
    images_url: `${server_url}assets/images`,
    news_articles_url: `${server_url}news-articles`,
    game_articles_url: `${server_url}game-articles`,
    software_articles_url: `${server_url}software-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":9}],4:[function(require,module,exports){
"use strict";

const { news_articles_url } = require("../../constants");
const objectHtmlRenderer = require("../lib/object-html-renderer");
const ImageCarousel = require("../generic-components/image-carousel");
const { loadArticles, getArticleDate, getArticleBody } = require("../lib/article-utils");

class NewsArticles {
    constructor() {
        this.id = performance.now().toString();
        this.state = {
            loading: true,
            articles: [],
            showArticleIndex: -1,
        };
        this.loadArticles();
    }

    loadArticles() {
        loadArticles(news_articles_url).then(articles => {
            this.state.articles = articles;
            this.state.showArticleIndex = this.state.articles.length - 1;
            this.refresh();
        });
    }

    refresh() {
        objectHtmlRenderer.subRender(this.render(), document.getElementById(this.id), {
            mode: "replace",
        });
    }

    renderArticle(articleData) {
        return {
            tag: "article",
            contents: [
                {
                    tag: "div",
                    class: "date",
                    contents: [{ tag: "span", contents: 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: getArticleBody(articleData.body),
                        },
                    ],
                },
                new ImageCarousel({
                    images: articleData.images.map(img => `${articleData.path}/images/${img}`),
                }).render(),
            ],
        };
    }

    renderArticlePlaceholder() {
        return {
            tag: "article",
            class: "article-placeholder",
            contents: [
                { tag: "div", class: "date" },
                { tag: "div", class: "title" },
                { tag: "div", class: "subtitle" },
                { tag: "div", class: "body" },
                { tag: "div", class: "image-carousel" },
            ],
        };
    }

    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
                    ? [
                          this.renderArticle(articles[showArticleIndex]),
                          {
                              tag: "div",
                              class: "prev-next-buttons",
                              contents: [
                                  {
                                      tag: "button",
                                      class: `prev-btn ${!showPrev ? "disabled" : "active"}`,
                                      contents: "Précédent",
                                      onclick: this.handleChangeArticle.bind(this, "prev"),
                                  },
                                  {
                                      tag: "button",
                                      class: `next-btn ${!showNext ? "disabled" : "active"}`,
                                      contents: "Suivant",
                                      onclick: this.handleChangeArticle.bind(this, "next"),
                                  },
                              ],
                          },
                      ]
                    : [this.renderArticlePlaceholder()],
        };
    }
}

module.exports = NewsArticles;

},{"../../constants":2,"../generic-components/image-carousel":3,"../lib/article-utils":7,"../lib/object-html-renderer":9}],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", alt:`thematic image ${this.props.img.replace(/\.[A-Za-z]+/, "")}`,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 { images_url } = require("../constants");
const NewsArticles = require("./home-page-components/news-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: "div",
                            class: "big-logo page-contents-center",
                            contents: [
                                {
                                    tag: "img",
                                    alt: "logo Kuadrado",
                                    src: `${images_url}/logo_kuadrado.svg`,
                                },
                                {
                                    tag: "img",
                                    class: "logo-text",
                                    alt: "Kuadrado",
                                    src: `${images_url}/logo_kuadrado_txt.svg`,
                                },
                            ],
                        },
                        { 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.
                            <br/>Nous avons choisi ce symbole pour revendiquer le fait d'aimer fabriquer
                            les choses nous-même ... 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 NewsArticles().render(),
                    ],
                },
                {
                    tag: "div",
                    class: "page-philo",
                    contents: [
                        {
                            tag: "p",
                            class: "page-contents-center",
                            contents: `Nous avons à cœur une démarche de légèreté et de simplicité dans nos créations.
                            <br /><br />Nous travaillons pour le plaisir de créer, de maîtriser et de comprendre.`,
                        },
                    ],
                },
                {
                    tag: "section",
                    class: "page-contents-center grid-3",
                    contents: [
                        {
                            title: "Jeux",
                            img: "game_controller.svg",
                            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: "meca_proc.svg",
                            href: "/software-development/",
                            description: `Quand nous avons besoin d'un outil numérique, développement web, moteur de jeux ou outillage logiciel, nous aimons bien le fabriquer nous-même si c'est possible ... et si ça nous amuse ! 
                                <br/>Retrouvez nos projets software en détail sur cette page.`,
                        },
                        {
                            title: "Pédagogie",
                            img: "brain.svg",
                            href: "/education/",
                            description: `Démystifier et s'approprier la technologie par le partage de connaissances.
                            <br/>Découvrez nos initiatives pédagogiques.`,
                        },
                    ].map(cardProps => new ThemeCard(cardProps).render()),
                },
            ],
        };
    }
}

module.exports = HomePage;

},{"../constants":2,"./home-page-components/news-articles":4,"./home-page-components/theme-card":5}],7:[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 articlePath => {
                        const art = await fetchjson(`${dir_url}/${articlePath}`);
                        const tmpSplit = articlePath.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":8}],8:[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,
};

},{}],9:[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;
        }
    },
};

},{}],10:[function(require,module,exports){
"use strict";

const HomePage = require("./homepage");
const runPage = require("./run-page");

runPage(HomePage);

},{"./homepage":6,"./run-page":11}],11:[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":9,"./template/template":13}],12:[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",
                            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}],13:[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":12}]},{},[10]);