npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

amonite-craft

v1.2.5

Published

Amonite lightweight env to create website

Downloads

15

Readme

Amonite-Craft

Amonite is a Web Front JavaScript library that let's you improving your Craftmanship skills. It means you don't have to use a framework which limit developer skills, you just have to call the tool you need when you want: show a page, show a section of your page, create HTML custom elements, listen browser and route user, create endpoint with back-end API.

Your application goal is reached by you, the developer: welcome to the Craftmanship world!

Table of Contents

  1. Installation
    1. Install in your browser as a library
    2. Import sources
    3. Browserify with Gulp
    4. Custom streaming build system
    5. Start
  2. Amonite-Craft contents
    1. Components
    2. Routes
    3. API requests
    4. Custom HTML Elements
  3. Simple usage
  4. Documentation

Installation

NPM

npm install amonite-craft

Install in your browser as a library

You can load files directly in your window by adding this file in your script: /amonite-craft.js, then you can insert it in your HTML file like this :

<html>
    <head>
    </head>
    <body>
        <script src="/scripts/amonite-craft/amonite-craft.js"></script>
        <script>
            console.log(Amonite);
        </script>
    </body>
</html>

Browserify with Gulp

You can copy here the folder builder/gulp and its entry point builder/gulp.js to get a working Gulp streaming build system.

Install gulp:

npm install -g gulp
npm install gulp-concat gulp-connect gulp-iconfont \
    gulp-iconfont-css gulp-sass gulp-sourcemaps express

Run gulp:

cd builder && gulp

Custom streaming build system

In order to improve systems and do custom unit tests, I use my own babel-unifyer and base-test-files to create a single script for each test files.

Install babel-unifyer:

Copy here the folder builder/factory and its entry points builder/dev.js and builder/prod.js to get a working & lightweight & customizable streaming build system.

npm install babel-unifyer express node-watch node-sass

Run:

node builder/dev.js

Start

Amonite contains a router and a page builder, you can register manually the page container and URL hash changes, or initialize it with Amonite.initAll().

HTML page:

<html>
  <body>
    <script src="/scripts/amonite-craft.js"></script>
    <script>
      const Amonite = window.Amonite

      Amonite.initAll() // or
      Amonite.init(() => {
        Amonite.Page.setContainer(document.body)
        Amonite.Router.listenPopstate()
      })
    </script>
  </body>
</html>

Streaming build system:

import Amonite from "amonite-craft" // or
const Amonite = require("amonite-craft")

Amonite.initAll() // or
Amonite.init(() => {
  Amonite.Page.setContainer(document.body)
  Amonite.Router.listenPopstate()
})
  • Callback cb is called in code init(cb) when window is loaded.
  • Callback cb is called in code initAll(cb) when window is loaded, Page container is set by default on document.body and the Router start listening registered routes.

If you want to load a section with a route when the user has loaded his window, then you should first register components, sections, pages and routes before calling Amonite.init(cb) or Amonite.initAll(cb).

Amonite-Craft contents

Components

  • A Component is a defined HTML node with a template, methods, events scoped.
  • A Section is a component which fill a page: there is only one section in a page.
  • A Page is the component structuring HTML document inserted in body: there is only one page opened at time and only one section in the page.

For examples:

  1. A very simple page with few information like a login, sign in or logout would expect the same light design (where light design is set by Page and where login, sign up and logout are Sections);
  2. A commercial prospecting page, an informative page or a statistic page would expect the same heavy design (where heavy design is set by Page and where prospecting, informative and statistic are Sections).

You can create a Page, a Section or a Component as easy as this (here 1 page, 2 sections):

//  pages have same structure
class MarketPage extends Amonite.Page {
  template () {
    return `<main></main>`
  }

  elements () {
    return {
      section: "main"
    }
  }
}

//  abstracted: all market sections are existing in a MarketPage structure
class MarketSection extends Amonite.Section {
  wrapper () {
    return MarketPage
  }
}

//  list items in this section
class MarketListSection extends MarketSection {
  template () {
    return `<ul>
      <li></li>
      <li></li>
    </ul>`
  }
}

//  show item in this section
class MarketItemSection extends MarketSection {
  template (item) {
    const addLabel = "Add to cart"
    return `<div class="item">
      <p>${item.name}</p>
      <p>${item.description}</p>
      <button>${addLabel}</button>
    </div>`
  }
}

