Coder Social home page Coder Social logo

enoki's Introduction


Enoki is a powerfully simple set of tools and interfaces for creating and managing websites, single-page apps, and whatever else you can imagine. It’s as vanilla as possible, meant to get out of your way, and play nicely with traditional tooling as well as unique environments, such as the peer-to-peer Beaker Browser.

Although fully-featured, Enoki is still early in development. Support for other frameworks and syntax styles are on the roadmap. If something you’d like to see is missing, please feel free to contribute!

Features

Usage

The Enoki module can be used in a variety of ways. For a quick overview in situ, take a look at an example design. For the sake of this readme, let’s just create a fresh little Choo app.

Create a /content directory in the root of your project and make an index.txt file. Pages (and sub-pages) are just folders with their own index.txt files:

title: Enoki Example
----
text: Hey, not bad!

Inside index.js let’s initialize our Choo app and require the enoki/choo plugin which loads our content. If in an environment exposing the Dat API we’ll dynamically read your /content into state. If over HTTP we’ll fallback to static JSON output of state when last edited/built.

var choo = require('choo')
var app = choo()

app.use(require('enoki/choo')())
Expaned Choo example
var html = require('choo/html')

function view (state, emit) {
  var page = state.page
  var children = page().children().sort('title', 'asc').value()

  return html`
    <body>
      <h1>${page.value('title')}</h1>
      <article>${page.value('text')}</article>
      <ul>
        ${children.map(renderChild)}
      </ul>
    </body>
  `

  function renderChild (props) {
    var child = page(props)
    return html`
      <li>
        <a href="${child.value('url')}">${child.value('title')}</a>
      </li>
    `
  }
}

Page API

Enoki provides a super convenient way for traversing flat content state called nanopage. Just pass some content state to the constructor and you’re set.

var Page = require('enoki/page')
var page = new Page(state)

// some examples
var title = page().value('title')
var children = page().children().toArray()
var imageFirst = page().files().value('path')

For a complete list of methods, take a look at the docs!

Enoki Panel

The Enoki Panel is a super extensible interface for managing an Enoki site’s content. It runs entirely client-side in Beaker Browser, and is accessible at panel.enoki.site.

Configuration options

{
  "blueprints": "/blueprints",
  "config": "site.json",
  "content": "content",
  "fallback": "/bundles/content.json",
  "file": "index.txt"
}

It’s recommended to place your configuration in a file called site.json within the root directory of your site. This works like package.json, but for your site. Just as package.json can be read using any number of tools, your site.json can be too.

Alternatively, when using the module, pass the configuration object as the first argument to the Enoki class. When using the Choo plugin, simply pass as the first argument to the returned function.

// using the module
new Enoki(defaults)

// using the choo plugin
app.use(require('enoki/choo')(defaults))

Configuration is progressively constructed, just like package.json: module defaults → site.json → configuration object argument.

Configuration options overview

blueprints

The directory containing your site’s blueprints. These are JSON files describing the fields for the Enoki Panel. Here’s an example of that.

config

The location of the configuration file.

content

The content directory.

fallback

The location of the content state JSON fallback for HTTP.

file.txt

The file containing data for each page. Defaults to index.txt. An alternate could be index.md.

Peer-to-Peer / Dat

The web is becoming re-decentralized! You can use Enoki with Dat in an environment such as Beaker Browser by swapping Node’s fs for the DatArchive API. This enables real-time reading of the archives’s files. Ensure you’re using .readAsync().

HTTP Fallback and CLI

When using Enoki in a Dat environment we use the DatArchive API instead of Node’s fs to read the archive’s files. However, over http Enoki reads a static json file for fallback.

If you’d like to output that static json when developing your site you can use the Enoki cli. It’s possible to watch your content directory for changes by using the --watch flag.

enoki content
enoki content --watch

Dependencies

For specifics on formatting directories and files, take a look at the dependencies’ documentation.

  • smarkt for parsing mixed key/value store and yaml plain text files
  • hypha for turning folders and files into json

