Skip to content

I want to be able to fill out a survey where the questions are aimed at gamers, with different answer options. If I don't finish the survey, I want to pick up where I left off later.

License

Notifications You must be signed in to change notification settings

RooyyDoe/League-of-legends-survey

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Browser Technologies

For this assignment I will design an interactive application. I need to make sure that all users, with all browsers, can see, hear and/or feel at least the core functionality in every context. The purpose of this assignment is to learn how to make an online interactive application using Progressive Enhancement and Feature Detection so that the application will always work.

Introduction

Case

I want to create a survey with questions aimed at gamers that uses different types of questions, such as open questions, rating questions and multiple choice questions. When a user doesn't finish a survey, the user should be able to come back and pick up where he left off.

The working of my application

When a user opens the application, he/she is given the option to start a new survey or to continue where he/she left off. Each survey will have a unique code. This code allows the user to get back where he/she left off in the survey. Every time the user goes to the next section, the data will be saved to a JSON file and can be extracted by making use of the unique code. The user needs to keep a good hold of the unique code otherwise he/she will not be able to return where he/she left off.

Final Product

Schermafbeelding 2021-03-30 om 18 11 18

Table of contents

Features

Install

Clone the repository of the project

git clone https://github.com/RooyyDoe/browser-technologies-2021.git

Navigate to the map

cd browser-technologies-2021

Install dependencies

npm install

Run server in terminal

npm run dev

Server running on localhost:5000

Demo also will be running live at Questions for gamers

Wireflows

These are the wireflows for the survey, start and end screen. I have annotations next to the wireflows for extra information and will explain under the images what I am going to do as enhancements.

The user flow of the main screens

Enhancements

  1. Progress bar: In the flow of my application I want to create a progress bar that will change its value whenever a user goes to the next section of the survey. With this feature the user will know the percentual progress of the survey towards completion. When the user is done with one section he/she needs to click on the next button and the progress bar will automatically update.
  2. Form validation: My survey is going to exist mainly of inputs and form elements. This is why I want validations. I want to make form validations into my client-side javascript where it checks if the form elements are empty or not filled in and then shows a error message. The fields that are not filled in will be highlighted with an outline.
  3. Highlighting elements: When a user selects an input field, these will automatically be highlighted so the user knows where he/she is. This is also good for people that use tabs to navigate through the application.
  4. Navigation between survey pages: Users will be able to navigate back and forward between survey pages. In this way they can edit their answers if they need to.
  5. localStorage and write/read Json object: I want to be able to get the written data by the users from the localStorage client-side. Whenever Javascript is turned off or localStorage isn't working, I want to have a back-up where the data will come out of a Json file. I will manage the data with a unique code that will be created on the server-side of my application. In this way I can give the users a unique code that they can fill in at the start of my application to get back where they left off in the survey.

301f5cf2-9b30-4892-ba55-8803f18d011d

  1. Responsive Design: I will use the methode: Mobile First to make my application responsive. Next to this method I will make use of the @support rule to check-up if the CSS classes will be supported in all the browsers. When this is not the case I'll figure out a back-up plan, so that every browser can use my application.

Different form elements I am going to use:

  • <form> Element
  • <input>: Checkbox Type
  • <textarea> Element
  • <input>: Text Type
  • <input>: Range Type
  • <select> Element
  • <input>: Radio Button Type
  • <label> Element
The start and end screen

Enhancements

  1. Unique code: Every user that joins my survey will get a unique code that they will have to use when they don't finish the survey and come back later. This code is given whenever a user starts the survey. In the start screen users will be able to see a list of their unique codes and will be able to click on them and get back to where they left off. There will also be an input field where the user can put in one of the existing codes that he/she copied.
  2. Copy to clipboard: Users will be able to copy the unique code from the page without double clicking the code or using the mouse. When the user is navigated to the unique code page the only thing that needs to be done is to click the copy short code from the keyboard, which is for a mac device: cmd + c and for a windows device: ctrl + c.
This is the interface for the personal questions

This will be the first screen when the users starts the survey. They will need to fill in a bit of personal information.

Form questions:

  • First name (Input field)
  • Surname (Input field)
  • Gender (Radio buttons)
  • Age (Only Digits)
  • Gamertag (Input field)
