Pages

Pages enable you to create custom content, layouts, and data interactions. While many of the types or resources you create will have many pages automatically generated, pages allows you to extend those defaults.

For now, the pages consist of static content. Later, data sources and much more will be incorporated.

Overview

Pages have two main parts, design and files. Design is where you specify the high-level portion of the page, and files will hold the specific content.

The pages resource was “designed” by Hofstadter Studios to be flexible, reusable, and extensible with the rest of the system.

Let’s take a look.

Design

Here is the design for a couple of pages:

app:
  name: "hof-starter-app"

  pages:

    - name: home
      route: "/"
      files:
        - "pages/home/home.html"
        - "pages/common/footer.html"
      translations:
        - name: en
          file: pages/home/locales/en.json
        - name: es
          file: pages/home/locales/es.json

    - name: about
      route: "/about"
      files:
        - "pages/about/about.html"
        - "pages/common/footer.html"
      translations:
        - name: en
          file: translations/translations.json
        - name: es
          file: translations/translations.json

Each page starts with a “name” and a “route”. The route is the part that will show up in the browser. Overriding a route from a resource, module, or type will cause issues and break your application. There will be similar machanisms for customizing those pages coming soon.

To specify the content of the page, we reference a list of “files” and “translations”. Files are rendered in order on the page, in the main section. Notice that you can share html content between pages.

Translations enable you to create multi-lingual content. The translations themselves are just data which is then referenced in the html files. This means you can have a single layout for consitency and have the language filled in from the data. More on this a little further down this page.

Content

Hofstadter Studios enables you to create any number of pages to accompany your application. At a minimum, you will need to have the home page.

Currently, the frameworks available are React + Bootstrap through the reactstrap library. You may use any of the components there. The thing to know is that you must prepend “RS.” to the component’s opening and closing tags. You also have access to all of bootstrap 4.

For example:

<RS.Alert color="primary">
  This is a primary alert — check it out!
</RS.Alert>

<RS.Container>
  <RS.Row>
    <RS.Col>Look, a column!</RS.Col>
  </RS.Row>
</RS.Container>

The html is injected into the React render() function inside the page layout and styling.

Translations

Translations provide you the method to have internationalization content, also known as “i18n.” In Hofstadter Studios, the language content is data. To see how this works, lets look at the existing home page files.

pages/home/locale/en.json

{
  "title": "Home",
  "meta": "Home example page",
  "loading": "Loading...",
  "messages": {
    "hello": "Hello"
  }
}

pages/home/locale/es.json

{
  "title": "Inicio",
  "meta": "Página de Inicio",
  "loading": "Cargando...",
  "messages": {
    "hello": "Hola"
  }
}

Notice that the json object fileds are the same, and it’s the calues that change. While the field names are in english, this does not matter, only that they have the same shape. How to use the language data in your pages, use the t() function like so:

pages/home/home.html

<h1>{ t('title') }</h1>

<hr />

<p>{ t('messages.hello') } from Hof Starter App</p>

Notice that the format is:

{ t('path.to.language.data') }

There are curly braces (beacuse this is actually injected into JSX code) and the t('...') function is inside of the { ... }.

Another note, you need to close all of your html tags, including <br /> and <hr></hr>. Either form is OK.

Type Pages

Pages for types also have data available for rendering. This uses the React { ... } syntax for accessing the data.

For example, here is the Post view html content.

<Link id="back-button" to="/posts">
  {t('post.btn.back')}
</Link>

<RS.Container>
  <RS.Row>
    <RS.Col lg="8">
			<h1>{ post.title }</h1>
			<h6>by { post.author ? post.author.username : "???"}</h6>
			<hr />
			<pre>{ post.content }</pre> 
		</RS.Col>
	</RS.Row>
</RS.Container>

(regular pages will get data access in an upcoming release)