Coder Social home page Coder Social logo

quaese / formula_one Goto Github PK

View Code? Open in Web Editor NEW
1.0 2.0 0.0 4.45 MB

Tool to manage highscore list for teams playing formula one games

JavaScript 40.18% HTML 0.67% Vue 49.08% CSS 10.07%
vue vuejs vuex font-awesome-5 highscore highscorelist nodejs express

formula_one's Introduction

formula_one

The directories used in the document/manual are relative to a base directory (i.e. formula_one).

Project setup

Prerequisite: Current directory is the base directory.

Frontend (Vue.js)

npm install

Backend (nodejs)

cd backend
npm install

Run server/application in production mode

Prerequisite: Current directory is the base directory.

  1. Start first the backend script to get the current ip address and start the node server
    # change from base directory to backend folder
    cd backend/
    # run start script for production mode
    npm run production
  2. Change back to base directory
    # change back to base directory
    cd ..
  3. Execute build script
    # builds the application in a ./dist folder
    npm run build
  4. Copy content of ./dist folder to a webserver

Run server/services commands for development mode

1. Backend (Nodejs-Server)

Run server

# change to backend directory
cd backend
# run server
npm run start

2. Frontend (Vue.js)

Run app

The app can run with defaults. That means it runs on localhost and current ip address for the host argument. The value for the port argument is 8080.

The app also works with custom values:

  • --host=[ip.address] - replace this with the wanted ip address, e.g. --host=192.168.1.10
  • --port=[port] - replace this with the wanted port number, e.g. --port=4216
# most cases (own port, default ip address and localhost)
npx vue-cli-service serve --port=[port]

# minimal
npx vue-cli-service serve

# run with special ip address and port
npx vue-cli-service serve --host=[ip.address] --port=[port]

Kill app

Kill a process of the app running on a special port. It can run on a default or a custom port (see Run App).

# kill running application on a port (e.g. 4216)
fuser -k [port]/tcp

Visual Studio Code setup

Add the following to ~/Library/Application Support/Code/User/settings.json (mac os)

{
  "vetur.format.defaultFormatter.js": "vscode-typescript",
  "vetur.format.defaultFormatter.html": "js-beautify-html",
  "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
  "eslint.autoFixOnSave": true,
  "eslint.validate": [
    {
      "language": "vue",
      "autoFix": true
    },
    {
      "language": "html",
      "autoFix": true
    },
    {
      "language": "javascript",
      "autoFix": true
    }
  ]
}

See: How to integrate ESLint with Vue.js and Vetur in Visual Studio Code (alligator.io)

More

Compiles and hot-reloads for development

npm run serve

Compiles and minifies for production

npm run build

Run your tests

npm run test

Lints and fixes files

npm run lint

Run your unit tests

npm run test:unit

Customize configuration

See Configuration Reference.

formula_one's People

Contributors

ep-mhoellein avatar quaese avatar

Stargazers

 avatar

Watchers

 avatar  avatar

formula_one's Issues

Add, Edit, Delete for Races

Implement functionalities to

  • add
  • edit
  • delete

races.

Hint

Don't forget to update depending seasons and results.

Create Cards for Seasons and Races

Create cards for seasons and races.

##Basics

  • Card
  • Card-Header
  • Card-Panel

##Requirements

  • one column (key: value) for lower resolutions
  • two columns (key: value) for higher resolutions

Replace location input fields with select boxes in season section

