Skip to content

Project Architecture

Sarah Rooney edited this page Sep 18, 2024 · 22 revisions

netnet.studio Project Architecture

netnet.studio is a "Single Page Application" (SPA), but unlike most modern SPA's which are developed using front end frameworks for creating SPA's (React, Vue, Angular, etc) netnet.studio is vanilla HTML/CSS/JS (...for now anyways, let's see how this develops). At the moment, we haven't found the need to minify, bundle or otherwise obfuscate any of the code in this project. We hope to keep it that way, we prefer it when we can view-source on a website and read through the code to understand what's going on.

*(with the exception of a couple of dependencies: our Netitor library and Fuse.js the third party library which handle's netnet's "fuzzy" search)

The Structure (HTML)

The literal "single page" in this SPA is www/index.html. Apart from the standard meta data in the head, the link element used to include netnet's CSS files and the script elements used to include netnet's JavaScript files, the index page's HTML structure is simply:

<section id="loader">
  <div>&lt;!-- loading (◕ ◞ ◕) &lt;BETA-2.0&gt; --&gt;</div>
</section>

<section id="netnet">
  <div id="nn-output"></div>
  <div id="nn-window">
    <div id="nn-editor"></div>
  </div>
</section>

<section id="loader">: The load screen which disappears once everything is loaded and netnet is ready.

<div id="nn-output">: The parent <section id="netnet"> element contains two children, the first of which is the <div id="nn-output">. netnet's code editor is an instance of netizen's netitor which can (optionally) render the output of it's code into an <iframe>, this <div id="nn-output"> is the parent element for that <iframe>.

<div id="nn-window">: The second child inside <section id="netnet"> is the <div id="nn-window">, this is netnet's main "window". It contains 1 child, the <div id="nn-editor"></div> which is where the instance of the netitor (netizen's code editor) goes.

The Style (CSS)

As is customary among netizens who hand craft their homepages, our index.html is accompanied by an images folder and a css folder. The images directory contains all our graphics, including menu icons and all the svg files that make up netnet's face. The css directory breaks down as follows:

/fonts                # all the fonts we're using
text-bubbles.css      # styles for the <text-bubble> custom element

widget-styles.css     # styles for base Widget class
hvp-ui.css            # styles for the hyper video player widget
reference-widget.css  # styles for the HTML/CSS/JSReference widgets

search-bar.css        # styles for netnet's serach bar
styles.css            # MAIN STYLESHEET

As mentioned in the Setting up a local environment doc, when writing any CSS, we're doing our best to stick to BEM, refer to this post on CSS-Tricks for a general introduction.

main styles

The www/css/styles.css contains the project's main global styles. This includes styles for all the main HTML elements (mentioned in the HTML section above) as well as importing fonts @font-face and setting a handful of CSS variables (defined in the :root rule) used throughout the project. NOTE: css variables can be referenced by any CSS code by using the CSS function var() for example color: var(--fg-color);, but when we need to reference one of these variables in JavaScript we use our utils.getVal('--fg-color') method (more on the global utils object below).

custom element styles

We've created a few custom elements used throughout the project, for the most part their styles are included in their this.innerHTML template strings, with a couple of exceptions:

  • <code-example>: we're using a library called highlight.js to style this element, so that the code snippets shared in these examples match the syntax highlighting in netnet's editor as closely as possible. The default stylesheet for this library is found in the www/css/libs/ folder.
  • <text-bubble>: the custom element used to created netnet's text bubble's has got quite a lot of CSS associated with it, so rather than including these styles in the custom element's this.innerHTML template strings (like the others) we've pulled these out into their own stylesheet text-bubbles.css.

widget styles

Every widget you encounter in netnet is either an instance of the base Widget class (more on that below) or some other Widget extended from this base class. The widget-styles.css is the stylesheet for this base Widget class and thus applies to every widget. Widget's can of course contain their own specific styles, these are either defined in their their this.innerHTML template strings or in a separate stylesheet. At the moment there are two types of widgets that have their own stylesheets, the HyperVideoPlayer www/css/hvp-ui.css and the reference widgets (HTMLReference, CSSReference and JSReference) www/css/reference-widgets.css.

CSS styleguide

As mentioned previously, styles are written using BEM as a class-naming methodology. Declarations are loosely based on Idiomatic CSS.

Don't worry if these concepts are unfamiliar! These aren't strict rules -- but having these systems as guidelines may make it easier to write or find CSS in the repository if you're a new or returning contributor.

BEM

BEM stands for Block, Element, Modifier. It is a methodology of writing class names.

A block is something unique on the page that is independent and meaningful on its own. It can be used in one or more locations across the site. A block is an opportunity to straightforwardly name something with a descriptive class, and should be written in kebob case.

An example would be .pill-btn taken from core/styles/buttons.css. Pills, a rounded design for buttons, are used in multiple places across netnet.

.pill-btn {
  position: relative;

  padding: 5px 15px;
  border: none;
  border-radius: 25px;
  margin-right: 0 5px 0 0;

  color: var(--bg-color);
  background: var(--fg-color);

  ...
}

