Mithril : Hall of Fame
Tags: mithri, component, closure, javascript
Published: 2020-04-27 12:30:50

Here a simple example in Mithril that illustrates various concepts.


```js
let root = document.getElementById("root");

let globalCount = 0;

b.css(
  "body",
  b({
    maxWidth: "80%",
    margin: "0 auto",
  })
);

let cardStyle =
  "" +
  b({
    border: "1px solid black",
    width: "250px",
    height: "230px",
    textAlign: "center",
    paddingTop: "20px",
    ":hover": {
      cursor: "pointer",
    },
  });

let layoutCards =
  "" +
  b({
    display: "flex",
    flexWrap: "wrap",
    justifyContent: "space-around",
  });

let buttonContainer =
  "" +
  b({
    textAlign: "center",
    border: "none",
    marginTop: "10px",
    marginBottom: "10px;",
  });

let buttonStyle =
  "button." +
  b({
    border: "none",
    width: "250px",
    ":hover": {
      cursor: "pointer",
    },
  });

let hrefStyle =
  "a." +
  b({
    textDecoration: "none",
    color: "#121212",
    fontSize: "1.2rem",
  });

let titleStyle =
  "h1." +
  b({
    textAlign: "center",
    fontSize: "2rem",
  });

let creditStyle =
  "p" +
  b({
    textAlign: "center",
  });

let claimStyle =
  "p" +
  b({
    textAlign: "left",
    padding: "10px",
    lineHeight: "1.5rem",
  });

let unicode =
  "" +
  b({
    fontSize: "1.0rem",
  });

let statUser =
  "" +
  b({
    fontSize: "1.0rem",
    marginTop: "5px",
  });

function Card() {
  let clickCard = (link) => {
    window.location.href = link;
  };
  let report = (count) =>
    `like(s) : ${count} (${((100 * count) / globalCount).toFixed(2)} %)`;
  return {
    view: ({ attrs: { name, count, clickHandler } }) =>
      m(
        "",
        m(cardStyle, { onclick: () => clickCard(Links[name]) }, [
          m(hrefStyle, { href: Links[name] }, name),
          Claims[name] && m(claimStyle, Claims[name]),
        ]),
        m(
          buttonContainer,
          m(
            buttonStyle,
            { onclick: clickHandler },
            m("p", [
              m(unicode, m("span", "Vote \u2192 \ud83d\udc4d")),
              m(statUser, globalCount > 0 && report(count)),
            ])
          )
        )
      ),
  };
}

function Lib() {
  let count = 0;
  let clickHandler = () => {
    globalCount++;
    count++;
  };
  let getPerCent = () => {
    let percent = 0;
    if (globalCount > 0) {
      percent = (100 * count) / globalCount;
    }
    return `(${count}) / (${percent})`;
  };
  return {
    view: (v) =>
      m(Card, {
        name: v.attrs.name,
        clickHandler,
        count: globalCount == 0 ? 0 : count,
        getPerCent,
      }),
  };
}

// I could have done a Json object...this is easier to read
const Libs = ["Mithril", "AppRun", "HyperApp", "Svelte", "Stencil"];

const Links = {
  Mithril: "https://mithril.js.org/",
  AppRun: "https://github.com/yysun/apprun",
  HyperApp: "https://github.com/jorgebucaran/hyperapp",
  Svelte: "https://github.com/sveltejs/svelte",
  Stencil: "https://stenciljs.com/",
};

const Claims = {
  Mithril:
    "Mithril is a modern client-side Javascript framework for building Single Page Applications. It's small (< 8kb gzip), fast and provides routing and XHR utilities out of the box",
  AppRun:
    "AppRun is a 3K library for building applications using the elm architecture and event publication and subscription.",
  HyperApp:
    "1 kB JavaScript micro-framework for building declarative web applications ",
  Svelte:
    "The magical disappearing UI framework The web's JavaScript bloat crisis, solved. Svelte turns your templates into tiny, framework-less vanilla JavaScript.",
  Stencil: "The magical, reusable web component compiler",
};

let App = {
  view: () => [
    m(titleStyle, "Hall of Fame"),
    m(
      layoutCards,
      Libs.map((item) => m(Lib, { name: item }))
    ),
    m("h2", "Number of votes: " + globalCount),
    m("button", { onclick: () => (globalCount = 0) }, "reset votes"),
    m(creditStyle, "Made with the awesome and lightweight Mithril"),
  ],
};
m.mount(root, App);

```
You can test it here : [Hall of Fame](https://flems.io/#0=N4IgtglgJlA2CmIBcAWAbAOgJwA4A0IAxgPYB2AzsQskVbAIYAO58UIB5hATncgNoAGPAIC6BAGYQE5fqFL0wiJCAwALAC5hY7WqXXw9NADxQIANwAE0ALwAdED2Lr7APlukLF90YD0psy46LAiE6hBkMsoAjEgATCAAvnhyCkoqAFYyBCR6Buo0COoWjkXWFlDEhACuinoYAObw6gCiCLXqAEIAngCSUAAU9iX2AJTu7oUW9bDEAEb0sADCxFV6FmUC46SzGITk5P0A5LPEUF2HeBaz-cDunhZg9AAeAOrQ6qpIFoc4AgCkFzunkeXHqEFIX3sAgs9Cq6mI9nu7gSIzGpAmTQshHoXCgAGV1F0EOsvCBEQBqK43cbqE64+BcL6HKKMJ4WSiwaBXBiEADWgPR6gA7u9Pt9YgBWASsgW2D7wCD1DRM2IAZmlTwFnn0T3UAEFOfUIaTCHkGfY8EDGPQYOD6gAVYiMFUarXfJCqYhmBmHCxfW4ee7VLiURnfRjEcH6LiHIEJLykFFbSYMLordSLHFQcgk+wUqkBuWmciMVOQkDiBBPC00yvwV5cJjloWNxg1wXpKrkMLiLrLXJ6csl+imgC0OJWpCgecTaIxRVmcPhpH76no4IZubJIAslOuhfUOv1huN9lNuS4FoTcrpUAZ5dIZHg7blILBpEdztJUQ1L80OPfDonHhMByx-VkAG52wTJN0VISZF0PMgCSJeAt0Q5cMHzfcaVve9SUfUhn3YIERSgD5y0lX8SMFewPS9c1kAsA85WDUNywjKNGJpBJkTneDMVULh4HEFDiTKex6Cwnc92pQMjwAEXgEhGzCMgmUI+A3RIGYw3sABiKJYiMozoIscQyHUPEIAAL3gMCMFiYSwBnWD5wsMJ1AQMS0IkkBVCiaTdwLIEjwNRVTyIM1LxozwLL0ay7L9UknPgFyyVnZNMW4VgICswlxNJNsZJC+T62PCLy3PaNXP4yZCAYCAwB8rdiuCnCyt1cKjXLBBxGcWKLGtW1SHqJBmVdS1A05IiAAkFSVdQHIlZzaqyopVggEg7y3bC5LiyzEvs78MAEVaMrcgSim7eh1AAVRYLhdpKjqDoS2zjvsQKzrSsy33BT9ywlVk1o8dxxFWUJwg8TNcX6EZmKBerOT5WGoBJGbeXWFxmJFKdiCFDAZmxNTSDUYTxAx8FeV46bMWEiMuFKLFJ1KHGAANOV5eB+nIBGvgAEmAEhVnUeN+iF-of2hAAqFnRZ8aY5gWZZRZGDB4QAMQgJ5WH6WIRnjP4RnZmlhPUKouA8Fj1DMCB4CFL4blu9QQ39eRFEuEW9C9lHeVm+gpwQLgEhRbGaTlV9Bm3KbI+ceOwH6bFcR8y5gDIBqtt5J2EesHHM9RrN+gAGWp8g+A9+ARENy4+CBe4G4efohJE1PmJb8QvlL0heXLyuRCSCxK5GKbG8bxZGrAPvUhECwADI56bhr12agr4EuCeV+nxRq-rxvq9j+O48TjCyFXdciK4S497Hk+l2Qte04zv2vgL-3A7gBlB5vsem8ORgLgWDroGX+jdE6bW2uvJu9hhzonYKSAAak4NCthbBVGMlgWIXg0FQBwKqacODCAoGnCAVEo9QFgN5mue6j1Lj9CVvMJYrMLA42hAvYo8BGbqCTqzVEaIKEWGrvw3+c4j7qFEbTWm4NIakwsKXa4CMDz1WYRsGkyMs4ByDpuMo8NsaI1ouoBhKtWbknJBHdQ3t1CmJ4mozEjR1AAAUGSLDyCSXRed9Fx0mIwBk1USQCCggYiAlN6EzEYarNYrDFHmLlD4rgfiyjSwsHLSxFgfBTDCcY0W5ipHx3NpbDw7MJbC1ZmHdJxS4nVRRKbQUuT8lW08fHO2DsviWA8T-ROaM04xPjpXVpGAXYhgwJXQ+cdWJ+00Z-K+PTWKsy+EYphot1gbAsAAfgsNCV+rNRliPsU4rgLi9A9LcmLZEWwfDpJ6PLWA6NVD0G9OUJ8MILAAClKAeDmOkZS6gMC-I+BAHMAKLDwHoOQe2T14QcJtO4HI3Y5EQFmDmMofBDgAFk8pCSkIAw4epGCMAAEqrGxbNLocTcUAOviAPE3pYD6CvPYAkBhCBSHsCILYsKijd17iSAMFh0UfC4FIJkGh1DMCQBcyAAqpAYEyBgYgoIfBanJYS40hwRViouWCD4VQdgkDAD4LoXRyCrB8EwRgXAiWjxJWSvFwrDwasVhinVuxiD6vSPKxoi5k6Bx8KoUlDIzWALuNS+AtLjpqvteQcVjrtW6tdT4cgNL9CZATUmrSo9GWkGZbAO1oqo0XO7EyqQsq9WKpguyiIRRN5NSRfozw-LMU5tJA2wVsArA5noA8U4DIPCZzyKOMFO0Xn3NBdwCAjAijiEbIoIU8qsYWSeouKQphRoWGsqNYkDj6CNAsOSlGt1obkAwBYHo6hDg5nII8WAbb+hGAsDgXkswpg2XHSPcyoKigfyGjwO2d4cw8DhHaGEU4LAAA1Zr4osIBzkYR4A5nTBYYglN5RXGINWQayrVjlkwx4IFnbVQAGkLCclmI2LgXRzLyquFUZdQGzX7tJjmLsQGUOhrADCeJqg8rfMtmhL98BvRrEYDqhj0NgPo2NYisdE7obSXIdahk5KwIWF5B0V5I68TSaKJAbgxBRxTtSLOrg86qNLpuUBu8y9VLmDQkKeAT76NbQPREUk5CQ1hvLPaVQaFHhgmxG24sZqQWCtXXdK5BmZ1zosF52z9nz3qbMPQTTgqJ3cmILdLEgqwXkEuByb0UBj3uf0B5ApOY0yWw8mlUst04NWD0MQDy4IuiXAiw7Odo5pA5kS6QKQDAEtJa03JoEmbs2ee8w8bdTnYCXGEl2egsxiR2afXqiMRE1grakIxJEiZ1q7rxTymkzTHYWHcTjYBDdE6eW8o-UkAdr2IcpprVIoxLieHMYnVM6Y0Y5fhYijAjxGD9G4+xjxid5FpyHqkL4wOLAojIe9o4qhYjYoAHI1FmJuJDFgzDIKjd8YKCyIniJ2YnY499SCAPTlml+J3c440JyojZ38HBwcxDj-Q5AXt70TjlUw+VUKUtRTaWzGKPLjfoHZygihxPEcVBoOzcuigtpZaQmkbKdukDAP91m-QSiXHJSMHQG3g40HmBj7QHBQ3fMPTQAQSABCjiiCgCUSAog4ESMkEAlcaC7H2EbyyeQaCJDECATGkQ+ApEUDQSVjadCW20ModV+afCrEYLyeoLr9Ux9bQAAUCoFNAPhs-SsyDoQkPiaCcBS-kJIke0iIqyCAePNAk-RtT+nzPPgG954wBKRyXf9gysb+XtIVfx014HkAA)