After implementation the admin section (issue #47) the input fields inside the season section can be replaced by select boxes.

Acceptance Criteria

  • input fields to enter locations inside race-cards are replaced by select boxes
  • input field to enter a location inside an add-race-card are replaced by a select box

Nice To Have

  • inside an add-race-card it is also possible to enter a new location (see add item inside result tables highscorelist-itemadd.component.vue)

Wording for Table Header in Results-Table

Translations in the header row of the results table are missing.

  • Platz (position)
  • Name (name)
  • Zeit (time)
  • prev (prev)
  • Aktionen (actions)

Try to find a better wording for 1st (e.g gap, distance) and prev.

Backend - Use different JSON files for state

Use different JSON files when initializing the app the first time and to save the state.

  1. check on first initialization if a JSON file exists to save data (state.json)
  2. if no file exists, use the default initialisation file (init.json) with default content
  3. use the default content to save it in state.json from now on
  4. add state.json to git.ignore?

Add dialog module

Add a module to have the possibility to use dialogs.

ToDo

  • possible Module vuejs-dialog: vue-js on npm (GitHub)
  • this module is available via the vue ui (search for vuejs-dialog)

Maybe there is another better module - check it.

Create Start Script

Create start script for vue app and node server.

Acceptance Criteria

  • start vue app (npx vue-cli-service serve) (not with this task, maybe later) ❌
  • start node/express server (node_modules/.bin/nodemon -e js) ✅

Additional Features

  • get ip address of machine => hand over to vue app with an env.js file ✅

Update ResizeObserver Directive

Update ResizeObserver Directive

Update resize-oberserver.directive.js

import Vue from "vue";
import { debounce } from "../tools/common.tools";

let observer;

export const QPResizeObserver = {
  // eslint-disable-next-line
  bind: function(el, binding, vnode) {
    const handler =
      binding.value && binding.value.handler
        ? binding.value.handler
        : undefined;
    const delay =
      binding.value && binding.value.delay ? binding.value.delay : 200;

    // observe only if a handler is present
    if (handler) {
      // if ResizeObserver API is supported
      if (ResizeObserver) {
        // register observer
        observer = new ResizeObserver(entries => {
          for (let entry of entries) {
            // entry.target is equal to el (observed element)
            if (entry.target === el) {
              handler(el);
            }
          }
        });

        // observe element
        observer.observe(el);
      } else {
        // create unique namespace or use handed over name
        observer =
          binding.value && binding.value.namespace
            ? binding.value.namespace
            : "id_" + new Date().getTime();

        // register native resize event on window object (namespaced)
        window.on(
          "resize." + observer,
          debounce(
            () => {
              handler(el);
            },
            delay,
            false
          )
        );
      }
    }
  },

  unbind: function(el) {
    // unobserve events on unbind event of driective

    if (observer) {
      if (ResizeObserver) {
        observer.unobserve(el);
      } else {
        window.off("resize." + observer);
      }
    }
  }
};

Vue.directive("resize-observer", QPResizeObserver);

Create tools file common.tools.js

const debounce = (func, delay, immediate) => {
  var timeout;

  return () => {
    const context = this,
      // eslint-disable-next-line
      args = arguments;

    const later = function() {
      timeout = null;

      if (!immediate) func.apply(context, args);
    };

    const callNow = immediate && !timeout;

    clearTimeout(timeout);
    timeout = setTimeout(later, delay);

    if (callNow) func.apply(context, args);
  };
};

export { debounce };

Create events-namespace file events.namespace.js

var events = {
  on(event, cb, opts) {
    if (!this.namespaces)
      // save the namespaces on the DOM element itself
      this.namespaces = {};

    this.namespaces[event] = cb;
    var options = opts || false;

    this.addEventListener(event.split(".")[0], cb, options);
    return this;
  },
  off(event) {
    this.removeEventListener(event.split(".")[0], this.namespaces[event]);
    delete this.namespaces[event];
    return this;
  }
};

// Extend the DOM with these above custom methods
window.on = document.on = Element.prototype.on = events.on;
window.off = document.off = Element.prototype.off = events.off;

// Example
/*
window
  .on('mousedown.foo', ()=> console.log("namespaced event will be removed after 3s"))
  .on('mousedown.bar', ()=> console.log("event will NOT be removed"))
  .on('mousedown.baz', ()=> console.log("event will fire once"), {once: true});

// after 3 seconds remove the event with `foo` namespace
setTimeout(function(){
    window.off('mousedown.foo')
}, 3000)
*/

Example 1 - matchMedia (Component.vue)

Observe resize of window object.

<template>
  <div class="about">
    <h1 v-resize-observer="observe" :class="{ red: color }">
      This is an about page
    </h1>
    <logo />
  </div>
</template>

<script>
import AppLogo from "../components/app-logo.component";
import QResizeObserver from "../directives/resize-observer.directive";

const maxWidth = 1000;

export default {
  name: "about",

  components: {
    logo: AppLogo
  },

  data() {
    const self = this;

    return {
      color: false,

      observe: {
        handler: function(el) {
          self.color = self.matchMedia();
        },
        namespace: "unique_namespace",
        delay: 500
      }
    };
  },

  methods: {
    matchMedia() {
      return window.matchMedia(`(max-width: ${maxWidth}px)`).matches;
    }
  }
};
</script>

<style lang="less" scoped>
.red {
  color: red;
}
</style>

Example 2 (Component.vue):

Observe resize of a HTML element.

<!--
  This component renders an animated logo. For the animation vue's *transition* and
  CSS animation (transition) are used. Background images for the animated parts are SVGs.

  @Uses
  - resize.oberserver directive to handle resizing of the logo

  @Props
  - handler - [Function, Boolean] if a function it will be used as callback for the resize oberver,
                                  otherwise the element is not observed by the ResizeObserver and
                                  the dimension get only calculated on the *mounted* hook
-->

<template>
  <div class="qp-logo-wrapper" ref="wrapper" v-resize-observer="observe">
    logo-inhalt
  </div>
</template>

<script>
import "../directives/resize-observer.directive";
import "../tools/events.namespace";

export default {
  name: "app-logo",

  data() {
    const self = this;

    return {
      start: false,
      observe: {
        handler:
          typeof self.handler === "function" ? self.handler.bind(self) : false
        //, namespace: 'unique_namespace'
        //, delay: 200
      }
    };
  },

  props: {
    handler: {
      type: [Function, Boolean],
      // eslint-disable-next-line
      default: function (observedElement) {
        this.calculateHeight(observedElement);
      }
    }
  },

  mounted() {
    // use resize observer if ResizeObserver API exists OR prop to handle resize is not a function (=> element is not observed by the ResizeObserver)
    if (!ResizeObserver || typeof this.handler !== "function") {
      this.calculateHeight(this.$refs.wrapper);
    }

    this.start = true;
  },

  methods: {
    calculateHeight: function(el) {
      el.style.height = parseInt((8 / 29) * el.offsetWidth) + "px";
      console.log(el.style.height);
    }
  }
};
</script>

<style lang="less" scoped>
/* *** Break Points *** */
@small-max-width: 576px;
@medium-max-width: 768px;
@large-max-width: 992px;
@extralarge-max-width: 1400px;

@formula-result-max-width: 1050px;

.qp-logo-wrapper {
  width: 100%;
}

@media (max-width: @large-max-width) {
  li {
  }
}
</style>

Content Improvements

Content Improvements

To Do:

  • add git hub link to provide the possibility to add issues ✔️
  • design home page and add some texts ✔️
  • remove unused routes from nav bar ✔️

Ideas / Questions

GitHub link

  • add footer?
  • as badge in header?

Done with github-corners - thanks to @tholman for providing github-corners

Mark for Deletion Functionality

Add a functionality to mark results for deletion. It can be deleted in a special routine later.

Solution hints

  • add property marked to result objects
  • marked property is set to false initially (default)
  • display just results with marked set to false

Add Drivers Section to State and App

Add drivers section to state:

  • expand state with driver section "drivers": { "driver1": { "name": "qp" }, "driver2": { "name": "Hoshi" } }}
  • add driver dropdown to results list

