diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..fa3421e --- /dev/null +++ b/src/App.vue @@ -0,0 +1,127 @@ + + + + + + + \ No newline at end of file diff --git a/src/assets/scss/style.scss b/src/assets/scss/style.scss new file mode 100644 index 0000000..e6f3e91 --- /dev/null +++ b/src/assets/scss/style.scss @@ -0,0 +1,35 @@ +// required to get $orange variable +$primary-dark: #737378; +$primary: #d8ba9c; +$secondary: #737378; + +@import "../../../node_modules/bootstrap/scss/functions"; +@import "../../../node_modules/bootstrap/scss/variables"; +@import "../../../node_modules/bootstrap/scss/variables-dark"; +@import "../../../node_modules/bootstrap/scss/maps"; +@import "../../../node_modules/bootstrap/scss/mixins"; +@import "../../../node_modules/bootstrap/scss/utilities"; + +//$card-cap-bg: rgba(var(--#{$prefix}emphasis-color), 1); +:root, +[data-bs-theme="light"] { + --#{$prefix}custom-card-cap-bg: #{to-rgb($primary)}; + --#{$prefix}soup-bg: #{$primary}; +} +:root, +[data-bs-theme="dark"] { + --#{$prefix}custom-card-cap-bg: #{to-rgb($primary-dark)}; + --#{$prefix}soup-bg: #{$primary-dark}; +} + +$card-cap-bg: rgba(var(--#{$prefix}custom-card-cap-bg), .6); +$pagination-active-bg: rgba(var(--#{$prefix}custom-card-cap-bg), 1); +$pagination-active-border-color: rgba(var(--#{$prefix}custom-card-cap-bg), 1); +$pagination-color: rgba(var(--#{$prefix}custom-card-cap-bg), 1); +$pagination-hover-color: var(--#{prefix}card-cap-color); +$form-check-input-checked-bg-color: rgba(var(--#{$prefix}custom-card-cap-bg), 1); +$form-check-input-checked-border-color: rgba(var(--#{$prefix}custom-card-cap-bg), .5); +$form-check-input-bg: rgba(var(--#{$prefix}custom-card-cap-bg), 1); + +// set changes +@import "../../../node_modules/bootstrap/scss/bootstrap"; \ No newline at end of file diff --git a/src/assets/vue.svg b/src/assets/vue.svg new file mode 100644 index 0000000..770e9d3 --- /dev/null +++ b/src/assets/vue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/DaySelection.vue b/src/components/DaySelection.vue new file mode 100644 index 0000000..6c8d7e9 --- /dev/null +++ b/src/components/DaySelection.vue @@ -0,0 +1,37 @@ + + + \ No newline at end of file diff --git a/src/components/Menu.vue b/src/components/Menu.vue new file mode 100644 index 0000000..0af7279 --- /dev/null +++ b/src/components/Menu.vue @@ -0,0 +1,105 @@ + + + \ No newline at end of file diff --git a/src/components/ThemeSelector.vue b/src/components/ThemeSelector.vue new file mode 100644 index 0000000..d0f88aa --- /dev/null +++ b/src/components/ThemeSelector.vue @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..47283e7 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,19 @@ +import { createApp } from 'vue' +import './style.css' +//import 'bootstrap/dist/css/bootstrap.css' +//import 'font-awesome/css/font-awesome.min.css' +import { library } from '@fortawesome/fontawesome-svg-core' +import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' +import { faSun, faMoon, faArrowLeft, faArrowRight } from '@fortawesome/free-solid-svg-icons' +import App from './App.vue' +import { store, key } from './store'; + +library.add(faSun); +library.add(faMoon); +library.add(faArrowLeft); +library.add(faArrowRight); + +const app = createApp(App); +app.component('font-awesome-icon', FontAwesomeIcon) +app.use(store, key); +app.mount('#app'); diff --git a/src/services/restaurantServices.ts b/src/services/restaurantServices.ts new file mode 100644 index 0000000..7ee1a2d --- /dev/null +++ b/src/services/restaurantServices.ts @@ -0,0 +1,23 @@ +import { Meal, Restaurant, RestaurantDay } from "../types/Restaurant" + +const noDataMeals: Meal[] = [ + { + name: "No Data", + description: "The selected restaurant has no data for this day", + isSoup: false, + price: -1 + } +] + +export const restaurantToRestaurantDay = (data: Restaurant[]): RestaurantDay[] => { + const result = []; + for(const restaurant of data) { + result.push({ + id: restaurant.id, + restaurant: restaurant.restaurant, + meals: restaurant.dailymenus[0].meals.length == 0 && restaurant.permanentmeals.length == 0 ? noDataMeals : restaurant.dailymenus[0].meals, + permanentmeals: restaurant.permanentmeals ?? [], + }); + } + return result; +} \ No newline at end of file diff --git a/src/store.ts b/src/store.ts new file mode 100644 index 0000000..9741d95 --- /dev/null +++ b/src/store.ts @@ -0,0 +1,55 @@ +import { InjectionKey } from "vue"; +import { createStore, Store } from 'vuex'; + +export interface State { + darkTheme: boolean + restaurantOrder: Map +} + +export const key: InjectionKey> = Symbol(); + +const restaurantOrderFromLocalStorage = (order: string | null): Map => { + const map = new Map(); + if (!order) { + return map; + } + const entries = order.split(','); + for (let i = 0; i < entries.length; i += 2) { + const key = parseInt(entries[i]); + const value = parseInt(entries[i + 1]); + map.set(key, value); + } + return map; +} + +const storeRestaurantOrder = (order: Map): void => { + let resultString = ""; + for (const [key, value] of order.entries()) { + resultString += key.toString() + "," + value.toString() + "," + } + resultString = resultString.substring(0, resultString.length - 1); + window.localStorage.setItem("restaurantOrder", resultString); +} + +export const store = createStore({ + state: { + darkTheme: window.localStorage.getItem("darkTheme") === "true" ?? false, + restaurantOrder: restaurantOrderFromLocalStorage(window.localStorage.getItem("restaurantOrder")) + }, + mutations: { + toggleDarkTheme(state: State) { + state.darkTheme = !state.darkTheme; + window.localStorage.setItem("darkTheme", state.darkTheme ? "true" : "false"); + }, + updateRestaurantOrder(state: State, payload: { id: number, newIndex: number, oldIndex: number, swapId: number }) { + const { id, newIndex, oldIndex, swapId } = payload; + state.restaurantOrder.set(swapId, oldIndex!); + state.restaurantOrder.set(id, newIndex); + storeRestaurantOrder(state.restaurantOrder); + }, + setRestaurantOrder(state: State, payload: Map) { + state.restaurantOrder = payload + storeRestaurantOrder(state.restaurantOrder); + } + } +}) \ No newline at end of file diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..c2a3e91 --- /dev/null +++ b/src/style.css @@ -0,0 +1,3 @@ +#lunchinator { + font-family: 'Dancing Script', cursive; +} \ No newline at end of file diff --git a/src/types/Restaurant.ts b/src/types/Restaurant.ts new file mode 100644 index 0000000..a3d0a9c --- /dev/null +++ b/src/types/Restaurant.ts @@ -0,0 +1,30 @@ +export type Restaurant = { + id: number + restaurant: string + dailymenus: Menu[] + permanentmeals: Meal[] +} + +export type RestaurantDay = { + id: number, + restaurant: string + meals: Meal[] + permanentmeals: Meal[] +} + +export type Menu = { + meals: Meal[] + day: string +} + +export type Meal = { + name: string + description: string + isSoup: boolean + price: number +} + +export enum Direction { + LEFT, + RIGHT +} \ No newline at end of file diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..74f3dca --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1,8 @@ +/// + +declare module "vuex" { + export * from "vuex/types/index.d.ts"; + export * from "vuex/types/helpers.d.ts"; + export * from "vuex/types/logger.d.ts"; + export * from "vuex/types/vue.d.ts"; +} \ No newline at end of file diff --git a/src/vuex.d.ts b/src/vuex.d.ts new file mode 100644 index 0000000..3619ba2 --- /dev/null +++ b/src/vuex.d.ts @@ -0,0 +1,13 @@ +import { Store } from 'vuex' + +declare module '@vue/runtime-core' { + // declare your own store states + interface State { + darkTheme: boolean + } + + // provide typings for `this.$store` + interface ComponentCustomProperties { + $store: Store + } +} \ No newline at end of file