DEV Community

Cover image for SPA with Juris
artydev
artydev

Posted on

SPA with Juris

Here is a fully functional basic SPA app with Juris, in plain Javascript.

You can tweak it here SPA-Juris

import b from 'bss'

b.css({ body: {maxWidth : '1024px', m: '0 auto', ff: 'Segoe UI', bc: '#131323', c: 'white', fw: 300, fs: '1.2rem' }, p:{c:'orange', mt: 8} , a: { mr: '1em', fw: 300, fs: '1.25rem', c: 'white' }, nav: { display: 'flex', jc: 'center', gap: '1rem', mt: '2rem', mb: '2rem' }, h1: { c: '#ff0000', fw: 300 } })

const HomePage = (props, context) => {
  const { getState } = context;
  return {
    render: () => ({
      div: {
        className: () => b`p 3rem ; mt 2rem;border 1px solid #ddd`.class,
        children: [
          {
            h1: {
              text: () => getState('homeTitle')
            }
          },
          {
            p: {
              text: 'Welcome to the reactive Home Page!'
            }
          }
        ]
      }
    })
  };
};

const ContactPage = (props, context) => {
  const { getState } = context;
  return {
    render: () => ({
      div: {
        className: () => b`p 3rem ; mt 2rem;border 1px solid #ddd`.class,
        children: [
          {
            h1: {
              text: () => getState('contactTitle')
            }
          },
          {
            p: {
              text: 'Welcome to the reactive Contact Page!'
            }
          }
        ]
      }
    })
  };
};

const AboutPage = (props, context) => {
  const { getState } = context;
  return {
    render: () => ({
      div: {
        className: () => b`p 3rem ; mt 2rem;border 1px solid #ddd`.class,
        children: [
          {
            h1: {
              text: () => getState('aboutTitle')
            }
          },
          {
            p: {
              text: 'Welcome to the reactive About Page!'
            }
          }
        ]
      }
    })
  };
};

const NotFoundPage = () => ({
  div: {

    children: [
      {
        h1: {

          text: () => 'Page not found'
        }
      }
    ]
  }
});

const RouteRenderer = (props, context) => {
  const { getState } = context;
  return {
    render: () => ({
      div: {

        children: () => {
          const currentRoute = getState('router.currentRoute', '/');

          if (props[currentRoute]) {
            const match = props[currentRoute];
            return Array.isArray(match) ? match : [match];
          }

          if (props.notFound) {
            return Array.isArray(props.notFound) ? props.notFound : [props.notFound];
          }

          return [{ div: { text: '404 - Route not found' } }];
        }
      }
    })
  };
};

const juris = new Juris({
  states: {
    homeTitle: 'Home Page',
    aboutTitle: 'About Page',
    contactTitle: 'Contact Page'
  },
  components: {
    HomePage,
    ContactPage,
    AboutPage,
    NotFoundPage,
    RouteRenderer
  }
});

const App = {
  div: {
    style: () => b`p 32 ff sans-serif bgc #eaeaea`,
    children: [
      {
        nav: {
          children: [
            {
              a: {
                text: '🏠 Home',
                href: '#/',
                style: () => b`m 0 12 c #007acc td none fw 500`
              }
            },
            {
              a: {
                text: '📞 Contact',
                href: '#/contact',
                style: () => b`m 0 12 c #007acc td none fw 500`
              }
            },
            {
              a: {
                text: 'ℹ️ About',
                href: '#/about',
                style: () => b`m 0 12 c #007acc td none fw 500`
              }
            }
          ]
        }
      },
      {
        RouteRenderer: {
          '/': { HomePage: {} },
          '/about': { AboutPage: {} },
          '/contact': { ContactPage: {} },
          notFound: { NotFoundPage: {} }
        }
      }
    ]
  }
};

document.getElementById('app').append(juris.objectToHtml(App));

window.addEventListener('hashchange', () => {
  juris.setState('router.currentRoute', location.hash.slice(1) || '/');
});

Enter fullscreen mode Exit fullscreen mode

Top comments (0)