Secret Gist: state.json

Add Administration Section

Add administration section.

  • driver administration (add, remove, update)
  • location administration (add, remove, update)

Further tasks

  • Add locations part to state.json file. Connect the locations via IDs (location_id) to the corresponding races and remove the real names from the race objects.

Cancel Button doesn't work in error case

Cancel button doesn't work in error case.

How to reproduce

  • go to results table
  • add new result
  • enter incorrect values (e.g. 00000 for time)
  • press cancel
    => nothing happens!

Use fix images for seasons

Use fix images for seasons. Currently the header images for seasons change on each interaction.

Acceptance criteria

  • on add/create a season a image is added
  • if a season has no image it will be added if the season is rendered
  • use a random image from an image pool (directory: @/assets/images/cardheader/)

Design Improvements

From feedback

  • bigger font-size for result table (use media query max-width: 1050px) ✅
  • use hashtag as header text for position column ✅
  • arrange action icons on upon the other => fix small width for actions column ✅
  • use container-fluid for top level container (App.vue) if width < max-width = 1050px

Create Animation for Logo

Create an animation component using transition for the logo.

  • use transition
  • use SVG parts to build the logo
  • start the animation on mount or a useful router event

Acceptance Criteria

  • create component for animated logo ✔️
  • use directive with ResizeObserver for logo recalculation on window resize ✔️
  • use vue js transition component to handle animation ✔️
  • use CSS transition to animate SVG parts ✔️
  • use animated logo at ✔️
    • homepage ✔️
    • nav bar ✔️

Collection task for smaller improvements

This is a task to collect smaller issues and ideas:

  • save result in result list on pressing enter key ✔️
  • correct german wording on Home section ("besitzen" instead of "besitzt" in description) ✔️
  • wrong driver name is displayed in card component ✔️
  • first place in highscore list doesn't get updated if it was created and changed before another entry was modified ✔️
  • sort race overview page by date ✔️ (done with PR #46)

Component for Layered Action Icons

Create components for layered action icons.

Action icons are built with font awesome components. There are two types of action icons:

  1. simple icons (just a font-awesome-icon component) => no change needed
  2. layered icons (always stacked an icon to a circle) => can become a component

Improve Error Handling

Improve error handling for input fields in highscorelist-item.component.vue and highscorelist-itemadd.component.vue.

Acceptance Criteria

  • highlight field that has the error
  • set focus in invalid field?
  • if more than one invalid exist than all get the highlight and the first one gets the focus

Possible Solution

  • validate directive for input fields
  • directive register events can be fired to mark a field as invalid

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.