This is the interface for the personal game questions

In de second survey screen the users get a couple more personal questions, but these questions will be mainly linked to gaming.

Form questions:

  • What is your favorite platform? (Input type Range)
  • How much time do you spend on gaming in a day (Input field)
  • Do you prefer multiplayer games or to go solo? (Checkboxes)
  • What's your favorite game genre? (Dropdown list)
  • What is your favorite game? (Input field)
This is the interface for the open game questions

This section is for the open questions. There will be three questions about gaming and I want the opinion of the users about these questions as detailed as they can.

Form questions:

  • What's your favorite game of all time? and why? (Textarea)
  • If video games didn't exist anymore, what would you do? (Textarea)
  • What or who got you into video games in the first place? (Textarea)
This is the interface for the 'Judge A game'

The last part of my survey I will be asking the user's opinion about a game of their choice with the use of a dropdown menu.

Form questions:

  • Choose a game: (Dropdown list)
  • What do you think about this game? (Textarea)
  • Give the game a number 1 - 10 (Input type Range)
  • How much time do you have in the game? (Only digits)
  • Would you recommend this game? (Radio buttons)

Browsers

The browsers I am going to use to test my application on:

Google Chrome (Works perfectly - Browser I designed in)

Firefox

In firefox I had some issues with the viewWidth when using this on the Headlines, but I have adjusted this to the perfect pixel ratio, so it would work on firefox and chrome.

legend > h1 {
font-family: "BeaufortforLOL-bold", Times, serif;
font-size: 5.5vw;
font-weight: bold;
color: #fff;
text-transform: uppercase;
padding-top: 0.5em;
margin: 0px auto;
}

This browser also had some issues with aligning the headlines of every page to the center. This happened, because I had not used the right styling for this. I was using align-self: center, but I just needed to give it a margin: 0px auto and then it was fixed.

I still have an issue with the tabbing through the survey pages. It does not recognize an <a href=""> element when it is tabbed. On all the other elements there will be a blue outlining whenever the user tabs through, but not on the a element. I have not fixed this problem, becaus I did not know how to do that. In the gif under here you see that I can tab on the a element, but it will not put an outline around it.

firefox_bug

Google Chrome android (Works perfectly, because I designed mobile first in the google chrome browser)

standard browser android

In this mobile browser some features of CSS/Javascript are unknown if they are supported, so when I tested this browser a CSS feature did not work. I have used @support for this problem and got it working again. Also some aligning of elements are not working properly on this browser, but it does not make the user experience worse and all the enhancements work perfectly.


fieldset {
margin: 0;
padding: 0;
border: 0;
text-align: -webkit-center;
}