Contributing

Enoki is early in development. If you’d like to see support for webpack, or whatever other tooling, feel free to contribute!

enoki's People

Contributors

jondashkyle avatar jongacnik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

enoki's Issues

psa: helpers

These don't necessarily need to be part of enoki core, but these are some helpers which have been coming in handy. Perhaps eventually useful as part of an eventual cheat-sheet. Will keep adding to this as things come up.

var ov = require('object-values')

exports.findbydirname = function (dirname, pages) {
  return ov(pages).find(function (page) {
    return page.dirname === dirname
  })
}

exports.firstfile = function (page) {
  var files = ov(page.files)
  return files.length ? files[0] : null
}

exports.images = function (page) {
  var files = ov(page.files) || []
  return files.filter(function (file) {
    return file.type === 'image'
  })
}

exports.videos = function (page) {
  var files = ov(page.files) || []
  return files.filter(function (file) {
    return file.type === 'video'
  })
}

exports.fileurls = function (files) {
  return ov(files).map(function (file) {
    return file.url
  })
}

Running into a problem when updating my Enoki site, and then hosting it over HTTP via the Dat CLI

Not sure if this is a workflow problem, or an issue with Enoki, as I can't really diagnose it beyond the error I'm getting.

Though it seems to be a problem with how content.json is syncing between local files and my server. (even when running build and then publishing the changes, it seems like the new content.json file isn't being grabbed on the HTTP site)

This is what I'm getting in the devtools:

screen shot 2018-04-13 at 11 46 56 am

The site will render hardcoded elements, but anything relying on Enoki content isn't being rendered.

My DNS shortname updates and works fine on dat://, its just HTTP where changes aren't propagating.

So maybe its a problem with the build script? Or maybe a caching issue?

Let me know if you need any other info from me!

complex yaml

Right now only simple yaml arrays are recognized, ideally we can get this working with more complex yaml structures as well. Examples:

----

field:
  key:
    subfield: value

----

field:
  key:
    - value
    - value
    - value

----

Feature Request: Ability to pass in a Hyperdrive instance

Use Case

Use a browser based hyperdrive/indexeddb instance as the filesystem for enoki content. I'd still like to serve my site over standard HTTP to regular browsers but not rely on the content.json file to provide my content. This would also allow me to write to the drive from regular browsers as well. If I could pass a custom hyperdrive instance, I could do something like the following.

const hyperdrive = require('hyperdrive')
const rai = require('random-access-idb')('db')
const Enoki = require('enoki')

const archive = hyperdrive(rai)
const enoki = new Enoki(archive, defaults)
...

Honestly not sure how feasible this would be, but it seems like it could work and allow for some more flexibility when wanting to use enoki in environments like standard browsers/PWA's and cordova apps where fs access is not available and neither would the DatArchive API's.

Thoughts?

file watch

The dev server works great with recognizing changes to txt files, ideally we can get content rebundles on file(s) update, add, delete as well

Modularize

The core enoki module should simply transform a directory containing content/ and site/ into JSON. The cli, including large dependencies such as budo should be split out into a separate module.

Perhaps this is best done by placing the core of Enoki in enoki-transform, and reserving the enoki namespace for the CLI?

Access to Enoki Panel

Hi @jondashkyle ,
Enoki looks great, i try it, but i have a question : How can i have access to panel ?
I have download the last Enoki starter kit and install it, but when i run command npm start panel, the local url show me the site not the panel.
I'm doing something wrong ?
Many thanks.

question: hasViewOrBlueprint()

Curious whether we can get away without the has hasViewOrBlueprint() check in lib/read/page.js#L56. I think it could make sense to simply make a rule of of 1 .txt file per directory — if it exists, use. It's just a thought, because otherwise it becomes a little more verbose to drop enoki into an app as purely a way to provide content. As it is now, the app needs to contain either a blueprints or a views directory, and there must be files within there which match the names of your .txt files in content.

The ability to just have a content folder where you can put w/e and not have to think about filenames and blueprints etc I think would be a real nice way to use enoki on a lower level.

🍄🔥

Edit: I suppose this gets a little tricky if wanting to use .txt files for file meta data (like Kirby). Maybe the check becomes hasMatchingFile() or something? Just thoughts, the way it works now is perhaps still the best, esp if pushing people to use panel/specific app structure.

Modularize Page method

Enoki exposes a handy Page method for easily traversing content state as generated with hypha. It’s used like this:

var Page = require('enoki/page')

While we should keep that around, it could be useful to break this out into it’s own module, especially as the core enoki module grows with the incoming static output of content state to JSON, as that’s going to include some heavier deps like watch. Think of this similarly to how Choo exposes nanohtml (bel) via require('choo/html'). Helps to keep things focused and small.

Could also be nice to refactor how this is structured a little, just some basic clean up.

@jongacnik

Random Enoki dev experiences/thoughts

I finished updating my old Enoki site to the new Enoki and had a few notes, comments, etc.:

Development Quirks

I never really figured out how to smoothly do development b/c of a few overlapping issues:

  • How the bundles/content.json gets created in the panel is very magical. Took me a bit to figure out that I had to open my site in the panel to get that file created.
    • It'd be cool for development to have something I can run outside the panel to create that file.
  • Confusing how to develop where I was changing content and JS stuff at the same time. It'd be good to specify how to use the panel during theme development.
    • I started by developing as I'd normally do (using a npm start and a local server or something). But that didn't work unless I manually updated content.json.
    • I tried to move to doing development in Beaker but got confused by the workspace thing (think they're aware of the issue there).

Feature/Doc Needs

  • How blueprints works? I have a links section on my homepage and want to add that to the panel. I could probably figure it out but was feeling lazy atm. I'm sure you're aware of this need. =) Just found this in the panel guides section
  • View random sites in Enoki! I want to link to the non-editable Enoki panel for my site (e.g. dat://enoki.panel/?site=dat://<random-key>, to show people how it works. I think this will showcase how easy it is to move data between custom viewers.
  • Deployment tips (to deploy with github pages or similar and dat). Main thing I think will be hard is the single page app stuff. The fallback page part in dat.json was also a bit magic.

Rename enoki.json

There are a few other apps appearing which share a common structure with Enoki. They have similar configuration options, however Enoki uses enoki.json for these options. For these applications to work nicely with each other, this should probably be renamed to something tool-agnostic.

@kodedninja’s orkl project is a good example of such a tool, and uses config.json, which makes sense. I wonder if we should use something self-describing, such as site.json? Consider how npm uses package.json for anything related to the package/module. That level of specificity allows for other json configuration files to be understandable.

Testing

This is super critical to get in place sooner rather than later!

Nested/repeated fields

Hi! Cool project, got me very excited. I’ve been working on similar ideas here: https://github.com/arturi/tent.

Now it’s just a markdown editor with live preview and drag and drop file support, but initially I was playing with an idea of having a configurable field editor: https://github.com/arturi/tent/blob/master/screenshot.jpg.

Have you considered nested/repeated fields? For example: I want to list my favorite places in Tokyo, where Tokyo would be a page, and place would be a field with name, details, picture and link as subfields, and I could add as many of these places as I wanted to.

Caching issues over https

Hey, this is an issue I've been experiencing with more than just Enoki, so please let me know if there's a better place to put it.

I think it's stemming from your start/build scripts (which are fantastic — I copy them over to all of my dat projects now)

Often times, whenever I am ready to push a new version of a project live, it works fine on dat, because its reading the "real" bundle files or w/e, but over https, either the new files aren't getting synced — I think its because the name doesn't change, or something related to how dat picks up on changes to files...

One solution might be to give each new bundle a unique hashed name, and removing the old ones — that way there's no caching of old bundles based on the simple name bundle, and the most recent version will 100% be re-synced. This is how choo's default build script also works, last time I checked.

Let me know if this belongs elsewhere, or if my thinking is totally wrong, and this is a known issue with dat or something.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.