Routes

The webapp can have many routes in many routers, there is no problem. Just keep in mind there is just one controller when no other route match (it could be a 404 error?).

function atFirstCallOnly() {
  // helps to prepare a page or a section, for example
  // ...
}

const router = new Router("/market", atFirstCallOnly)
const list = router.add("/", () => (new MarketListSection()).setSection())
const item = router.add("/item/:integer", (args) => {
  const id = args[2].value
  return (new MarketItemSection(id)).setSection();
})

function error404() {
  // may be a redirection
  // ...
}
Router.setDefault(error404)

In this example :

  • The function atFirstCallOnly() is called one time in all the window session. You can use it if you want to improve your website performance and do the necessary actions before showing page and section.
  • The function Section.prototype.setSection() replaces the current section by this section (important: if the current page is different than this section's page, then the page is also replaced!).
  • The function router.add("route", function exec(args) {}) create a route registered in this router. In the above section, the route list matches when URL path is /market or /market/ (last slash is optional), and the route item matches when URL path is /market/item/123aze (or anything else than "123aze"). The arguments args are extracted from URL (ie: ["", "item", {value: "123aze", type: "integer"}]).

API requests

There is three common ways to send an AJAX request: with collection/model system, with resource/promise system, or with AJAX self configuration. You can use each of them, but they are not developed to be mixed with each others. I prefer resource/promise system :

import { Resource } from "amonite-craft"

class MarketItemRequest extends Resource {
  constructor () {
    this.items = []
  }

  fetch (id) {
    const prom = Resource.request("GET", "//your.api.site/item/" + id)
    const self = this
    prom.then((xhr) => {
      self.updateItem(JSON.parse(xhr.responseText))
    })
    return prom
  }

  list (first = 0, max = 30) { // pagination
    const prom = Resource.request("POST", "//your.api.site/list", {first, max})
    const self = this
    prom.then((xhr) => {
      JSON.parse(xhr.responseText).forEach(self.updateItem.bind(self))
    })
    return prom
  }

  updateItem (data) {
    const item = this.items.find((i) => i.id === data.id)
    if (!item) this.items.push(data)
    else Object.assign(item, data)
  }
}

const req = new MarketItemRequest()
req.list().then((xhr) => {})

Custom HTML Elements

Following Mozilla recommendations for HTML Custom Elements, Amonite declares its own Polyfill for defining Custom HTML Elements. Browsers does not all supports this function and its third parameter, so there is not the third parameter for define().

import { define, CustomHTMLElement } from "amonite-craft"

class PopupInfoHTMLElement extends CustomHTMLElement {
  constructor (node) {
    super()
    node.addEventListener("load", this.load.bind(this))
  }

  load () {
    // when children are all loaded
  }
}
define("popup-info", PopupInfoHTMLElement)

Then just insert HTML element in your template:

<html>
  <body>
    <popup-info></popup-info>
  </body>
</html>

Or with JavaScript common functions:

document.body.appendChild(document.createElement("popup-info"))

My library has a strong improvement: the new custom element trigger the event load only when all of its children are loaded. It is useful when you create child custom elements into your custom element.

import { define, CustomHTMLElement } from "amonite-craft"

class PopupInfoHTMLElement extends CustomHTMLElement {
  constructor (node) {
    super()
    this.node = node
    this.addEventListener("load", node.load.bind(this))
    node.appendChild(this.text = document.createElement("popup-text"))
    node.appendChild(this.close = document.createElement("popup-close"))

    this.close.getAttribute("icon") // is null
  }

  load () {
    // when children are all loaded
    this.node.children // contains popup-text and popup-close loaded
    this.close.getAttribute("icon") // is "close"
  }
}

class PopupTextHTMLElement extends CustomHTMLElement {}

class PopupCloseHTMLElement extends CustomHTMLElement {
  constructor (node) {
    super()
    node.setAttribute("icon", "close")
    node.addEventListener("click", this.click.bind(this))
  }

  click () {
    // do your thing
  }
}

define("popup-info", PopupInfoHTMLElement)
define("popup-text", PopupTextHTMLElement)
define("popup-close", PopupCloseHTMLElement)

The constructor is executed only when inserted in DOM, and only one time.

Simple usage

See examples here

Documentation

See full page here