@supports (align-items: center) {
fieldset {
  flex-grow: 1;
  margin: 30px;
  padding: 0;
  border: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
}

Layers

Functional layer

The functional layer is the core functionality of the application which needs to work on every device. Part of the core functionality is that the survey needs to be saved and can be continued later by the user. This part of the application mainly consists of plain HTML and server-side functionalities.

Schermafbeelding 2021-03-30 om 15 35 42

I have added the required attribute to every input that exists in the survey. This will be the core validation of my application. Whenever a user clicks on the input:submit button it will check if all the required fields are filled in and will give a message to the field that is not filled in correctly. Whenever the user has filled in all the fields correctly the data will be writen to the server and linked to a unique code that users will get whenever they start a new survey.

Schermafbeelding 2021-03-30 om 15 51 42

If they leave the survey without finishing it, the unique code is the only way back to continue with the survey where they left off.

Usable layer

The usable layer is an upgrade of the core functionality. This is done through styling and will make your application easier to use.

In the usable layer I want to create a better visual experience for the user. This layer gives the user a better view of how the application works and will make it easier for the user to follow the flow.

Making the application readable

As text styling I have used a couple different colors to separate the labels/inputs from each other. For the headlines I mainly used white and for sub headlines I have used the same as the label's colors. All the colors are in good contrast with the background-color_(This is a images that has a filtered layer)_ and are perfectly visible on every device.

In the headlines I am using viewwidth to scale down the headline whenever a user watches the application from a mobile phone.

Schermafbeelding 2021-03-30 om 16 29 59

These are all buttons!

For all the buttons I have used the same styling and only the buttons that needed to get more attention of the user are bigger. The back and next buttons have both the same layout. This is different in the core functionality. One is an a element and the other is an input:submit element. These two look way different when there is no styling, so by making them look indentical the user will have no issues or difficulties.

Schermafbeelding 2021-03-30 om 16 36 09

Does it @support?

The application needs to work in every browser, so whenever this doesn't work you need to have a fall-back for this. You can look with @support if the CSS styling gets supported in different browsers. Whenever this is supported you run the code, but when a browser does not support this styling it needs to have a fall-back.

fieldset {
 margin: 0;
 padding: 0;
 border: 0;
 text-align: -webkit-center;
}

@supports (align-items: center) {
 fieldset {
   flex-grow: 1;
   margin: 30px;
   padding: 0;
   border: 0;
   display: flex;
   flex-direction: column;
   align-items: center;
 }
}

Making validation more reliable

For the validation I only had the required field on the inputs. I wanted to give the user a bit more feedback on how the input fields needed to be filled in. Next to the feedback on what the users did wrong I also wanted to give the users positive feedback for when they have correctly filled in the input fields. I started by getting all the needed input fields of the page.

const inputs = [...document.querySelector('form').querySelectorAll('input:not([type=hidden]):not([type=submit]), textArea' )]

With this piece of code I have every single input of the current page in an array. Now I can put a forEach around every input and see if they meet the requirements I want the fields to have:

  • Empty string
  • Requires 3 characters
  • Match a pattern
    inputs.forEach(input => {
        input.addEventListener('blur', () => {
            if (input.type === 'text' && !input.pattern.includes('[0-9]+')) {
                if (input.value === '') {
                }
            }
        })
    }

When selected the input I needed to make validations for them, these will exist out of valid and invalid. The ones that are invalid will get a invalid class added to the label and it will also get a .setAttribute() with the error message in it. For the valid one its the other way around and the error message will be empty instead. These error messages will be added to the ::after of the label.

label.classList.add('invalid')
label.setAttribute('error-message', 'Please enter a valid input')
label.setAttribute('error-message', '')
label.classList.add('valid')

When a input field is not correctly filled in, the next submit button will be disabled and when the valid class is added to the label, the button will be enabled again.

// invalid case
document.querySelector('input[type=submit]').disabled = true
// valid case
document.querySelector('input[type=submit]').disabled = false
Pleasurable layer

The pleasurable layer is the layer where we will add extra enhancements for the user to make it more pleasurable. The layer is a bit like the usable layer only not so focused on the look and feel, but more on what extra functionalities I can add to give the user a more pleasurable experience. This layer is also often linked to the client-side javascript.

List with previous surveys

As a user you need to save the unique code you get at the beginning of the survey. When a user forgets this code or loses it, they will never be able to return to the previous survey. I wanted to make an enhancement for this so that the unique code will always be available when the user forgets to copy the code.

Whenever a user comes back to the application and they want to continue with a previous survey, there will be a list on the homepage with all the surveys that are available to resume.

Schermafbeelding 2021-03-29 om 16 15 42

The previous survey list works with localStorage and will not work without it. Whenever the user gets to the get_code page I will save an object to localStorage including the unique code.

  // getting uniqueCode from HTML
  const uniqueCode = document.getElementById('get-unique-code').value
  // Making empty object linked to the uniqueCode for localStorage
  const newSurvey = {
      code: uniqueCode,
      personal: {
          name: "",
          surname: "",
          age: "",
          gender: "",
          favoriteGame: "",
      },
      "game_personal": {
          favoritePlatform: "",
          averageGameTime: "",
          prefer: "",
          favoriteGameGenre: "",
          gamertag: "",
      },
      "open_questions": {
          favoriteGameOfAllTime: "",
          whatWouldYouDo: "",
          intoVideoGames: "",
      },
      "rate_game": {
          opinionAboutTheGame: "",
          rate: "",
          timeSpend: "",
          recommend: "",
      },
  }

  localStorage.setItem(uniqueCode, JSON.stringify(newSurvey)) 

We can call this object in the start page and write the data into an HTML element. In the next section I will explain more about the JSON object in localStorage. At first it was just a plain list of unique codes, where the users could click on and had no further information. This was not that good of a UX design, so I had to change it and give it a bit more information. I have implemented four different use cases:

  • User has just started the survey: The previous survey element will only show the unique code of the survey
  • User has only filled in the name: The previous survey element will show the name and unique code of the survey
  • User has only filled in the favorite game: the previous survey element will show the favorite game and unique code of the survey
  • User has filled in name and favorite game: the previous survey element will show the name and favorite game of the survey

On every page I have a progress bar that shows the user how far they are with the survey. As feedback I heard that it would be nice to see that back in the previous list aswell. So whenever a user has just finished the second part it will show that they have 50% done when they come back to the start page.

Saving data on blur

On the server-side of this application it automatically saves the data to a JSON file and then write it back. I want to enhance this feature into saving the data whenever a user leaves the input field. When a user leaves the survey and has only filled in two fields of a survey page and is going to come back later, both these fields will be filled in already. I am going to do this through localStorage.

localStorage_in_working

This is the function I am using for this enhancement. I am first parsing the data to JSON so that I can use it and after that I will link the current path to the JSON data and only get the data under the name that is equal to the pathname variable.

Then forEach input I am going to fill in the data from the localStorage and when the data change through user input (blur event) I will write the data to localStorage, so that whenever the user leaves early and comes back, the same inputs will be filled in already.

    const progression = () => {
      // Parses the survey object into JSON so we can work with it.
      const currentSurvey = JSON.parse(getCurrentSurvey(uniqueCodeInput))
      // gets the path of current page this title will be the same as the
      // parent object of the fields { personal: {....}} 
      const pathname = form.id
      // sets the data linked to the current page into this variable 
      // { personal: {age: "", favoriteGame: ""}} etc 
      const currentPageData = currentSurvey[pathname]

      // for each input run this code
      inputs.forEach(input => {
          // fills localStorage data into the input.value of each input on this way
          // the data will be visible for the users.
          if (input.type === 'text') input.value = currentPageData[input.name]
          else if (input.type === 'radio' && input.value === currentPageData[input.name]) {
              input.checked = true
          } 
          else if (input.type === 'textarea') input.value = currentPageData[input.name]
          
          input.addEventListener('blur', () => {
              // gets name and value of the input element that has the event blur
              const {name, value} = input
              
              // gets the variable in the JSON object and overrites the value
              currentPageData[name] = value
          
              // Strinigy's the data
              localStorage.setItem(uniqueCodeInput, JSON.stringify(currentSurvey)) 
          })
      })
  }

progression()

CSS / JS support

CSS support

When I am doing CSS I am mainly focussing on divs and classes. This project I tried to focus on ID's and normal CSS attributes like: input[type="text"]. On this way I will not work with too many classes and the HTML code will also be cleaner and in the end the CSS code will be much less lengthy.

As CSS Support I have used the @support attribute to look if a browser supports the styling that you want to add. In this case it was on the android default browser where the text was not aligning to the center, but it stayed at the left side of the screen. When align-items: center is supported in browsers this will be the CSS code that will be send through.

@supports (align-items: center) {
  fieldset {
    flex-grow: 1;
    margin: 30px;
    padding: 0;
    border: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
  }

Whenever this is not supported I will give a fall-back option for the problem:

fieldset {
  margin: 0;
  padding: 0;
  border: 0;
  text-align: -webkit-center;
}

This project I wanted to try to not use the @media attribute as much as I used it in other projects. I mainly worked with width and height and the variable vw for the headlines. Also used flex for the alignment of the form elements.

@media screen and (min-device-width: 1200px) and (max-device-width: 1820px) and (-webkit-min-device-pixel-ratio: 1) {
  header > img {
    left: 49%;
  }

  #form-section {
    width: 40%;
  }
}

I had somme small issues with my header image and it did not stay centered in the firefox browser, so I have just put it to the left a little bit. And the form-section was getting to big when you look at it on a big computer screen. I wanted to have a small form and not a stretched one. Both of the changes could be removed and the CSS layer will still work perfectly. These are just slight adjustments to correct some styling parts.

JS support

As for javascript I haven't had too much issues with finding feature detection support. I am mainly using javascript functionalities that are supported in the browsers I have tested.

In my application some of the functionalities are making use of localStorage. Because of this I want to make sure I can check if localStorage works for the users and if so, it will run the functionalities and when for example javascript or localStorage is off, it will run the code of the fall-back section. Some functionalities can not function without localStorage so these functionalities will not be visible for the user without localStorage.

This is the code that checks if localStorage is available:

const storageAvailable = () => {
  let storage;
  try {
      storage = window['localStorage'];
      var x = '__storage_test__';
      storage.setItem(x, x);
      storage.removeItem(x);
      return true;
  }
  catch(e) {
      return e instanceof DOMException && (
          // everything except Firefox
          e.code === 22 ||
          // Firefox
          e.code === 1014 ||
          // test name field too, because code might not be present
          // everything except Firefox
          e.name === 'QuotaExceededError' ||
          // Firefox
          e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
          // acknowledge QuotaExceededError only if there's something already stored
          (storage && storage.length !== 0);
  }
}
if (storageAvailable()) {
    // Code that will run when localStorage is available
} else (
    // Code that will run when localStorage is not available
)

Fall-back explained

I am not making use of this subject too much into my code next to the one for javascript, so I want to give another example that will explain it in more details. The reason I am not making use of this is that all the browsers that I tested in, worked fine with the javascript code I used. However, when I am going to expand to more browsers this will maybe be a good feature detection option:

function addEventListener() {
    if (window.addEventListener) {
        return true
    } else {
        return false
    }
}

const validateInputs = (inputs) => {
    inputs.forEach(input => {
        if(addEventListener()) {
            input.addEventListener('blur', () => {
                if (input.type === 'text' && !input.pattern.includes('[0-9]+')) {
                    if (input.value === '') {
                        // Some code that will be executed
                    }
                }
            })
        } else {
            input.attachEvent('onblur', () => {
                if (input.type === 'text' && !input.pattern.includes('[0-9]+')) {
                    if (input.value === '') {
                        // Some code that will be executed
                    }
                }
            })
        }
    })
}

The attachEvent was back in the days mainly used for internet explorer and was a good fall-back for the addEventListener, but it is microsoft edge now and in there addEventListener is supported, so in my code it is not needed anymore. So whenever a browser does not support a functionality you want to have a fall-back that is supported in the paticular browser. By doing this your application will work in all the browsers.

What happens if?

Turn off images

In my application I am not using that many images to begin with. I am using a couple SVG images that will be removed, but nothing will happen with the layout and every width/height will stay the same. All the images also have an empty alt, because of this there will be no image placeholders visible. The background image will just be replaced with the background-color.

Schermafbeelding 2021-03-30 om 10 59 39 Schermafbeelding 2021-03-30 om 10 59 19

Next to this I am making use of validation icons that will show if the user has filled in the inputs correctly. As back-up I also made use of an underline message that tells the user if he did something wrong.

Schermafbeelding 2021-03-30 om 11 05 59 Schermafbeelding 2021-03-30 om 11 06 09
Custom font

I am making use of a custom font with @font-face


@font-face {
  font-family: "BeaufortforLOL";
  src: url("../fonts/Beaufort-Regular.ttf"),
    url("../fonts/Beaufort-Regular.woff"),
    url("../fonts/Beaufort-Regular.woff2");
}

When the custom font doesn't load in, I am falling back on my back-up fonts(Times or Serif):

font-family: "BeaufortforLOL", Times, serif;
Color

These are the different colors I use. It is hard to test with a filter attribute on an image. In the second one, the ratio is a bit low and the first one is perfect.

Schermafbeelding 2021-03-30 om 11 58 19 Schermafbeelding 2021-03-30 om 11 59 21
Muis / Trackpad

When the user can only use the keyboard or when the trackpad/mouse is not working, you can use TAB to navigate through the survey. When a user comes back to the application to finish a previous survey, they will have an easy way to select the previous survey and continue with it.

chrome-capture (2)

The user can just TAB to the previous survey and click on Space and will be automatically be returned to the input field and then will be able to click on Enter to go back to this survey.

Breedband internet

I have tested this on slow internet, because if the internet is gone it will just give me a no internet page from the browser. The website will load in, but it will take around 5 - 10 seconds to fully load in. Also the font-family will not load in right away, but it will use the fall-back font.

internet_gif

Javascript

When I turn off Javascript my client-side functionalities will not work anymore. This will mean the localStorage, previous survey list and custom validation will not work anymore. It will fall back on the required attributes of HTML and it will use the server-side to load in the written data from a user. When a user goes to the next survey page the data will be written to a database file and when the user wants to come back to the application, he/she can use the unique code from the previous session to go back where he/she left off.

Turn_Off_javascript

Cookies

I am making no use of cookies in my application, but cookies work together with localStorage. When you turn off cookies, localStorage will also be turned off and the client-side of my application will not work, but as back-up we have the server-side. So the core functionalities will always work.

localStorage

This is where I am making use of feature detection. In this piece of code it will run a try, catch that looks if localStorage is available.


const storageAvailable = () => {
  let storage;
  try {
      storage = window['localStorage'];
      var x = '__storage_test__';
      storage.setItem(x, x);
      storage.removeItem(x);
      return true;
  }
  catch(e) {
      return e instanceof DOMException && (
          // everything except Firefox
          e.code === 22 ||
          // Firefox
          e.code === 1014 ||
          // test name field too, because code might not be present
          // everything except Firefox
          e.name === 'QuotaExceededError' ||
          // Firefox
          e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
          // acknowledge QuotaExceededError only if there's something already stored
          (storage && storage.length !== 0);
  }
}

This will be followed up by an if statement that will run code when localStorage is available.


if( storageAvailable() ) {
 // Code when storage is available
 } else {
 // Storage is not available 
 }
 

Conclusion

After this course, I finally have a better understanding of the terms progressive enhancement and feature detection. These terms where very vague in the beginning and became more and more clear during this course. I am also happy that I was able to turn a robust survey that consisted only of HTML into a fully working survey with all the enhancements included. In addition, my goal was to start working with localStorage and to investigate exactly how this works, so that I could use it in more projects after this one. I think I have performed quite well during this course and that I have created a super cool application in general. Next to all the developer progression I have made, I also overcame fears during this period that caused me to fail last year and I think that that is already quite a victory.

My take on Progressive Enhancement

With Progressive enhancement you make sure the core functionalities work on every device, and then you add extra features when the browsers can handle these features. The core functionalities mostly exist out of plain HTML and server-side functionalities. These functionalities will always work when for example Javascript is turned off. These functionalities can be Account management, Validation, Saving data through a database or JSON, (add, update, remove), etc

The usable layer is an upgrade of the core functionalities. This is done through styling and will make your application easier to use for your users. For example you can change the styling of your headlines/paragraphs, so that it is better readable for your users. Or style the buttons in the application and make the content fully responsive. In this layer you will make mostly use of CSS and a bit of Javascript.

The pleasurable layer is the layer where we will add extra enhancements so that it will be more pleasurable for the users. The layer is a bit like the usable layer only the focus is not that much on the look and feel, but more on what extra functionalities can be added to give the user a more pleasurable experience. This layer is also often linked to the client-side javascript.

My take on Feature Detection

The idea behind feature detection is that you can test whether a feature is supported in the current browser. When it is supported, it will just run the code and when it is not supported, it will run the fall back code. If you don't use feature detection, browsers that do not support the features you are using in your application will not display them properly and will just fail. When this happens you are creating a bad user experience.

In my code a good example is the localStorage. Whenever I make use of localStorage I will first check if it is available and when it is available it will automatically run the code. When it does not support localStorage, it will use the fall-back option of my application and that will be the server-side functionalities of my application.

With the enhancement(localStorage) I am making the user experience more pleasant so that the user does not have to remember the unique code and he can just click on one of the items in the previous survey list, but whenever localStorage is not available, the user needs to copy or remember the code when they want to return to where they left off.

Extra

Opdracht 1 πŸ›Ή NPM install Progressive enhancement

Demo Is running at: Progressive Enhancement

Opdracht 2 πŸ’” Breek het Web

Article notes

Sources

Credits

  • Wessel Smit - BIG thanks for helping me with server-side!!
  • Thijs Spijker - helped me with some issues on the client-side

About

I want to be able to fill out a survey where the questions are aimed at gamers, with different answer options. If I don't finish the survey, I want to pick up where I left off later.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 50.3%
  • Handlebars 36.2%
  • CSS 13.5%