An element, on the other hand, is entirely dependent on an established block. In other words, it denotes a part of a block that is inside of -- and only meaningful within -- its parent. In the context of cascading styles, elements don't inherit their parent block's styles; rather, they are are semantically tied to their parent blocks due to their specificity. They are written using two underscores to denote its element status: [parent-block]__[child-element].

Good examples of elements can be found in widgets/styles.css.

.widget {
  position: absolute;

  min-width: 200px;
  min-height: 150px;
  
  ...
}

.widget__top {
  display: flex;
  justify-content: space-between;
  align-items: center;

  ...
}

While .widget is a block declaring general styles for widgets, .widget__top is an element that declares styles only for the top bar of a widget. It's not used anywhere on netnet besides on the inside of a widget.

Now, onto modifiers! Once a block or element is established, there may be variations of it for altered use across the site. This is where modifiers come in, distinguished by adding a --[modifier] flag to the class name. Modifiers can be used on a block or element class to change an aspect of its base behavior. They are additive, meaning one block or element can take many modifiers, if necessary. Modifier classes should declare only what it intends to change about its parent class.

An example would be .pill-btn's --secondary state, which features alternative colors and slightly different sizing, used in various cases across netnet (to denote a different meaning or to maintain visibility).

.pill-btn--secondary {
  display: inline-block;

  padding: 5px 10px;
  border: 1px solid var(--netizen-meta);

  color: var(--netizen-meta);
  background-color: var(--bg-color);

  ...
}

When writing HTML, modified classes should be used succeeding their base classes, offering various ways to mix and match core design elements with modified states. [class] [class]--[modifier]. Using the above example to create a secondary pill button would look like this in HTML:

<button class="pill-btn pill-btn--secondary"></button>

Idiomatic CSS

Right now, the only aspect of Idiomatic CSS we're adopting is a consistent declaration order format. We'll likely adopt more in the future.

We're writing declarations in order of related properties. Positioning -> Display -> Box Model (from outside in) -> Color -> Type -> Animation. These are loose rules to adopt going forward with the intention of fleshing out stricter rules as we go!

.selector {
    /* Positioning */
    position: absolute;
    z-index: 10;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;

    /* Display */
    display: inline-block;
    overflow: hidden;
    box-sizing: border-box;
    visibility: visible;
    opacity: 1;

    /* Box Model */
    margin: 10px;
    outline: 1px solid #000;
    border: 10px solid #333;
    padding: 10px;

    /* Color */
    color: #fff;
    background: #000;

    /* Type */
    font-family: sans-serif;
    font-size: 16px;
    text-align: right;
    white-space: nowrap;

    /* Animation */
    transition: color .1s ease;
}

The Logic (JavaScript)

At the moment, we haven't found the need to minify, bundle or otherwise obfuscate any of the JavaScript code in this project. We hope to keep it that way, we prefer it when we can view-source on a website and read through the code to understand what's going on. All the client-side JavaScript code can be found in the following directories:

  • www/convos: This is where we keep the logic and text for various "dialogues" you can have with netnet. For more on how this system works see the Dialogue System doc.
  • www/widgets: this is where all the custom widgets (which extend the base Widget class) are kept. For more on how the Widget system works see the Creating Widgets doc.
  • www/js: this is where all the core JavaScript lives, which breaks down as follows:
/custom-elements  # all our custom HTML elements
/libs             # a couple of third party libraries

Convos.js         # the convo system, see Editing-Dialogue.md
Widget.js         # the base widget class, see reating-Widgets.md

SearchBar.js      # netnet's search bar
Menu.js           # netnet's menu
NetNet.js         # netnet itself

utils.js          # global utility object
main.js           # the main js file (see below)

main.js

The main JavaScript file is www/js/main.js, and handles: setting up all the main event listeners, loading everything that needs to be loaded when you first arrive at the studio and setting up a couple of the global variables NNW, the instance of NetNet.js, and NNE (the instance of the Netitor, see netizenorg/netitor for more on that)

Global Variables

There are a few global variables used throughout the project by various files:

  • NNE: this is the instance of the Netitor, which is netnet's code editor. We maintain this Netitor class (instantiated in main.js) in it's own separate repo, as it's something that can be used on it's own outside the context of the studio, here's a demo

  • NNW: this is the instance of NetNet.js, which essentially is netnet (or the netnet window). You can use this global object to access the instance of netnet's menu (Menu.js) via NNW.menu as well as netnet's search bar (SearchBar.js) via NNW.menu.searchbar

  • WIDGETS: netnet's widget system, For more on how the Widget system works see the Creating Widgets doc.

  • CONVOS: the conversations currently loaded into netnet's dialogue system. For more on how this system works see the Dialogue System doc.

  • utils: the utils.js contains a collection of utility functions shared by various other files throughout the project. For more on these helper functions see the Helpers doc.

  • Maths: a simple JS class with static math functions not included in JavaScript's standard library Math object. This is maintained in a separate repo: Maths.js

  • Color: a simple JS class with static functions for doing different color maths, like converting a hex color value into an hsl string and vice-versa. This is maintained in a separate repo: Color.js

  • Averigua: a simple JS class that checks for all sorts of things, like the type of browser the user is using, whether it's mobile or not, font support, audio support, etc. This is maintained in a separate repo: Averigua.js

Clone this wiki locally