diff --git a/pants/diary/serializers.py b/pants/diary/serializers.py index fc24a1e..6e896d3 100644 --- a/pants/diary/serializers.py +++ b/pants/diary/serializers.py @@ -5,6 +5,12 @@ class DiaryFoodSerializer(serializers.HyperlinkedModelSerializer): nutrition_data = serializers.ReadOnlyField() + def create(self, validated_data): + # Ensure the current user is specified + if 'user' not in validated_data: + validated_data['user'] = self.context['request'].user + return DiaryFood.objects.create(**validated_data) + class Meta: model = DiaryFood diff --git a/pants/diary/views.py b/pants/diary/views.py index d8aea6e..c97c96f 100644 --- a/pants/diary/views.py +++ b/pants/diary/views.py @@ -51,6 +51,9 @@ class DiaryFoodViewSet(viewsets.ModelViewSet): serializer_class = DiaryFoodSerializer permission_classes = [permissions.DjangoModelPermissions] queryset = DiaryFood.objects.none() # Required for DjangoModelPermissions to get Model + filterset_fields = { + 'start_time': ['gte', 'lte', 'exact', 'gt', 'lt'], + } def get_queryset(self): user = self.request.user diff --git a/pants/frontend/static/frontend/favicon.ico b/pants/frontend/static/frontend/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/pants/frontend/static/frontend/favicon.ico differ diff --git a/pants/frontend/static/frontend/js/app.js b/pants/frontend/static/frontend/js/app.js new file mode 100644 index 0000000..c2327e2 --- /dev/null +++ b/pants/frontend/static/frontend/js/app.js @@ -0,0 +1,1309 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // install a JSONP callback for chunk loading +/******/ function webpackJsonpCallback(data) { +/******/ var chunkIds = data[0]; +/******/ var moreModules = data[1]; +/******/ var executeModules = data[2]; +/******/ +/******/ // add "moreModules" to the modules object, +/******/ // then flag all "chunkIds" as loaded and fire callback +/******/ var moduleId, chunkId, i = 0, resolves = []; +/******/ for(;i < chunkIds.length; i++) { +/******/ chunkId = chunkIds[i]; +/******/ if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) { +/******/ resolves.push(installedChunks[chunkId][0]); +/******/ } +/******/ installedChunks[chunkId] = 0; +/******/ } +/******/ for(moduleId in moreModules) { +/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { +/******/ modules[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(parentJsonpFunction) parentJsonpFunction(data); +/******/ +/******/ while(resolves.length) { +/******/ resolves.shift()(); +/******/ } +/******/ +/******/ // add entry modules from loaded chunk to deferred list +/******/ deferredModules.push.apply(deferredModules, executeModules || []); +/******/ +/******/ // run deferred modules when all chunks ready +/******/ return checkDeferredModules(); +/******/ }; +/******/ function checkDeferredModules() { +/******/ var result; +/******/ for(var i = 0; i < deferredModules.length; i++) { +/******/ var deferredModule = deferredModules[i]; +/******/ var fulfilled = true; +/******/ for(var j = 1; j < deferredModule.length; j++) { +/******/ var depId = deferredModule[j]; +/******/ if(installedChunks[depId] !== 0) fulfilled = false; +/******/ } +/******/ if(fulfilled) { +/******/ deferredModules.splice(i--, 1); +/******/ result = __webpack_require__(__webpack_require__.s = deferredModule[0]); +/******/ } +/******/ } +/******/ +/******/ return result; +/******/ } +/******/ +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // object to store loaded and loading chunks +/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched +/******/ // Promise = chunk loading, 0 = chunk loaded +/******/ var installedChunks = { +/******/ "app": 0 +/******/ }; +/******/ +/******/ var deferredModules = []; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = "/static/frontend/"; +/******/ +/******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || []; +/******/ var oldJsonpFunction = jsonpArray.push.bind(jsonpArray); +/******/ jsonpArray.push = webpackJsonpCallback; +/******/ jsonpArray = jsonpArray.slice(); +/******/ for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]); +/******/ var parentJsonpFunction = oldJsonpFunction; +/******/ +/******/ +/******/ // add entry module to deferred list +/******/ deferredModules.push([0,"chunk-vendors"]); +/******/ // run deferred modules when ready +/******/ return checkDeferredModules(); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js&": +/*!*************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=script&lang=js& ***! + \*************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var js_cookie__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! js-cookie */ \"./node_modules/js-cookie/src/js.cookie.js\");\n/* harmony import */ var js_cookie__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(js_cookie__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _assets_js_pants_api__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/assets/js/pants_api */ \"./src/assets/js/pants_api.js\");\n/* harmony import */ var _components_pages_layouts_layout_default__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @/components/pages/layouts/layout-default */ \"./src/components/pages/layouts/layout-default.vue\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n // Configure the Pants API based on what authentication is available.\n// If django is serving this SPA, then we can use the csrftoken it provides (preferred)\n// If this SPA is being served elsewhere, then the user will need to provide their user name and password for PANTS\n// THIS REQUIRES HTTPS TO BE SECURE. If this frontend uses http to connect to the backend, then the user name and password will be transmitted in plain text as http headers.\n\nlet pantsAuthentication = {};\n\nif (js_cookie__WEBPACK_IMPORTED_MODULE_0___default.a.get(\"csrftoken\") === undefined) {\n pantsAuthentication.method = \"Basic\"; // @todo the the vue app should provide this username and password?\n\n pantsAuthentication.username = \"\";\n pantsAuthentication.password = \"\";\n} else {\n pantsAuthentication.method = \"Token\";\n pantsAuthentication.token = js_cookie__WEBPACK_IMPORTED_MODULE_0___default.a.get(\"csrftoken\");\n} // If the API is served from the same hostname as the frontend, set this to undefined. If not, you should set this value\n// to the hostname the API will be served at e.g. \"https://localhost:8000\"\n// const API_HOSTNAME = undefined;\n\n\nconst API_HOSTNAME = \"http://localhost:8000\";\nlet pants = new _assets_js_pants_api__WEBPACK_IMPORTED_MODULE_1__[\"default\"]('1', pantsAuthentication, API_HOSTNAME);\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: 'App',\n components: {\n LayoutDefault: _components_pages_layouts_layout_default__WEBPACK_IMPORTED_MODULE_2__[\"default\"]\n },\n provide: {\n pants: pants\n },\n\n data() {\n return {\n menu_items: {\n home: {\n url: '/',\n icon: 'home'\n },\n ingredient_manager: {\n url: '/ingredient_manager',\n icon: 'carrot'\n },\n recipe_manager: {\n url: '/recipe_manager',\n icon: 'hamburger'\n },\n diary: {\n url: '/diary',\n icon: 'book'\n },\n target_manager: {\n url: '/target_manager',\n icon: 'bullseye'\n },\n login: {\n url: '/login',\n icon: 'user'\n }\n }\n };\n }\n\n});\n\n//# sourceURL=webpack:///./src/App.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/cell-renderers/action-button.vue?vue&type=script&lang=js&": +/*!*************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/cell-renderers/action-button.vue?vue&type=script&lang=js& ***! + \*************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.runtime.esm.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].extend({\n data() {\n return {\n icon: null,\n onClick: null,\n rowData: null\n };\n },\n\n beforeMount() {\n this.rowData = this.params.data;\n this.onClick = this.params.onClick;\n this.icon = this.params.icon;\n }\n\n}));\n\n//# sourceURL=webpack:///./src/components/cell-renderers/action-button.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/informational/target-summary.vue?vue&type=script&lang=js&": +/*!*************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/informational/target-summary.vue?vue&type=script&lang=js& ***! + \*************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_es_array_reduce__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.array.reduce */ \"./node_modules/core-js/modules/es.array.reduce.js\");\n/* harmony import */ var core_js_modules_es_array_reduce__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_array_reduce__WEBPACK_IMPORTED_MODULE_0__);\n\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"target-summary\",\n props: {\n // The value shown can either be a number, or an array of numbers that will be summed together for the final display\n value: {\n type: [Number, Array],\n required: true\n },\n targetMinValue: {\n type: Number,\n required: true // @todo should the min and max be required? There is usually no min cost, and sometimes no max protein for ex.\n\n },\n targetMaxValue: {\n type: Number,\n required: true\n },\n // A proposed relative amount (e.g. +2, -3, etc). If set, the value shown will be the value + proposedChange\n // and what proportions of the total value are the original value and proposed change will be made obvious\n // @todo support negative changes better\n proposedChange: {\n type: Number,\n default: null\n },\n // If set, the provided color will be used instead of the automatic yellow/green/red for under/within/over\n // target. If an array of colors is provided then:\n // - If the value is a single number, the first color is in the array is used\n // - If the value is an array of numbers, the colors will be used in order for each piece portion of the value\n // This is useful for helping to correlate how the portions of different targets are contributed by the same food.\n // If the color for a given index is null, the default yellow/green/red will be used\n valueColors: {\n type: [String, Array],\n default: null\n }\n },\n\n data() {\n return {\n // If true, the target value and other additional values will be shown\n forceDetail: false,\n // If the summary currently has the mouse over it\n hovering: false\n };\n },\n\n computed: {\n // Ensures the value is an array of numbers, even if a single number is passed in\n valueAsArray() {\n if (Array.isArray(this.value)) return this.value;\n return [this.value];\n },\n\n // Ensures the value is a single number, even if an array of numbers is passed in\n valueAsNumber() {\n if (typeof this.value === 'number') return this.value;\n return this.value.reduce((sum, val) => sum + val);\n },\n\n // Determines the actual shown value, including any proposed change\n displayValue() {\n return this.valueAsNumber + (this.proposedChange || 0);\n },\n\n // Gets the largest value we consider, whether that's one of the targets, or the displayValue itself\n largestValue() {\n return Math.max(this.displayValue, this.targetMaxValue, this.targetMinValue);\n },\n\n // An array of percentages, corresponding to what percent of the largest value each value component takes up\n percentValues() {\n return this.valueAsArray.map(val => val / this.largestValue);\n },\n\n percentProposed() {\n return this.proposedChange / this.largestValue;\n },\n\n percentRemaining() {\n return 1 - this.displayValue / this.largestValue;\n },\n\n percentMin() {\n return this.targetMinValue / this.largestValue;\n },\n\n percentMax() {\n return this.targetMaxValue / this.largestValue;\n },\n\n /**\n * Determines if greater detail should be shown for this component\n */\n showDetail() {\n return this.forceDetail || this.hovering;\n }\n\n }\n});\n\n//# sourceURL=webpack:///./src/components/informational/target-summary.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/inputs/input-checkbox.vue?vue&type=script&lang=js&": +/*!******************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/inputs/input-checkbox.vue?vue&type=script&lang=js& ***! + \******************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"input-checkbox\",\n props: {\n // Unique id for this checkbox\n id: String,\n // The actual value for the checkbox\n value: Boolean,\n // The label for the checkbox\n label: String\n },\n\n data() {\n return {};\n },\n\n computed: {\n // Handles getting and setting value, which is controlled by a v-model\n internalValue: {\n get() {\n return this.value;\n },\n\n set(newValue) {\n this.$emit('input', newValue);\n }\n\n }\n }\n});\n\n//# sourceURL=webpack:///./src/components/inputs/input-checkbox.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/inputs/input-float.vue?vue&type=script&lang=js&": +/*!***************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/inputs/input-float.vue?vue&type=script&lang=js& ***! + \***************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var imask__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! imask */ \"./node_modules/imask/esm/index.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"input-float\",\n props: {\n // Unique identifier for this input\n id: {\n type: String,\n required: true\n },\n // Determines what name the input should have\n name: {\n type: String,\n default: ''\n },\n // What type of input to create\n type: {\n type: String,\n default: 'text'\n },\n // If we expect multiline input\n multiline: {\n type: Boolean,\n default: false\n },\n // What the floating label should say\n label: {\n type: String,\n default: ''\n },\n // Object of additional attributes that should go on this input\n extra: Object,\n // Object of additional attributes that should go on the container for this input\n container_extra: Object,\n // input mask is for js input masking options with IMask library.\n // Should be the name of a named mask in this element\n // TODO make it so that you can specify your own mask?\n input_mask_name: String,\n // @todo hint support\n // hint is a paragraph explaining what could be put in, or limitations to inputs. Possibly should be made visible on focus\n hint: {\n type: String,\n default: ''\n },\n // Determines what value the input should currently hold\n value: [String, Number],\n\n /* @todo value getter setter\n get value(){\n return this.querySelector(`[name=\"${this.id}\"]`).value;\n }\n set value(value){\n this.querySelector(`[name=\"${this.id}\"]`).value = value;\n // If this has an input mask, the mask's internal value will need to be synchronized.\n if(this.input_mask){\n this.input_mask.updateValue();\n }\n if(this.type === \"select\"){\n // Need to trigger a change so that the data-picked_option updates\n let evt = document.createEvent(\"HTMLEvents\");\n evt.initEvent(\"change\", false, true);\n this.querySelector(`[name=\"${this.id}\"]`).dispatchEvent(evt);\n }\n }\n */\n\n /* Determines if the default option for select inputs should be hidden so that it cannot be picked manually*/\n hideDefaultOption: {\n type: Boolean,\n default: false\n },\n // If the input should be disabled or not\n disabled: {\n type: Boolean,\n default: false\n }\n },\n data: function () {\n return {\n /* Input Mask */\n named_masks: {\n // Mask that ensures only 6 total digits, max 3 decimals\n 'nutrition_mask': {\n mask: /^(?=^[\\d.]{0,7}$)\\d{0,6}(\\.\\d{0,3})?$/\n },\n // Mask that ensures only lowercase letters, numbers and dashes\n \"slug_mask\": {\n mask: /^[0-9a-z-]*$/\n },\n // Ensures only lowercase letters, numbers, dashes, and commas\n \"tag_mask\": {\n mask: /^[0-9a-z,-]*$/\n }\n },\n // The actual input mask created by IMask\n input_mask: undefined,\n // The actual contents of the input\n content: \"\"\n };\n },\n\n mounted() {\n if (this.input_mask_name) {\n this.input_mask = Object(imask__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(this.$refs.input, this.named_masks[this.input_mask_name]);\n }\n },\n\n watch: {\n value: {\n immediate: true,\n handler: function (newVal) {\n if (this.input_mask) {\n this.input_mask.unmaskedValue = newVal !== null && newVal !== void 0 ? newVal : \"\";\n } else {\n this.content = newVal !== null && newVal !== void 0 ? newVal : \"\";\n }\n }\n }\n },\n methods: {\n /**\n * Add an option if the input type is a select\n * @param value {string} the value of the new option\n * @param text {string} the text of the new option\n */\n addOption(value, text) {\n if (this.type === 'select') {\n let new_option = document.createElement('option');\n new_option.value = value;\n new_option.innerText = text;\n this.querySelector(`[name=\"${this.id}\"]`).appendChild(new_option);\n }\n },\n\n /**\n * Emits the input event with appropriate data when the value of the input field changes\n */\n handleInput() {\n this.$emit('input', this.input_mask ? this.input_mask.masked : this.content);\n }\n\n }\n});\n\n//# sourceURL=webpack:///./src/components/inputs/input-float.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/diary.vue?vue&type=script&lang=js&": +/*!********************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/diary.vue?vue&type=script&lang=js& ***! + \********************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_es_string_replace__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.string.replace */ \"./node_modules/core-js/modules/es.string.replace.js\");\n/* harmony import */ var core_js_modules_es_string_replace__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_string_replace__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/web.dom-collections.iterator */ \"./node_modules/core-js/modules/web.dom-collections.iterator.js\");\n/* harmony import */ var core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _components_inputs_input_float__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @/components/inputs/input-float */ \"./src/components/inputs/input-float.vue\");\n/* harmony import */ var ag_grid_vue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ag-grid-vue */ \"./node_modules/ag-grid-vue/main.js\");\n/* harmony import */ var ag_grid_vue__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(ag_grid_vue__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ag-grid-community/dist/styles/ag-grid.css */ \"./node_modules/ag-grid-community/dist/styles/ag-grid.css\");\n/* harmony import */ var ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ag-grid-community/dist/styles/ag-theme-balham.css */ \"./node_modules/ag-grid-community/dist/styles/ag-theme-balham.css\");\n/* harmony import */ var ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _components_informational_target_summary__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @/components/informational/target-summary */ \"./src/components/informational/target-summary.vue\");\n\n\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n// Setup variables to access form inputs\n\n\n\n\n // Setup obvious defaults, if you are coming here you probably want to record what happened right now\n// @todo set up the 'current time' just before its seen/used rather than on load to prevent stale times getting logged\n\nlet sysDate = new Date(); // This conversion is necessary to get the datetime as the user would expect it to look\n\nlet userDate = new Date(Date.UTC(sysDate.getFullYear(), sysDate.getMonth(), sysDate.getDate(), sysDate.getHours(), sysDate.getMinutes(), 0)); // The time input element doesn't support seconds, so the seconds value doesn't matter\n\nconst _static = {\n // Enum describing how specific the user wants to be when specifying the time of an entry\n timeSpecificity: {\n JUST_NOW: 'just-now',\n TODAY_AT: 'today-at',\n ON_DATETIME: 'on-datetime'\n },\n // Enum describing the various time periods that can be selected for viewing the diary\n timePeriod: {\n PAST_24: 0,\n TODAY: 1,\n YESTERDAY: 2\n },\n text: {\n changeTimeBtn: {\n 'just-now': \"Just now,\",\n 'today-at': \"Today at\",\n 'on-datetime': \"On\"\n }\n },\n icons: {\n nutrients: {\n cost: \"money-bill-alt\",\n kilojoules: \"bolt\",\n protein: \"egg\",\n carbohydrate: \"bread-slice\",\n fat: \"tint\",\n saturatedfat: \"tint-slash\",\n fibre: \"seedling\",\n sodium: \"stroopwafel\",\n sugar: \"cubes\"\n }\n },\n units: {\n cost: '$',\n kilojoules: 'kcal',\n protein: 'g',\n carbohydrate: 'g',\n fat: 'g',\n saturatedfat: 'g',\n fibre: 'g',\n sodium: 'mg',\n sugar: 'g'\n },\n entryType: {\n RECIPE: \"recipe\",\n INGREDIENT: \"ingredient\",\n ONE_OFF_FOOD: \"one-off-food\"\n },\n // A template object showing all the nutrient keys we care about\n nutrientValues: {\n cost: null,\n kilojoules: null,\n protein: null,\n carbohydrate: null,\n fat: null,\n saturatedfat: null,\n fibre: null,\n sodium: null,\n sugar: null\n },\n // The current day and time\n now: new Date()\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"diary\",\n components: {\n TargetSummary: _components_informational_target_summary__WEBPACK_IMPORTED_MODULE_6__[\"default\"],\n InputFloat: _components_inputs_input_float__WEBPACK_IMPORTED_MODULE_2__[\"default\"],\n AgGridVue: ag_grid_vue__WEBPACK_IMPORTED_MODULE_3__[\"AgGridVue\"]\n },\n inject: ['pants'],\n\n data() {\n return {\n staticVals: _static,\n timeSpecificity: _static.timeSpecificity.JUST_NOW,\n // The users current daily target, by which all nutrient amounts are compared\n currentTarget: null,\n // The current proposed entry\n entry: {\n date: userDate.toISOString().split('T')[0],\n time: userDate.toISOString().split('T')[1].slice(0, 5),\n unit: \"weight\",\n amount: 100 // For nutrition calculations (the server would normally handle this but we pre-calculate on the front end for visualization)\n // See the 'proposedEntryNutrients' computed property.\n\n },\n // Stores the currently selected recipe/ingredient\n selected: {\n recipe: null,\n ingredient: null\n },\n entryType: \"recipe\",\n // The currently input one off food values\n // @todo this is the same nutrient set as for target\n oneOffFood: { ..._static.nutrientValues\n },\n recipeGrid: {\n gridOptions: {},\n columnDefs: [{\n headerName: \"Name\",\n field: \"name\"\n }, {\n headerName: \"Description\",\n field: \"description\"\n }, {\n headerName: \"Serves\",\n field: \"serves\"\n }, {\n headerName: \"Notes\",\n field: \"notes\"\n }],\n defaultColDef: {\n flex: 1,\n sortable: true,\n resizable: true\n },\n rowModelType: 'infinite',\n rowSelection: 'single',\n pagination: true,\n paginationAutoPageSize: true,\n // Set up the grid to paginate using the server side API\n datasource: {\n getRows: async params => {\n // params.searchKey = document.querySelector('#recipe_filter').value;\n let response = await this.pants.get_recipes(params);\n\n if (response.ok) {\n let data = await response.json();\n params.successCallback(data['results'], data['count']);\n } else {\n params.failCallback();\n }\n }\n }\n },\n componentsGrid: {\n gridOptions: {},\n columnDefs: [{\n headerName: \"Name\",\n field: \"name\"\n }, {\n headerName: \"Description\",\n field: \"description\"\n }, {\n headerName: \"Serving\",\n field: \"serving\"\n }, {\n headerName: \"Notes\",\n field: \"notes\"\n }],\n defaultColDef: {\n flex: 1,\n sortable: true,\n resizable: true\n },\n rowModelType: 'infinite',\n rowSelection: 'single',\n pagination: true,\n paginationAutoPageSize: true,\n // Set up the grid to paginate using the server side API\n datasource: {\n getRows: async params => {\n //params.searchKey = document.querySelector('#ingredient_filter').value;\n let response = await this.pants.get_ingredients(params);\n\n if (response.ok) {\n let data = await response.json();\n params.successCallback(data.results, data.count);\n } else {\n params.failCallback();\n }\n }\n }\n },\n dailyTarget: {\n min: { ..._static.nutrientValues\n },\n max: { ..._static.nutrientValues\n }\n },\n // All the foods eaten in the last 24 hours\n diaryFoods: [],\n // If not null, an index indicating which diaryFood should be highlighted at the moment\n highlightedFood: null,\n targetTimePeriod: _static.timePeriod.PAST_24\n };\n },\n\n beforeMount() {\n this.pants.Target.getDaily().then(resp => {\n let target = resp.results[0];\n\n for (let nutrient of Object.keys(this.staticVals.nutrientValues)) {\n this.dailyTarget.max[nutrient] = parseFloat(target.maximum[nutrient]) || 0;\n this.dailyTarget.min[nutrient] = parseFloat(target.minimum[nutrient]) || 0;\n }\n }); // Get all DiaryFood entries for the chosen time period\n\n this.refreshTimePeriodDiaryFoods();\n },\n\n computed: {\n /**\n * The total for each nutrient we are tracking of all foods entered in the last 24 hours\n * @returns {{}}\n */\n diaryFoodNutrientTotals() {\n let totals = { ...this.staticVals.nutrientValues\n };\n this.diaryFoods.forEach(entry => {\n for (let nutrient of Object.keys(totals)) {\n if (totals[nutrient] == null) totals[nutrient] = 0;\n totals[nutrient] += parseFloat(entry[nutrient]) || 0;\n }\n });\n return totals;\n },\n\n /**\n * Gets an array of each nutrient value across all diary foods\n */\n diaryFoodNutrientArray() {\n let totals = { ...this.staticVals.nutrientValues\n };\n this.diaryFoods.forEach(entry => {\n for (let nutrient of Object.keys(totals)) {\n if (totals[nutrient] == null) totals[nutrient] = [];\n totals[nutrient].push(parseFloat(entry[nutrient]) || 0);\n }\n });\n return totals;\n },\n\n /**\n * The nutrients that would be added if we were to commit the currently selected amount and unit of chosen food item\n */\n proposedEntryNutrients() {\n let totals = { ...this.staticVals.nutrientValues\n };\n\n if (this.entryType === this.staticVals.entryType.RECIPE && this.selected.recipe != null) {\n let chosenGrams = 0; // How much of this recipe in grams did the user propose to add\n\n let gramsInRecipe = this.selected.recipe.nutrition_data.grams; // How many grams the recipe creates if followed as is\n\n if (this.entry.unit === 'servings') {\n let gramsPerServing = gramsInRecipe / parseFloat(this.selected.recipe.serves) || 1; // g/recipe / servings/recipe = g/serving\n\n chosenGrams = gramsPerServing * this.entry.amount;\n } else {\n chosenGrams = this.entry.amount; //\n }\n\n let ratio = chosenGrams / gramsInRecipe;\n\n for (let nutrient of Object.keys(totals)) {\n totals[nutrient] = parseFloat(this.selected.recipe.nutrition_data[nutrient]) * ratio || 0;\n }\n } else if (this.entryType === this.staticVals.entryType.INGREDIENT && this.selected.ingredient != null) {\n // Scale according to the desired number of grams\n let storedGramUnit = 1000; // All nutrition info is stored per kg for an ingredient\n\n let chosenAmountInGrams = 0; // need to know how many grams user has chosen\n\n if (this.entry.unit === 'servings') {\n // Convert servings to grams\n let servingSize = parseFloat(this.selected.ingredient.serving);\n chosenAmountInGrams = servingSize * this.entry.amount;\n } else {\n chosenAmountInGrams = this.entry.amount;\n }\n\n let ratio = chosenAmountInGrams / storedGramUnit;\n\n for (let nutrient of Object.keys(totals)) {\n totals[nutrient] = parseFloat(this.selected.ingredient.nutrition_data[nutrient]) * ratio || 0;\n }\n } else {\n // Use the one off food values\n for (let nutrient of Object.keys(totals)) {\n totals[nutrient] = parseFloat(this.oneOffFood[nutrient]) || 0;\n }\n }\n\n return totals;\n }\n\n },\n watch: {\n entryType(newValue) {\n if (newValue !== this.staticVals.entryType.ONE_OFF_FOOD) {\n for (let nutrient of Object.keys(this.staticVals.nutrientValues)) {\n this.oneOffFood[nutrient] = null;\n }\n }\n },\n\n targetTimePeriod() {\n this.refreshTimePeriodDiaryFoods();\n }\n\n },\n methods: {\n /**\n * Gets the diary foods logged from the past day, updating the internally stored copy from the db\n */\n refreshTimePeriodDiaryFoods() {\n if (!(this.targetTimePeriod in Object.values(this.staticVals.timePeriod))) {\n console.error(`Target time period ${this.targetTimePeriod} was not a valid value`);\n return;\n } // @todo the api should be in charge of converting from local time to server time, not this component\n\n\n let start_time, end_time;\n const NOW = new Date(),\n ONE_DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;\n let mostRecentMidnight = new Date(NOW.getTime());\n mostRecentMidnight.setHours(0, 0, 0, 0);\n\n if (this.targetTimePeriod === this.staticVals.timePeriod.PAST_24) {\n start_time = new Date(NOW - ONE_DAY_IN_MILLISECONDS);\n end_time = NOW;\n } else if (this.targetTimePeriod === this.staticVals.timePeriod.TODAY) {\n start_time = mostRecentMidnight;\n end_time = new Date(mostRecentMidnight.getTime() + ONE_DAY_IN_MILLISECONDS);\n } else if (this.targetTimePeriod === this.staticVals.timePeriod.YESTERDAY) {\n start_time = new Date(mostRecentMidnight.getTime() - ONE_DAY_IN_MILLISECONDS);\n end_time = mostRecentMidnight;\n } // Convert to time value server will understand\n\n\n start_time = start_time.toISOString().replace('T', ' ');\n end_time = end_time.toISOString().replace('T', ' ');\n return this.pants.DiaryFood.get_all({\n filterDict: {\n 'start_time': [['>=', start_time], ['<=', end_time]]\n }\n }).then(resp => {\n this.diaryFoods = resp.results;\n });\n },\n\n createDiaryFood() {\n let requestObject = {\n // Convert input time to ISO time (server should be in UTC)\n 'start_time': new Date(this.entry.date + \"T\" + this.entry.time).toISOString(),\n // Set 'servings' or 'weight'\n [this.entry.unit]: this.entry.amount\n }; // What food gets added depends on what view we are in\n\n if (this.entryType === this.staticVals.entryType.RECIPE && this.selected.recipe !== null) {\n requestObject[\"of_recipe\"] = this.selected.recipe.url;\n } else if (this.entryType === this.staticVals.entryType.INGREDIENT && this.selected.ingredient !== null) {\n requestObject[\"of_ingredient\"] = this.selected.ingredient.url;\n } else if (this.entryType === this.staticVals.entryType.ONE_OFF_FOOD) {\n // @todo allow specifying a name for this food\n requestObject[\"name\"] = \"Custom Food\"; // @todo properly set up one time food entry\n } else {\n alert('Please select a food from the table, or use the \"One Off Food\" option');\n }\n\n this.pants.DiaryFood.create(requestObject).then(() => {\n this.refreshTimePeriodDiaryFoods().then(() => {\n if (requestObject['of_recipe']) {\n this.recipeGrid.gridOptions.api.deselectAll();\n this.selected.recipe = null;\n } else if (requestObject['of_ingredient']) {\n this.componentsGrid.gridOptions.api.deselectAll();\n this.selected.ingredient = null;\n }\n });\n });\n /*\n let component_data = JSON.parse(component.value)[0];\n this.pants.create_diaryfood({\n 'start_time': (new Date(date.value + \"T\" + time.value)).toISOString(),\n // Set 'servings' or 'weight'\n [unit.value]: amount.value,\n // Set 'of_ingredient', 'of_recipe' or 'name' depending on what has been entered\n [component_data.url === undefined\n ? 'name'\n : (component_data.url.split(\"/\").slice(-3)[0] === 'recipe'\n ? 'of_recipe'\n : 'of_ingredient')\n ]: component_data.url === undefined ? component_data.name : component_data.url,\n })\n */\n },\n\n // Setup progressively being able to specify more specifically when you ate the food\n changeTime() {\n if (this.timeSpecificity === _static.timeSpecificity.JUST_NOW) {\n this.timeSpecificity = _static.timeSpecificity.TODAY_AT;\n } else if (this.timeSpecificity === _static.timeSpecificity.TODAY_AT) {\n this.timeSpecificity = _static.timeSpecificity.ON_DATETIME;\n } else {\n this.timeSpecificity = _static.timeSpecificity.JUST_NOW; // @todo reset date, time to now\n }\n },\n\n onRecipeRowSelected(args) {\n // This event fires if a row is selected OR deselected, we only care if something gets selected\n if (!args.node.selected) return;\n this.selected.recipe = args.data;\n },\n\n onIngredientRowSelected(args) {\n // This event fires if a row is selected OR deselected, we only care if something gets selected\n if (!args.node.selected) return;\n this.selected.ingredient = args.data;\n }\n\n }\n});\n\n//# sourceURL=webpack:///./src/components/pages/diary.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/home.vue?vue&type=script&lang=js&": +/*!*******************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/home.vue?vue&type=script&lang=js& ***! + \*******************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"home\"\n});\n\n//# sourceURL=webpack:///./src/components/pages/home.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/ingredient-manager.vue?vue&type=script&lang=js&": +/*!*********************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/ingredient-manager.vue?vue&type=script&lang=js& ***! + \*********************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/web.dom-collections.iterator */ \"./node_modules/core-js/modules/web.dom-collections.iterator.js\");\n/* harmony import */ var core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _inputs_input_float__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../inputs/input-float */ \"./src/components/inputs/input-float.vue\");\n/* harmony import */ var ag_grid_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ag-grid-vue */ \"./node_modules/ag-grid-vue/main.js\");\n/* harmony import */ var ag_grid_vue__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ag_grid_vue__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ag-grid-community/dist/styles/ag-grid.css */ \"./node_modules/ag-grid-community/dist/styles/ag-grid.css\");\n/* harmony import */ var ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ag-grid-community/dist/styles/ag-theme-balham.css */ \"./node_modules/ag-grid-community/dist/styles/ag-theme-balham.css\");\n/* harmony import */ var ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_4__);\n\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"ingredient-manager\",\n components: {\n InputFloat: _inputs_input_float__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n AgGridVue: ag_grid_vue__WEBPACK_IMPORTED_MODULE_2__[\"AgGridVue\"]\n },\n inject: ['pants'],\n\n data() {\n return {\n all_ingredients: {},\n columnDefs: [{\n headerName: \"Name\",\n field: \"name\",\n sort: 'asc'\n }, {\n headerName: \"Description\",\n field: \"description\"\n }, {\n headerName: \"Serving\",\n field: \"serving\"\n }, {\n headerName: \"Notes\",\n field: \"notes\"\n }],\n defaultColDef: {\n flex: 1,\n sortable: true,\n resizable: true\n },\n gridOptions: {},\n datasource: {\n getRows: async params => {\n params.searchKey = document.querySelector('#ingredient_filter').value;\n let response = await this.pants.get_ingredients(params);\n\n if (response.ok) {\n let data = await response.json();\n params.successCallback(data['results'], data['count']);\n } else {\n params.failCallback();\n }\n }\n },\n ingredient: {\n uri: null,\n introduction: null,\n name: null,\n slug: null,\n description: null,\n notes: null,\n tags: null,\n owner: null,\n serving: null,\n kilojoules: null,\n protein: null,\n carbohydrate: null,\n fat: null,\n saturatedfat: null,\n sugar: null,\n sodium: null,\n fibre: null\n },\n // The node currently displayed in the ingredient form\n focusedNode: null\n };\n },\n\n computed: {\n shortName() {\n let short_name = '';\n if (this.ingredient.name == null) return;\n\n if (this.ingredient.name.length > 13) {\n short_name = this.ingredient.name.slice(0, 10) + '...';\n } else {\n short_name = this.ingredient.name.slice(0, 13);\n }\n\n return short_name;\n },\n\n canEdit() {\n return this.focusedNode != null;\n },\n\n canDelete() {\n return this.focusedNode != null;\n }\n\n },\n methods: {\n /**\n * Updates the ingredient based on the values in the ingredients form\n */\n editIngredient() {\n this.pants.edit_ingredient(this.ingredient.uri, {\n name: this.ingredient.name,\n slug: this.ingredient.slug,\n description: this.ingredient.description,\n // @todo Cannot edit owner? Remove this if there is no case where this is possible\n // 'owner': form.querySelector('[name=owner]').value,\n tags: this.ingredient.tags.split(',').filter(tag => tag !== ''),\n // Remove empty tags\n serving: this.ingredient.serving,\n introduction: this.ingredient.introduction,\n notes: this.ingredient.notes,\n // Nutritional Data\n kilojoules: this.ingredient.kilojoules,\n protein: this.ingredient.protein,\n fibre: this.ingredient.fibre,\n carbohydrate: this.ingredient.carbohydrate,\n fat: this.ingredient.fat,\n sugar: this.ingredient.sugar,\n saturatedfat: this.ingredient.saturatedfat,\n sodium: this.ingredient.sodium\n }).then(resp => {\n let row_node = this.focusedNode;\n row_node.setData(resp);\n this.gridOptions.api.flashCells({\n rowNodes: [row_node]\n });\n });\n },\n\n /**\n * Deletes the currently selected ingredient\n */\n deleteIngredient() {\n this.pants.delete_ingredient(this.ingredient.uri).then(() => {\n this.gridOptions.api.deselectAll();\n this.refreshTable();\n\n for (let key of Object.keys(this.ingredient)) {\n this.ingredient[key] = \"\";\n }\n });\n },\n\n /**\n * Creates a new ingredient using the information in the input fields\n */\n createIngredient() {\n this.pants.create_ingredient({\n name: this.ingredient.name,\n slug: this.ingredient.slug,\n description: this.ingredient.description,\n // @todo Cannot edit owner? Remove this if there is no case where this is possible\n // 'owner': form.querySelector('[name=owner]').value,\n tags: this.ingredient.tags.split(',').filter(tag => tag !== ''),\n // Remove empty tags\n serving: this.ingredient.serving,\n introduction: this.ingredient.introduction,\n notes: this.ingredient.notes,\n // Nutritional Data\n kilojoules: this.ingredient.kilojoules,\n protein: this.ingredient.protein,\n fibre: this.ingredient.fibre,\n carbohydrate: this.ingredient.carbohydrate,\n fat: this.ingredient.fat,\n sugar: this.ingredient.sugar,\n saturatedfat: this.ingredient.saturatedfat,\n sodium: this.ingredient.sodium\n }).then(resp => {\n console.log(resp);\n this.refreshTable();\n });\n },\n\n onRowSelected(args) {\n // This event fires if a row is selected OR deselected, we only care if something gets selected\n if (!args.node.selected) return;\n let ingredient = args.data;\n this.ingredient.uri = ingredient.url;\n this.ingredient.name = ingredient.name;\n this.ingredient.description = ingredient.description;\n this.ingredient.owner = ingredient.owner;\n this.ingredient.serving = ingredient.serving;\n this.ingredient.introduction = ingredient.introduction;\n this.ingredient.notes = ingredient.notes;\n this.ingredient.tags = ingredient.tags.join(',');\n this.ingredient.slug = ingredient.slug; // Nutritional Data\n\n this.ingredient.kilojoules = ingredient.kilojoules;\n this.ingredient.protein = ingredient.protein;\n this.ingredient.fibre = ingredient.fibre;\n this.ingredient.carbohydrate = ingredient.carbohydrate;\n this.ingredient.fat = ingredient.fat;\n this.ingredient.sugar = ingredient.sugar;\n this.ingredient.saturatedfat = ingredient.saturatedfat;\n this.ingredient.sodium = ingredient.sodium; // Also store a reference to this node so that we can refresh it\n\n this.focusedNode = args.node;\n },\n\n onSearch() {\n this.refreshTable();\n },\n\n refreshTable() {\n this.gridOptions.api.refreshInfiniteCache();\n }\n\n }\n});\n\n//# sourceURL=webpack:///./src/components/pages/ingredient-manager.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/layouts/layout-default.vue?vue&type=script&lang=js&": +/*!*************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/layouts/layout-default.vue?vue&type=script&lang=js& ***! + \*************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"layout-default\",\n props: {\n currentLoc: {\n type: String\n },\n menu_items: {\n type: Object,\n required: true\n }\n }\n});\n\n//# sourceURL=webpack:///./src/components/pages/layouts/layout-default.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/recipe-manager.vue?vue&type=script&lang=js&": +/*!*****************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/recipe-manager.vue?vue&type=script&lang=js& ***! + \*****************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/web.dom-collections.iterator */ \"./node_modules/core-js/modules/web.dom-collections.iterator.js\");\n/* harmony import */ var core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_web_dom_collections_iterator__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _components_inputs_input_float__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @/components/inputs/input-float */ \"./src/components/inputs/input-float.vue\");\n/* harmony import */ var ag_grid_vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ag-grid-vue */ \"./node_modules/ag-grid-vue/main.js\");\n/* harmony import */ var ag_grid_vue__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ag_grid_vue__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _components_recipe_component__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @/components/recipe-component */ \"./src/components/recipe-component.vue\");\n/* harmony import */ var ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ag-grid-community/dist/styles/ag-grid.css */ \"./node_modules/ag-grid-community/dist/styles/ag-grid.css\");\n/* harmony import */ var ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ag-grid-community/dist/styles/ag-theme-balham.css */ \"./node_modules/ag-grid-community/dist/styles/ag-theme-balham.css\");\n/* harmony import */ var ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _components_cell_renderers_action_button__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @/components/cell-renderers/action-button */ \"./src/components/cell-renderers/action-button.vue\");\n\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"recipe-manager\",\n components: {\n RecipeComponent: _components_recipe_component__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n InputFloat: _components_inputs_input_float__WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n AgGridVue: ag_grid_vue__WEBPACK_IMPORTED_MODULE_2__[\"AgGridVue\"]\n },\n inject: ['pants'],\n\n data() {\n return {\n recipeGrid: {\n gridOptions: {},\n frameworkComponents: {\n actionsCell: _components_cell_renderers_action_button__WEBPACK_IMPORTED_MODULE_6__[\"default\"]\n },\n columnDefs: [{\n headerName: \"Name\",\n field: \"name\"\n }, {\n headerName: \"Description\",\n field: \"description\"\n }, {\n headerName: \"Serves\",\n field: \"serves\"\n }, {\n headerName: \"Notes\",\n field: \"notes\"\n }, {\n headerName: \"Actions\",\n cellRenderer: \"actionsCell\",\n cellRendererParams: {\n onClick: recipe => {\n this.add_component(\"recipe\", undefined, // There is no database id since this is a newly added component\n recipe.url.split(\"/\").slice(-2)[0], recipe.name, \"\", \"servings\");\n },\n icon: \"carrot\"\n },\n cellStyle: {\n \"padding\": \"0\"\n },\n maxWidth: 25\n }],\n defaultColDef: {\n flex: 1,\n sortable: true,\n resizable: true\n },\n rowModelType: 'infinite',\n rowSelection: 'single',\n pagination: true,\n paginationAutoPageSize: true,\n // Set up the grid to paginate using the server side API\n datasource: {\n getRows: async params => {\n params.searchKey = document.querySelector('#recipe_filter').value;\n let response = await this.pants.get_recipes(params);\n\n if (response.ok) {\n let data = await response.json();\n params.successCallback(data['results'], data['count']);\n } else {\n params.failCallback();\n }\n }\n }\n },\n componentsGrid: {\n gridOptions: {},\n frameworkComponents: {\n actionsCell: _components_cell_renderers_action_button__WEBPACK_IMPORTED_MODULE_6__[\"default\"]\n },\n columnDefs: [{\n headerName: \"Name\",\n field: \"name\"\n }, {\n headerName: \"Description\",\n field: \"description\"\n }, {\n headerName: \"Serving\",\n field: \"serving\"\n }, {\n headerName: \"Notes\",\n field: \"notes\"\n }, {\n headerName: \"Actions\",\n cellRenderer: \"actionsCell\",\n cellRendererParams: {\n onClick: ingredient => {\n this.add_component(\"ingredient\", undefined, // There is no database id since this is a newly added component\n ingredient.url.split(\"/\").slice(-2)[0], ingredient.name, \"\", \"weight\");\n },\n icon: \"carrot\"\n },\n cellStyle: {\n \"padding\": \"0\"\n },\n maxWidth: 25\n }],\n defaultColDef: {\n flex: 1,\n sortable: true,\n resizable: true\n },\n rowModelType: 'infinite',\n pagination: true,\n paginationAutoPageSize: true,\n // Set up the grid to paginate using the server side API\n datasource: {\n getRows: async params => {\n params.searchKey = document.querySelector('#ingredient_filter').value;\n let response = await this.pants.get_ingredients(params);\n\n if (response.ok) {\n let data = await response.json();\n params.successCallback(data.results, data.count);\n } else {\n params.failCallback();\n }\n }\n }\n },\n recipe: {\n components: [],\n uri: null,\n introduction: null,\n name: null,\n slug: null,\n description: null,\n serves: null,\n tags: null,\n flag: null,\n method: null,\n notes: null\n },\n focusedNode: null,\n allowedFlags: []\n };\n },\n\n computed: {\n canEdit() {\n return this.focusedNode != null;\n },\n\n canDelete() {\n return this.focusedNode != null;\n }\n\n },\n\n mounted() {\n // Set flag options\n this.pants.get_recipe_flags().then(data => {\n this.allowedFlags = data.results;\n });\n },\n\n methods: {\n /**\n * Gets all the components in the components list and returns a list suitable for passing onto the api\n */\n get_components() {\n let output = [];\n this.recipe.components.forEach(component => {\n let component_obj = {\n name: component.name,\n note: component.note || '',\n // Set \"servings\" or \"weight\"\n [component.unit]: component.amount,\n // Set \"of_ingredient\" or \"of_recipe\"\n [\"of_\" + component.type]: component.recipe_or_ingredient_id\n };\n\n if (component.id) {\n // Only set db id if it has been provided by the db\n component_obj[\"id\"] = component.id;\n }\n\n output.push(component_obj);\n });\n return output;\n },\n\n /**\n * Adds a component to the component list\n * @param {string} type either \"recipe\" or \"ingredient\"\n * @param {number} id the id number of the component (not the url) for this component relationship\n * @param {number|string} recipe_or_ingredient_id the original recipe or ingredient id for this component\n * @param {string} name the name of the component\n * @param {number|string} amount how much of the component in units\n * @param {string} unit what unit the amount is in. Should be \"weight\" for grams, or \"servings\" for servings\n * @param {string} note any additional notes\n */\n add_component(type, id, recipe_or_ingredient_id, name, amount, unit, note) {\n this.recipe.components.push({\n type: type,\n id: id,\n recipe_or_ingredient_id: parseFloat(recipe_or_ingredient_id),\n name: name,\n amount: parseFloat(amount) || 0,\n unit: unit,\n note: note\n });\n },\n\n /**\n * Deletes the currently selected recipe\n */\n delete_recipe() {\n this.pants.delete_recipe(this.recipe.uri).then(() => {\n this.recipeGrid.gridOptions.api.deselectAll();\n this.recipeGrid.gridOptions.api.refreshInfiniteCache(); // Clear form\n\n for (let key of Object.keys(this.recipe)) {\n this.recipe[key] = null;\n }\n });\n },\n\n /**\n * Updates the recipe based on the values in the recipe form\n */\n edit_recipe() {\n this.pants.edit_recipe(this.recipe.uri, {\n name: this.recipe.name,\n slug: this.recipe.slug,\n description: this.recipe.description,\n // @todo Cannot edit owner? Remove this if there is no case where this is possible\n // 'owner': form.querySelector('[name=owner]').value,\n tags: this.recipe.tags.split(',').filter(tag => tag !== ''),\n // Remove empty tags\n serves: this.recipe.serves,\n introduction: this.recipe.introduction,\n notes: this.recipe.notes,\n method: this.recipe.method,\n components: this.get_components(),\n flag: this.recipe.flag\n }).then(resp => {\n let row_node = this.focusedNode;\n row_node.setData(resp);\n this.recipeGrid.gridOptions.api.flashCells({\n rowNodes: [row_node]\n });\n });\n },\n\n /**\n * Creates a new recipe using the information in the recipe form\n */\n create_recipe() {\n this.pants.create_recipe({\n name: this.recipe.name,\n slug: this.recipe.slug,\n description: this.recipe.description,\n // @todo Cannot edit owner? Remove this if there is no case where this is possible\n // 'owner': form.querySelector('[name=owner]').value,\n tags: this.recipe.tags.split(',').filter(tag => tag !== ''),\n // Remove empty tags,\n serves: this.recipe.serves,\n introduction: this.recipe.introduction,\n notes: this.recipe.notes,\n method: this.recipe.method,\n components: this.get_components(),\n flag: this.recipe.flag\n }).then(() => {\n this.recipeGrid.gridOptions.api.refreshInfiniteCache();\n });\n },\n\n remove_all_components() {\n this.recipe.components = [];\n },\n\n onRecipeRowSelected(args) {\n // This event fires if a row is selected OR deselected, we only care if something gets selected\n if (!args.node.selected) return;\n let recipe = args.data;\n this.recipe.introduction = recipe.introduction;\n this.recipe.name = recipe.name;\n this.recipe.description = recipe.description;\n this.recipe.uri = recipe.url;\n this.recipe.serves = recipe.serves;\n this.recipe.flag = recipe.flag || \"\";\n this.recipe.method = recipe.method;\n this.recipe.notes = recipe.notes;\n this.recipe.tags = recipe.tags.join(',');\n this.recipe.slug = recipe.slug; // Components are not included in results for performance reasons, make a separate call to get those\n\n this.pants.get_recipe_full(recipe.url).then(response => response.json()).then(json => {\n // Empty current components\n this.remove_all_components();\n json.components.forEach(component => {\n this.add_component(component.of_ingredient == null ? \"recipe\" : \"ingredient\", component.id, component.of_ingredient || component.of_recipe, component.name, component.servings || component.weight, component.servings == null ? \"weight\" : \"servings\", component.note);\n });\n }).catch(e => {\n console.log(e); // Don't leave components from last recipe in there.\n\n this.remove_all_components();\n }); // Also store a reference to this node so that we can refresh it\n\n this.focusedNode = args.node;\n }\n\n }\n});\n\n//# sourceURL=webpack:///./src/components/pages/recipe-manager.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/target-manager.vue?vue&type=script&lang=js&": +/*!*****************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/target-manager.vue?vue&type=script&lang=js& ***! + \*****************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _inputs_input_float__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../inputs/input-float */ \"./src/components/inputs/input-float.vue\");\n/* harmony import */ var ag_grid_vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ag-grid-vue */ \"./node_modules/ag-grid-vue/main.js\");\n/* harmony import */ var ag_grid_vue__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(ag_grid_vue__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ag-grid-community/dist/styles/ag-grid.css */ \"./node_modules/ag-grid-community/dist/styles/ag-grid.css\");\n/* harmony import */ var ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(ag_grid_community_dist_styles_ag_grid_css__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ag-grid-community/dist/styles/ag-theme-balham.css */ \"./node_modules/ag-grid-community/dist/styles/ag-theme-balham.css\");\n/* harmony import */ var ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(ag_grid_community_dist_styles_ag_theme_balham_css__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var _components_inputs_input_checkbox__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @/components/inputs/input-checkbox */ \"./src/components/inputs/input-checkbox.vue\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\n\n // A blank nutrition object, to be used for both the target max and min\n// @todo extract to pants api?\n\nconst nutritionObj = {\n cost: null,\n kilojoules: null,\n protein: null,\n carbohydrate: null,\n fat: null,\n saturatedfat: null,\n fibre: null,\n sodium: null,\n sugar: null\n};\nconst _static = {\n icons: {\n nutrients: {\n cost: \"money-bill-alt\",\n kilojoules: \"bolt\",\n protein: \"egg\",\n carbohydrate: \"bread-slice\",\n fat: \"tint\",\n saturatedfat: \"tint-slash\",\n fibre: \"seedling\",\n sodium: \"stroopwafel\",\n sugar: \"cubes\"\n }\n },\n units: {\n cost: '$',\n kilojoules: 'kcal',\n protein: 'g',\n carbohydrate: 'g',\n fat: 'g',\n saturatedfat: 'g',\n fibre: 'g',\n sodium: 'mg',\n sugar: 'g'\n }\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"target-manager\",\n components: {\n InputCheckbox: _components_inputs_input_checkbox__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n InputFloat: _inputs_input_float__WEBPACK_IMPORTED_MODULE_0__[\"default\"],\n AgGridVue: ag_grid_vue__WEBPACK_IMPORTED_MODULE_1__[\"AgGridVue\"]\n },\n inject: ['pants'],\n\n data() {\n return {\n staticVals: _static,\n targetsGrid: {\n columnDefs: [{\n headerName: \"Name\",\n field: \"name\",\n sort: 'asc'\n }, {\n headerName: \"Description\",\n field: \"description\"\n }, {\n headerName: \"Daily\",\n field: \"daily_target\"\n }],\n defaultColDef: {\n flex: 1,\n sortable: true,\n resizable: true\n },\n gridOptions: {},\n datasource: {\n getRows: async params => {\n // @todo implement search\n //params.searchKey = document.querySelector('#ingredient_filter').value;\n let data = await this.pants.get_target(params);\n params.successCallback(data['results'], data['count']);\n }\n }\n },\n target: {\n url: null,\n name: null,\n slug: null,\n description: null,\n daily: false,\n minimum: { ...nutritionObj\n },\n maximum: { ...nutritionObj\n }\n },\n focusedNode: null\n };\n },\n\n computed: {\n canEdit() {\n return this.target.url != null;\n },\n\n canDelete() {\n return this.target.url != null;\n }\n\n },\n methods: {\n onRowSelected(args) {\n // This event fires if a row is selected OR deselected, we only care if something gets selected\n if (!args.node.selected) return;\n let target = args.data;\n this.target.name = target.name;\n this.target.slug = target.slug;\n this.target.url = target.url;\n this.target.daily = target.daily_target;\n this.target.description = target.description; // Deal with minimums and maximums\n\n this.target.minimum.cost = target.minimum.cost;\n this.target.minimum.kilojoules = target.minimum.kilojoules;\n this.target.minimum.protein = target.minimum.protein;\n this.target.minimum.carbohydrate = target.minimum.carbohydrate;\n this.target.minimum.fat = target.minimum.fat;\n this.target.minimum.saturatedfat = target.minimum.saturatedfat;\n this.target.minimum.fibre = target.minimum.fibre;\n this.target.minimum.sodium = target.minimum.sodium;\n this.target.minimum.sugar = target.minimum.sugar;\n this.target.maximum.cost = target.maximum.cost;\n this.target.maximum.kilojoules = target.maximum.kilojoules;\n this.target.maximum.protein = target.maximum.protein;\n this.target.maximum.carbohydrate = target.maximum.carbohydrate;\n this.target.maximum.fat = target.maximum.fat;\n this.target.maximum.saturatedfat = target.maximum.saturatedfat;\n this.target.maximum.fibre = target.maximum.fibre;\n this.target.maximum.sodium = target.maximum.sodium;\n this.target.maximum.sugar = target.maximum.sugar;\n this.focusedNode = args.node;\n },\n\n createTarget() {\n this.pants.Target.create({\n name: this.target.name,\n slug: this.target.slug,\n description: this.target.description,\n daily_target: this.target.daily,\n minimum: this.target.minimum,\n maximum: this.target.maximum\n }).then(() => {\n this.refreshTable();\n });\n },\n\n editTarget() {\n this.pants.Target.update(this.target.url, {\n name: this.target.name,\n slug: this.target.slug,\n description: this.target.description,\n daily_target: this.target.daily,\n minimum: this.target.minimum,\n maximum: this.target.maximum\n }).then(resp => {\n let row_node = this.focusedNode;\n row_node.setData(resp);\n this.targetsGrid.gridOptions.api.flashCells({\n rowNodes: [row_node]\n });\n });\n },\n\n deleteTarget() {\n this.pants.Target.delete(this.target.url).then(() => this.refreshTable());\n },\n\n refreshTable() {\n this.targetsGrid.gridOptions.api.refreshInfiniteCache();\n }\n\n }\n});\n\n//# sourceURL=webpack:///./src/components/pages/target-manager.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/recipe-component.vue?vue&type=script&lang=js&": +/*!*************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/recipe-component.vue?vue&type=script&lang=js& ***! + \*************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _components_inputs_input_float__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @/components/inputs/input-float */ \"./src/components/inputs/input-float.vue\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n name: \"recipe-component\",\n components: {\n InputFloat: _components_inputs_input_float__WEBPACK_IMPORTED_MODULE_0__[\"default\"]\n },\n props: {\n name: String,\n note: String,\n unit: String,\n // one of 'servings' or 'weight'\n amount: Number,\n type: String,\n recipe_or_ingredient_id: Number,\n id: Number\n },\n\n data() {\n return {\n // Internal data storage for user editable properties\n synced: {\n note: '',\n unit: null,\n amount: null\n },\n // If the user has stated they wanted to add a note\n wantsNote: false\n };\n },\n\n mounted() {\n // Transfer synced props to internal data\n this.synced.note = this.note || '';\n this.synced.unit = this.unit;\n this.synced.amount = this.amount; // Do this so that deleting the note text does not immediately hide the note box\n\n this.wantsNote = this.synced.note !== '';\n },\n\n computed: {\n hasNote() {\n return this.synced.note !== '' || this.wantsNote;\n }\n\n },\n methods: {\n onClickNote() {\n this.wantsNote = !this.wantsNote;\n this.note = '';\n }\n\n }\n});\n\n//# sourceURL=webpack:///./src/components/recipe-component.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=template&id=7ba5bd90&": +/*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/App.vue?vue&type=template&id=7ba5bd90& ***! + \*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { attrs: { id: \"app\" } },\n [\n _c(\n \"layout-default\",\n { attrs: { menu_items: _vm.menu_items } },\n [_c(\"template\", { slot: \"content\" }, [_c(\"router-view\")], 1)],\n 2\n )\n ],\n 1\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/App.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/cell-renderers/action-button.vue?vue&type=template&id=6a6cf40f&scoped=true&": +/*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/cell-renderers/action-button.vue?vue&type=template&id=6a6cf40f&scoped=true& ***! + \*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"flex-row-equalfill\" }, [\n _c(\n \"button\",\n {\n staticClass: \"dark\",\n on: {\n click: function($event) {\n $event.preventDefault()\n return _vm.onClick(_vm.rowData)\n }\n }\n },\n [_c(\"fa-icon\", { attrs: { icon: [\"fas\", _vm.icon] } })],\n 1\n )\n ])\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/cell-renderers/action-button.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/informational/target-summary.vue?vue&type=template&id=68999d32&scoped=true&": +/*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/informational/target-summary.vue?vue&type=template&id=68999d32&scoped=true& ***! + \*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n {\n class: _vm.$options.name,\n attrs: { \"data-show-detail\": _vm.showDetail },\n on: {\n click: function($event) {\n _vm.forceDetail = !_vm.forceDetail\n },\n mouseover: function($event) {\n _vm.hovering = true\n },\n mouseleave: function($event) {\n _vm.hovering = false\n }\n }\n },\n [\n _c(\"p\", { staticClass: \"label-displayVal\" }, [\n _vm._v(\n _vm._s(\n _vm.displayValue.toLocaleString(undefined, {\n maximumFractionDigits: 2\n })\n )\n )\n ]),\n _c(\n \"p\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.showDetail,\n expression: \"showDetail\"\n }\n ],\n staticClass: \"label-min\",\n style: { left: _vm.percentMin * 100 + \"%\" }\n },\n [_vm._v(_vm._s(_vm.targetMinValue))]\n ),\n _c(\n \"p\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.showDetail,\n expression: \"showDetail\"\n }\n ],\n staticClass: \"label-max\",\n style: { right: (1 - _vm.percentMax) * 100 + \"%\" }\n },\n [_vm._v(_vm._s(_vm.targetMaxValue))]\n ),\n _c(\n \"div\",\n {\n staticClass: \"bar\",\n class: {\n under: _vm.displayValue < _vm.targetMinValue,\n reached:\n _vm.displayValue >= _vm.targetMinValue &&\n _vm.displayValue <= _vm.targetMaxValue,\n over: _vm.displayValue > _vm.targetMaxValue\n }\n },\n [\n _vm._l(_vm.percentValues, function(value, idx) {\n return [\n _c(\"div\", {\n key: idx,\n staticClass: \"value-portion\",\n style: {\n flexGrow: value,\n backgroundColor:\n _vm.valueColors !== null && _vm.valueColors[idx] !== null\n ? _vm.valueColors[idx]\n : null\n }\n })\n ]\n }),\n _c(\"div\", {\n staticClass: \"proposed-portion\",\n style: { flexGrow: _vm.percentProposed }\n }),\n _c(\"div\", {\n staticClass: \"remaining-portion\",\n style: { flexGrow: _vm.percentRemaining }\n }),\n _c(\"div\", {\n staticClass: \"min-val-tick\",\n style: {\n left: _vm.percentMin * 100 + \"%\",\n transform: _vm.percentMin >= 1 ? \"translateX(-200%)\" : false\n }\n }),\n _c(\"div\", {\n staticClass: \"max-val-tick\",\n style: {\n left: _vm.percentMax * 100 + \"%\",\n transform: \"translateX(-100%)\"\n }\n })\n ],\n 2\n )\n ]\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/informational/target-summary.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/inputs/input-checkbox.vue?vue&type=template&id=61c3516c&scoped=true&": +/*!**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/inputs/input-checkbox.vue?vue&type=template&id=61c3516c&scoped=true& ***! + \**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _obj\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n {\n class:\n ((_obj = {}),\n (_obj[_vm.$options.name] = true),\n (_obj.checked = _vm.internalValue),\n _obj)\n },\n [\n _c(\"input\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.internalValue,\n expression: \"internalValue\"\n }\n ],\n attrs: { id: _vm.id, type: \"checkbox\" },\n domProps: {\n checked: Array.isArray(_vm.internalValue)\n ? _vm._i(_vm.internalValue, null) > -1\n : _vm.internalValue\n },\n on: {\n change: function($event) {\n var $$a = _vm.internalValue,\n $$el = $event.target,\n $$c = $$el.checked ? true : false\n if (Array.isArray($$a)) {\n var $$v = null,\n $$i = _vm._i($$a, $$v)\n if ($$el.checked) {\n $$i < 0 && (_vm.internalValue = $$a.concat([$$v]))\n } else {\n $$i > -1 &&\n (_vm.internalValue = $$a\n .slice(0, $$i)\n .concat($$a.slice($$i + 1)))\n }\n } else {\n _vm.internalValue = $$c\n }\n }\n }\n }),\n _c(\"label\", { attrs: { for: _vm.id } }, [\n _c(\n \"div\",\n { staticClass: \"fake-checkbox\" },\n [\n _c(\"fa-icon\", {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.internalValue,\n expression: \"internalValue\"\n }\n ],\n attrs: { icon: [\"fas\", \"check\"] }\n })\n ],\n 1\n ),\n _vm._v(\" \" + _vm._s(_vm.label) + \" \")\n ])\n ]\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/inputs/input-checkbox.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/inputs/input-float.vue?vue&type=template&id=701ddc03&scoped=true&": +/*!***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/inputs/input-float.vue?vue&type=template&id=701ddc03&scoped=true& ***! + \***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n _vm._b(\n {\n staticClass: \"field\",\n class: { disabled: _vm.disabled },\n attrs: { id: _vm.id + \"-container\" }\n },\n \"div\",\n _vm.container_extra,\n false\n ),\n [\n _vm.type === \"text\" && _vm.multiline\n ? _c(\n \"textarea\",\n _vm._b(\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.content,\n expression: \"content\"\n }\n ],\n ref: \"input\",\n staticClass: \"field__input\",\n attrs: {\n name: _vm.id,\n id: _vm.id,\n type: _vm.type,\n placeholder: _vm.label,\n disabled: _vm.disabled\n },\n domProps: { value: _vm.content },\n on: {\n keyup: function($event) {\n return _vm.$emit(\"keyup\")\n },\n input: [\n function($event) {\n if ($event.target.composing) {\n return\n }\n _vm.content = $event.target.value\n },\n _vm.handleInput\n ]\n }\n },\n \"textarea\",\n _vm.extra,\n false\n )\n )\n : _vm.type === \"select\"\n ? _c(\n \"select\",\n _vm._b(\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.content,\n expression: \"content\"\n }\n ],\n staticClass: \"field__input\",\n attrs: {\n name: _vm.id,\n id: _vm.id,\n disabled: _vm.disabled,\n \"data-picked_option\": _vm.content,\n \"data-has-label\": !!_vm.label\n },\n on: {\n change: [\n function($event) {\n var $$selectedVal = Array.prototype.filter\n .call($event.target.options, function(o) {\n return o.selected\n })\n .map(function(o) {\n var val = \"_value\" in o ? o._value : o.value\n return val\n })\n _vm.content = $event.target.multiple\n ? $$selectedVal\n : $$selectedVal[0]\n },\n _vm.handleInput\n ]\n }\n },\n \"select\",\n _vm.extra,\n false\n ),\n [\n _vm.label\n ? _c(\n \"option\",\n { attrs: { value: \"\", hidden: _vm.hideDefaultOption } },\n [_vm._v(_vm._s(_vm.label))]\n )\n : _vm._e(),\n _vm._t(\"default\")\n ],\n 2\n )\n : _vm.type === \"checkbox\"\n ? _c(\n \"input\",\n _vm._b(\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.content,\n expression: \"content\"\n }\n ],\n ref: \"input\",\n staticClass: \"field__input\",\n attrs: {\n name: _vm.id,\n id: _vm.id,\n placeholder: _vm.label,\n disabled: _vm.disabled,\n type: \"checkbox\"\n },\n domProps: {\n checked: Array.isArray(_vm.content)\n ? _vm._i(_vm.content, null) > -1\n : _vm.content\n },\n on: {\n keyup: function($event) {\n return _vm.$emit(\"keyup\")\n },\n input: _vm.handleInput,\n change: function($event) {\n var $$a = _vm.content,\n $$el = $event.target,\n $$c = $$el.checked ? true : false\n if (Array.isArray($$a)) {\n var $$v = null,\n $$i = _vm._i($$a, $$v)\n if ($$el.checked) {\n $$i < 0 && (_vm.content = $$a.concat([$$v]))\n } else {\n $$i > -1 &&\n (_vm.content = $$a\n .slice(0, $$i)\n .concat($$a.slice($$i + 1)))\n }\n } else {\n _vm.content = $$c\n }\n }\n }\n },\n \"input\",\n _vm.extra,\n false\n )\n )\n : _vm.type === \"radio\"\n ? _c(\n \"input\",\n _vm._b(\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.content,\n expression: \"content\"\n }\n ],\n ref: \"input\",\n staticClass: \"field__input\",\n attrs: {\n name: _vm.id,\n id: _vm.id,\n placeholder: _vm.label,\n disabled: _vm.disabled,\n type: \"radio\"\n },\n domProps: { checked: _vm._q(_vm.content, null) },\n on: {\n keyup: function($event) {\n return _vm.$emit(\"keyup\")\n },\n input: _vm.handleInput,\n change: function($event) {\n _vm.content = null\n }\n }\n },\n \"input\",\n _vm.extra,\n false\n )\n )\n : _c(\n \"input\",\n _vm._b(\n {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.content,\n expression: \"content\"\n }\n ],\n ref: \"input\",\n staticClass: \"field__input\",\n attrs: {\n name: _vm.id,\n id: _vm.id,\n placeholder: _vm.label,\n disabled: _vm.disabled,\n type: _vm.type\n },\n domProps: { value: _vm.content },\n on: {\n keyup: function($event) {\n return _vm.$emit(\"keyup\")\n },\n input: [\n function($event) {\n if ($event.target.composing) {\n return\n }\n _vm.content = $event.target.value\n },\n _vm.handleInput\n ]\n }\n },\n \"input\",\n _vm.extra,\n false\n )\n ),\n _c(\"label\", { staticClass: \"field__label\", attrs: { for: _vm.id } }, [\n _vm._v(_vm._s(_vm.label))\n ])\n ]\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/inputs/input-float.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/diary.vue?vue&type=template&id=29671fd8&scoped=true&": +/*!****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/diary.vue?vue&type=template&id=29671fd8&scoped=true& ***! + \****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { class: _vm.$options.name }, [\n _c(\"h1\", { staticClass: \"header-add\" }, [_vm._v(\"Add to Diary\")]),\n _c(\"h1\", { staticClass: \"header-display\" }, [_vm._v(\"Target Progress\")]),\n _c(\"div\", { staticClass: \"display-forms\" }, [\n _c(\n \"div\",\n { staticClass: \"nutrientTargets\" },\n _vm._l(Object.keys(_vm.staticVals.nutrientValues), function(nutrient) {\n return _c(\n \"div\",\n { key: nutrient, staticClass: \"dailyTargetNutrient\" },\n [\n _c(\"fa-icon\", {\n attrs: {\n icon: [\"fas\", _vm.staticVals.icons.nutrients[nutrient]],\n fixedWidth: \"\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: nutrient,\n label: nutrient + \" (\" + _vm.staticVals.units[nutrient] + \")\",\n disabled:\n _vm.entryType !== _vm.staticVals.entryType.ONE_OFF_FOOD\n },\n model: {\n value: _vm.oneOffFood[nutrient],\n callback: function($$v) {\n _vm.$set(_vm.oneOffFood, nutrient, $$v)\n },\n expression: \"oneOffFood[nutrient]\"\n }\n }),\n _c(\"target-summary\", {\n attrs: {\n value: _vm.diaryFoodNutrientArray[nutrient] || [0],\n \"proposed-change\": _vm.proposedEntryNutrients[nutrient] || 0,\n \"target-min-value\": _vm.dailyTarget.min[nutrient] || 0,\n \"target-max-value\": _vm.dailyTarget.max[nutrient] || 0,\n \"value-colors\":\n _vm.highlightedFood === null || _vm.diaryFoods === null\n ? null\n : _vm.diaryFoods.map(function(value, index) {\n return index === _vm.highlightedFood ? \"orange\" : null\n })\n }\n })\n ],\n 1\n )\n }),\n 0\n ),\n _c(\n \"h2\",\n { staticClass: \"time-period-header\" },\n [\n _c(\"span\", [_vm._v(\"Foods from \")]),\n _c(\n \"input-float\",\n {\n attrs: { type: \"select\", id: \"targetTimePeriod\" },\n model: {\n value: _vm.targetTimePeriod,\n callback: function($$v) {\n _vm.targetTimePeriod = $$v\n },\n expression: \"targetTimePeriod\"\n }\n },\n [\n _c(\n \"option\",\n { domProps: { value: _vm.staticVals.timePeriod.PAST_24 } },\n [_vm._v(\"the past 24 hours\")]\n ),\n _c(\n \"option\",\n { domProps: { value: _vm.staticVals.timePeriod.TODAY } },\n [_vm._v(\"today\")]\n ),\n _c(\n \"option\",\n { domProps: { value: _vm.staticVals.timePeriod.YESTERDAY } },\n [_vm._v(\"yesterday\")]\n )\n ]\n )\n ],\n 1\n ),\n _c(\"div\", { staticClass: \"diaryFoods\" }, [\n _c(\n \"ul\",\n _vm._l(_vm.diaryFoods, function(food, idx) {\n return _c(\n \"li\",\n {\n key: food.url,\n on: {\n mouseover: function($event) {\n _vm.highlightedFood = idx\n },\n mouseleave: function($event) {\n _vm.highlightedFood = null\n }\n }\n },\n [\n _vm._v(\n _vm._s(_vm.highlightedFood === idx ? \"-->\" : \"\") +\n _vm._s(food.name) +\n \" \"\n )\n ]\n )\n }),\n 0\n )\n ])\n ]),\n _c(\"div\", { staticClass: \"add-forms\" }, [\n _c(\n \"form\",\n { staticClass: \"flex-row-start\", attrs: { id: \"diary_entry_form\" } },\n [\n _c(\n \"button\",\n {\n staticClass: \"text-only\",\n attrs: { id: \"time-text\", type: \"button\" },\n on: { click: _vm.changeTime }\n },\n [\n _vm._v(\n _vm._s(_vm.staticVals.text.changeTimeBtn[_vm.timeSpecificity]) +\n \" \"\n )\n ]\n ),\n _c(\"input-float\", {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value:\n _vm.timeSpecificity ===\n _vm.staticVals.timeSpecificity.ON_DATETIME,\n expression:\n \"timeSpecificity===staticVals.timeSpecificity.ON_DATETIME\"\n }\n ],\n attrs: { id: \"date\", label: \"Date\", type: \"date\" },\n model: {\n value: _vm.entry.date,\n callback: function($$v) {\n _vm.$set(_vm.entry, \"date\", $$v)\n },\n expression: \"entry.date\"\n }\n }),\n _c(\"input-float\", {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value:\n _vm.timeSpecificity !==\n _vm.staticVals.timeSpecificity.JUST_NOW,\n expression:\n \"timeSpecificity!==staticVals.timeSpecificity.JUST_NOW\"\n }\n ],\n attrs: { id: \"time\", label: \"Time\", type: \"time\" },\n model: {\n value: _vm.entry.time,\n callback: function($$v) {\n _vm.$set(_vm.entry, \"time\", $$v)\n },\n expression: \"entry.time\"\n }\n }),\n _c(\"span\", [_vm._v(\"I ate\")]),\n _c(\"input-float\", {\n attrs: {\n id: \"amount\",\n label: \"Amount\",\n extra: { style: \"text-align:right;max-width:6em\" }\n },\n model: {\n value: _vm.entry.amount,\n callback: function($$v) {\n _vm.$set(_vm.entry, \"amount\", $$v)\n },\n expression: \"entry.amount\"\n }\n }),\n _c(\n \"input-float\",\n {\n attrs: {\n id: \"unit\",\n type: \"select\",\n \"hide-default-option\": true\n },\n model: {\n value: _vm.entry.unit,\n callback: function($$v) {\n _vm.$set(_vm.entry, \"unit\", $$v)\n },\n expression: \"entry.unit\"\n }\n },\n [\n _c(\"option\", { attrs: { value: \"weight\" } }, [_vm._v(\"Grams\")]),\n _c(\"option\", { attrs: { value: \"servings\" } }, [\n _vm._v(\"Servings\")\n ])\n ]\n ),\n _c(\"span\", [_vm._v(\"of\")]),\n _c(\n \"input-float\",\n {\n attrs: {\n id: \"entry-type\",\n type: \"select\",\n \"hide-default-option\": true\n },\n model: {\n value: _vm.entryType,\n callback: function($$v) {\n _vm.entryType = $$v\n },\n expression: \"entryType\"\n }\n },\n [\n _c(\n \"option\",\n { domProps: { value: _vm.staticVals.entryType.RECIPE } },\n [_vm._v(\"Recipe\")]\n ),\n _c(\n \"option\",\n { domProps: { value: _vm.staticVals.entryType.INGREDIENT } },\n [_vm._v(\"Ingredient\")]\n ),\n _c(\n \"option\",\n { domProps: { value: _vm.staticVals.entryType.ONE_OFF_FOOD } },\n [_vm._v(\"One-off Food\")]\n )\n ]\n ),\n _c(\n \"button\",\n {\n staticClass: \"dark\",\n attrs: { type: \"button\" },\n on: { click: _vm.createDiaryFood }\n },\n [_vm._v(\"Add\")]\n )\n ],\n 1\n ),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.entryType === _vm.staticVals.entryType.RECIPE,\n expression: \"entryType === staticVals.entryType.RECIPE\"\n }\n ],\n staticClass: \"food-selection\"\n },\n [\n _c(\"ag-grid-vue\", {\n staticClass: \"ag-theme-balham recipe-grid\",\n attrs: {\n id: \"all_recipes_table\",\n gridOptions: _vm.recipeGrid.gridOptions,\n frameworkComponents: _vm.recipeGrid.frameworkComponents,\n columnDefs: _vm.recipeGrid.columnDefs,\n defaultColDef: _vm.recipeGrid.defaultColDef,\n rowModelType: _vm.recipeGrid.rowModelType,\n rowSelection: _vm.recipeGrid.rowSelection,\n pagination: _vm.recipeGrid.pagination,\n paginationAutoPageSize: _vm.recipeGrid.paginationAutoPageSize,\n datasource: _vm.recipeGrid.datasource\n },\n on: { \"row-selected\": _vm.onRecipeRowSelected }\n })\n ],\n 1\n ),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.entryType === _vm.staticVals.entryType.INGREDIENT,\n expression: \"entryType === staticVals.entryType.INGREDIENT\"\n }\n ],\n staticClass: \"food-selection\"\n },\n [\n _c(\"ag-grid-vue\", {\n staticClass: \"ag-theme-balham ingredient-grid\",\n attrs: {\n id: \"ingredients\",\n gridOptions: _vm.componentsGrid.gridOptions,\n frameworkComponents: _vm.componentsGrid.frameworkComponents,\n columnDefs: _vm.componentsGrid.columnDefs,\n defaultColDef: _vm.componentsGrid.defaultColDef,\n rowModelType: _vm.componentsGrid.rowModelType,\n rowSelection: _vm.componentsGrid.rowSelection,\n pagination: _vm.componentsGrid.pagination,\n paginationAutoPageSize: _vm.componentsGrid.paginationAutoPageSize,\n datasource: _vm.componentsGrid.datasource\n },\n on: { \"row-selected\": _vm.onIngredientRowSelected }\n })\n ],\n 1\n )\n ])\n ])\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/pages/diary.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/home.vue?vue&type=template&id=5e4cad4c&scoped=true&": +/*!***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/home.vue?vue&type=template&id=5e4cad4c&scoped=true& ***! + \***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"p\", [\n _vm._v(\n \"Welcome to the Price and Nutrition Tracker. Select an item on the navigation bar to get started.\"\n )\n ])\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/pages/home.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/ingredient-manager.vue?vue&type=template&id=48e555ec&scoped=true&": +/*!*****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/ingredient-manager.vue?vue&type=template&id=48e555ec&scoped=true& ***! + \*****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { attrs: { id: \"ingredient-manager\" } }, [\n _c(\n \"div\",\n { staticClass: \"header-all flex-row-between flex-gap-regular\" },\n [\n _c(\"h2\", [_vm._v(\"All Ingredients\")]),\n _c(\"input-float\", {\n attrs: { id: \"ingredient_filter\", label: \"Search\" },\n on: { keyup: _vm.onSearch }\n })\n ],\n 1\n ),\n _c(\n \"div\",\n { staticClass: \"ingredients-all\" },\n [\n _c(\"ag-grid-vue\", {\n staticClass: \"contained_table ag-theme-balham\",\n attrs: {\n id: \"ingredients\",\n gridOptions: _vm.gridOptions,\n datasource: _vm.datasource,\n columnDefs: _vm.columnDefs,\n defaulColDef: _vm.defaultColDef,\n pagination: true,\n paginationAutoPageSize: true,\n rowModelType: \"infinite\",\n rowSelection: \"single\"\n },\n on: { \"row-selected\": _vm.onRowSelected }\n })\n ],\n 1\n ),\n _vm._m(0),\n _c(\"div\", { staticClass: \"ingredient\" }, [\n _c(\n \"form\",\n { attrs: { id: \"ingredient_edit_form\", autocomplete: \"off\" } },\n [\n _c(\"input-float\", {\n attrs: {\n id: \"introduction\",\n label: \"Introduction\",\n hint: \"Introductory paragraph explains ingredient\",\n multiline: true\n },\n model: {\n value: _vm.ingredient.introduction,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"introduction\", $$v)\n },\n expression: \"ingredient.introduction\"\n }\n }),\n _c(\n \"div\",\n { staticClass: \"flex-row-equalfill\" },\n [\n _c(\"input-float\", {\n attrs: { id: \"name\", label: \"Name\", hint: \"Grilled Cheese\" },\n model: {\n value: _vm.ingredient.name,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"name\", $$v)\n },\n expression: \"ingredient.name\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"slug\",\n label: \"Slug\",\n hint: \"grilled-cheese\",\n input_mask_name: \"slug_mask\"\n },\n model: {\n value: _vm.ingredient.slug,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"slug\", $$v)\n },\n expression: \"ingredient.slug\"\n }\n })\n ],\n 1\n ),\n _c(\"input-float\", {\n attrs: {\n id: \"description\",\n label: \"Description\",\n hint: \"A sandwich made with melted cheese\",\n multiline: true\n },\n model: {\n value: _vm.ingredient.description,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"description\", $$v)\n },\n expression: \"ingredient.description\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"notes\",\n label: \"Notes\",\n hint: \"Additional information about usage, types, etc.\",\n multiline: true\n },\n model: {\n value: _vm.ingredient.notes,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"notes\", $$v)\n },\n expression: \"ingredient.notes\"\n }\n }),\n _c(\n \"div\",\n { staticClass: \"flex-row-equalfill\" },\n [\n _c(\"input-float\", {\n attrs: {\n id: \"tags\",\n label: \"Tags\",\n hint: \"tag1,tag2,tag3\",\n input_mask_name: \"tag_mask\"\n },\n model: {\n value: _vm.ingredient.tags,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"tags\", $$v)\n },\n expression: \"ingredient.tags\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"owner\",\n label: \"Owner\",\n hint: \"A sandwich made with melted cheese\",\n extra: { disabled: true, value: \"\" }\n },\n model: {\n value: _vm.ingredient.owner,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"owner\", $$v)\n },\n expression: \"ingredient.owner\"\n }\n })\n ],\n 1\n ),\n _c(\"h3\", [_vm._v(\"Nutrition\")]),\n _c(\n \"div\",\n { staticClass: \"flex-row-equalfill\" },\n [\n _c(\"input-float\", {\n attrs: {\n id: \"serving\",\n label: \"Serving Size (g)\",\n hint: \"in grams\",\n input_mask_name: \"nutrition_mask\"\n },\n model: {\n value: _vm.ingredient.serving,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"serving\", $$v)\n },\n expression: \"ingredient.serving\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"kilojoules\",\n label: \"kilojoules\",\n input_mask_name: \"nutrition_mask\"\n },\n model: {\n value: _vm.ingredient.kilojoules,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"kilojoules\", $$v)\n },\n expression: \"ingredient.kilojoules\"\n }\n })\n ],\n 1\n ),\n _c(\n \"div\",\n { staticClass: \"flex-row-equalfill\" },\n [\n _c(\"input-float\", {\n attrs: {\n id: \"protein\",\n label: \"protein (g)\",\n hint: \"in grams\",\n input_mask_name: \"nutrition_mask\"\n },\n model: {\n value: _vm.ingredient.protein,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"protein\", $$v)\n },\n expression: \"ingredient.protein\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"carbohydrate\",\n label: \"carbohydrate (g)\",\n hint: \"in grams\",\n input_mask_name: \"nutrition_mask\"\n },\n model: {\n value: _vm.ingredient.carbohydrate,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"carbohydrate\", $$v)\n },\n expression: \"ingredient.carbohydrate\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"fat\",\n label: \"fat (g)\",\n hint: \"in grams\",\n input_mask_name: \"nutrition_mask\"\n },\n model: {\n value: _vm.ingredient.fat,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"fat\", $$v)\n },\n expression: \"ingredient.fat\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"saturatedfat\",\n label: \"saturatedfat (g)\",\n hint: \"in grams\",\n input_mask_name: \"nutrition_mask\"\n },\n model: {\n value: _vm.ingredient.saturatedfat,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"saturatedfat\", $$v)\n },\n expression: \"ingredient.saturatedfat\"\n }\n })\n ],\n 1\n ),\n _c(\n \"div\",\n { staticClass: \"flex-row-equalfill\" },\n [\n _c(\"input-float\", {\n attrs: {\n id: \"sugar\",\n label: \"sugar (g)\",\n hint: \"in grams\",\n input_mask_name: \"nutrition_mask\"\n },\n model: {\n value: _vm.ingredient.sugar,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"sugar\", $$v)\n },\n expression: \"ingredient.sugar\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"sodium\",\n label: \"sodium (mg)\",\n hint: \"in milligrams\",\n input_mask_name: \"nutrition_mask\"\n },\n model: {\n value: _vm.ingredient.sodium,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"sodium\", $$v)\n },\n expression: \"ingredient.sodium\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"fibre\",\n label: \"fibre (g)\",\n hint: \"in grams\",\n input_mask_name: \"nutrition_mask\"\n },\n model: {\n value: _vm.ingredient.fibre,\n callback: function($$v) {\n _vm.$set(_vm.ingredient, \"fibre\", $$v)\n },\n expression: \"ingredient.fibre\"\n }\n })\n ],\n 1\n )\n ],\n 1\n ),\n _c(\"div\", { staticClass: \"flex-row-equalfill\" }, [\n _c(\n \"button\",\n { staticClass: \"oneline dark\", on: { click: _vm.createIngredient } },\n [_vm._v(\"Create New \")]\n ),\n _c(\n \"button\",\n {\n staticClass: \"oneline dark\",\n attrs: { disabled: !_vm.canEdit, id: \"edit_desc\" },\n on: { click: _vm.editIngredient }\n },\n [\n _vm._v(\"Edit\"),\n _vm.shortName\n ? _c(\"span\", [_vm._v(\" \" + _vm._s(_vm.shortName))])\n : _vm._e()\n ]\n ),\n _c(\n \"button\",\n {\n staticClass: \"oneline dark\",\n attrs: { disabled: !_vm.canDelete, id: \"delete_desc\" },\n on: { click: _vm.deleteIngredient }\n },\n [\n _vm._v(\"Delete\"),\n _vm.shortName\n ? _c(\"span\", [_vm._v(\" \" + _vm._s(_vm.shortName))])\n : _vm._e()\n ]\n )\n ])\n ])\n ])\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"header\" }, [\n _c(\"h2\", [_vm._v(\"Information\")])\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/pages/ingredient-manager.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/layouts/layout-default.vue?vue&type=template&id=c75993c2&scoped=true&": +/*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/layouts/layout-default.vue?vue&type=template&id=c75993c2&scoped=true& ***! + \*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { class: _vm.$options.name }, [\n _c(\"div\", { staticClass: \"menu\" }, [\n _c(\n \"div\",\n { staticClass: \"nav\" },\n _vm._l(_vm.menu_items, function(item, key) {\n return _c(\n \"router-link\",\n {\n key: key,\n staticClass: \"nav-item\",\n class: { active: _vm.currentLoc === key },\n attrs: { to: item.url }\n },\n [_c(\"fa-icon\", { attrs: { icon: [\"fas\", item.icon] } })],\n 1\n )\n }),\n 1\n )\n ]),\n _c(\n \"div\",\n { staticClass: \"quick-info\" },\n [\n _c(\"h1\", { staticClass: \"page-title\" }, [_vm._t(\"page_title\")], 2),\n _vm._t(\"quick_info\")\n ],\n 2\n ),\n _c(\"div\", { staticClass: \"content\" }, [_vm._t(\"content\")], 2)\n ])\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/pages/layouts/layout-default.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/recipe-manager.vue?vue&type=template&id=455c0fa9&scoped=true&": +/*!*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/recipe-manager.vue?vue&type=template&id=455c0fa9&scoped=true& ***! + \*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { attrs: { id: \"recipe-manager\" } }, [\n _c(\n \"div\",\n { staticClass: \"header-all-recipes flex-row-between flex-gap-regular\" },\n [\n _c(\"h2\", [_vm._v(\"All Recipes\")]),\n _c(\"input-float\", {\n attrs: { id: \"recipe_filter\", label: \"Search\" },\n on: {\n keyup: function($event) {\n return _vm.recipeGrid.gridOptions.api.refreshInfiniteCache()\n }\n }\n })\n ],\n 1\n ),\n _c(\n \"div\",\n { staticClass: \"all-recipes resizable-vertical\" },\n [\n _c(\"ag-grid-vue\", {\n staticClass: \"ag-theme-balham fill-height\",\n attrs: {\n id: \"all_recipes_table\",\n gridOptions: _vm.recipeGrid.gridOptions,\n frameworkComponents: _vm.recipeGrid.frameworkComponents,\n columnDefs: _vm.recipeGrid.columnDefs,\n defaultColDef: _vm.recipeGrid.defaultColDef,\n rowModelType: _vm.recipeGrid.rowModelType,\n rowSelection: _vm.recipeGrid.rowSelection,\n pagination: _vm.recipeGrid.pagination,\n paginationAutoPageSize: _vm.recipeGrid.paginationAutoPageSize,\n datasource: _vm.recipeGrid.datasource\n },\n on: { \"row-selected\": _vm.onRecipeRowSelected }\n })\n ],\n 1\n ),\n _c(\n \"div\",\n {\n staticClass: \"header-all-ingredients flex-row-between flex-gap-regular\"\n },\n [\n _c(\"h2\", [_vm._v(\"All Ingredients\")]),\n _c(\"input-float\", {\n attrs: { id: \"ingredient_filter\", label: \"Search\" },\n on: {\n keyup: function($event) {\n return _vm.componentsGrid.gridOptions.api.refreshInfiniteCache()\n }\n }\n })\n ],\n 1\n ),\n _c(\n \"div\",\n { staticClass: \"all-ingredients resizable-vertical\" },\n [\n _c(\"ag-grid-vue\", {\n staticClass: \"ag-theme-balham fill-height\",\n attrs: {\n id: \"ingredients\",\n gridOptions: _vm.componentsGrid.gridOptions,\n frameworkComponents: _vm.componentsGrid.frameworkComponents,\n columnDefs: _vm.componentsGrid.columnDefs,\n defaultColDef: _vm.componentsGrid.defaultColDef,\n rowModelType: _vm.componentsGrid.rowModelType,\n pagination: _vm.componentsGrid.pagination,\n paginationAutoPageSize: _vm.componentsGrid.paginationAutoPageSize,\n datasource: _vm.componentsGrid.datasource\n }\n })\n ],\n 1\n ),\n _vm._m(0),\n _c(\"div\", { staticClass: \"recipe\" }, [\n _c(\n \"form\",\n { attrs: { id: \"recipe-edit-form\", autocomplete: \"off\" } },\n [\n _c(\"input\", { attrs: { type: \"hidden\", id: \"selected_row_node\" } }),\n _c(\"input\", {\n attrs: { type: \"hidden\", id: \"recipe_uri\", name: \"recipe_uri\" }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"introduction\",\n label: \"Introduction\",\n hint: \"A story about how the grilled cheese came to be\",\n multiline: true\n },\n model: {\n value: _vm.recipe.introduction,\n callback: function($$v) {\n _vm.$set(_vm.recipe, \"introduction\", $$v)\n },\n expression: \"recipe.introduction\"\n }\n }),\n _c(\n \"div\",\n { staticClass: \"flex-row-equalfill\" },\n [\n _c(\"input-float\", {\n attrs: { id: \"name\", label: \"Name\", hint: \"Grilled Cheese\" },\n model: {\n value: _vm.recipe.name,\n callback: function($$v) {\n _vm.$set(_vm.recipe, \"name\", $$v)\n },\n expression: \"recipe.name\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"slug\",\n label: \"Slug\",\n hint: \"grilled-cheese\",\n input_mask_name: \"slug_mask\"\n },\n model: {\n value: _vm.recipe.slug,\n callback: function($$v) {\n _vm.$set(_vm.recipe, \"slug\", $$v)\n },\n expression: \"recipe.slug\"\n }\n })\n ],\n 1\n ),\n _c(\"input-float\", {\n attrs: {\n id: \"description\",\n label: \"Description\",\n hint: \"A sandwich made with melted cheese\",\n multiline: true\n },\n model: {\n value: _vm.recipe.description,\n callback: function($$v) {\n _vm.$set(_vm.recipe, \"description\", $$v)\n },\n expression: \"recipe.description\"\n }\n }),\n _c(\n \"div\",\n { staticClass: \"flex-row-equalfill\" },\n [\n _c(\"input-float\", {\n attrs: { id: \"serves\", label: \"Serves\", hint: \"1\" },\n model: {\n value: _vm.recipe.serves,\n callback: function($$v) {\n _vm.$set(_vm.recipe, \"serves\", $$v)\n },\n expression: \"recipe.serves\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"tags\",\n label: \"Tags\",\n hint: \"tag1,tag2,tag3\",\n input_mask: \"tag_mask\",\n extra: { style: \"flex:2\" }\n },\n model: {\n value: _vm.recipe.tags,\n callback: function($$v) {\n _vm.$set(_vm.recipe, \"tags\", $$v)\n },\n expression: \"recipe.tags\"\n }\n }),\n _c(\n \"input-float\",\n {\n attrs: { id: \"flag\", type: \"select\", label: \"Flag\" },\n model: {\n value: _vm.recipe.flag,\n callback: function($$v) {\n _vm.$set(_vm.recipe, \"flag\", $$v)\n },\n expression: \"recipe.flag\"\n }\n },\n _vm._l(_vm.allowedFlags, function(flag) {\n return _c(\n \"option\",\n { key: flag.name, domProps: { value: flag.name } },\n [\n _vm._v(\n \"(\" + _vm._s(flag.char) + \") \" + _vm._s(flag.name) + \" \"\n )\n ]\n )\n }),\n 0\n )\n ],\n 1\n ),\n _c(\"h3\", [_vm._v(\"Recipe Ingredients\")]),\n _c(\n \"div\",\n { attrs: { id: \"recipe-components\" } },\n _vm._l(_vm.recipe.components, function(component, idx) {\n return _c(\"recipe-component\", {\n key: idx,\n attrs: {\n id: component.id,\n name: component.name,\n recipe_or_ingredient_id: component.recipe_or_ingredient_id,\n type: component.type,\n note: component.note,\n unit: component.unit,\n amount: component.amount\n },\n on: {\n \"update:note\": function($event) {\n return _vm.$set(component, \"note\", $event)\n },\n \"update:unit\": function($event) {\n return _vm.$set(component, \"unit\", $event)\n },\n \"update:amount\": function($event) {\n return _vm.$set(component, \"amount\", $event)\n },\n delete: function($event) {\n return _vm.recipe.components.splice(idx, 1)\n }\n }\n })\n }),\n 1\n ),\n _c(\"input-float\", {\n attrs: {\n id: \"method\",\n label: \"Method\",\n hint: \"Add cheese to bread, toast.\",\n multiline: true\n },\n model: {\n value: _vm.recipe.method,\n callback: function($$v) {\n _vm.$set(_vm.recipe, \"method\", $$v)\n },\n expression: \"recipe.method\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"notes\",\n label: \"Notes\",\n hint:\n \"Can use different cheeses than what is listed. Recipe is flexible.\",\n multiline: true\n },\n model: {\n value: _vm.recipe.notes,\n callback: function($$v) {\n _vm.$set(_vm.recipe, \"notes\", $$v)\n },\n expression: \"recipe.notes\"\n }\n })\n ],\n 1\n ),\n _c(\"div\", { staticClass: \"flex-row-equalfill\" }, [\n _c(\n \"button\",\n { staticClass: \"oneline dark\", on: { click: _vm.create_recipe } },\n [_vm._v(\"Create New \")]\n ),\n _c(\n \"button\",\n {\n staticClass: \"oneline dark\",\n attrs: { disabled: !_vm.canEdit },\n on: { click: _vm.edit_recipe }\n },\n [\n _vm._v(\"Edit \"),\n _vm.recipe.name\n ? _c(\"span\", [_vm._v(\" \" + _vm._s(_vm.recipe.name))])\n : _vm._e()\n ]\n ),\n _c(\n \"button\",\n {\n staticClass: \"oneline dark\",\n attrs: { disabled: !_vm.canDelete },\n on: { click: _vm.delete_recipe }\n },\n [\n _vm._v(\"Delete \"),\n _vm.recipe.name\n ? _c(\"span\", [_vm._v(\" \" + _vm._s(_vm.recipe.name))])\n : _vm._e()\n ]\n )\n ])\n ])\n ])\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"header-recipe\" }, [\n _c(\"h2\", [_vm._v(\"Selected Recipe\")])\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/pages/recipe-manager.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/target-manager.vue?vue&type=template&id=54d33f2c&scoped=true&": +/*!*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/target-manager.vue?vue&type=template&id=54d33f2c&scoped=true& ***! + \*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { class: _vm.$options.name }, [\n _vm._m(0),\n _c(\"div\", { staticClass: \"header-form\" }),\n _c(\n \"div\",\n { staticClass: \"targets-all\" },\n [\n _c(\"ag-grid-vue\", {\n staticClass: \"targets-table ag-theme-balham\",\n attrs: {\n id: \"targets-grid\",\n gridOptions: _vm.targetsGrid.gridOptions,\n datasource: _vm.targetsGrid.datasource,\n columnDefs: _vm.targetsGrid.columnDefs,\n defaulColDef: _vm.targetsGrid.defaultColDef,\n pagination: true,\n paginationAutoPageSize: true,\n rowModelType: \"infinite\",\n rowSelection: \"single\"\n },\n on: { \"row-selected\": _vm.onRowSelected }\n })\n ],\n 1\n ),\n _c(\"div\", { staticClass: \"target-selected\" }, [\n _c(\n \"form\",\n [\n _c(\"input-float\", {\n attrs: { id: \"name\", label: \"name\" },\n model: {\n value: _vm.target.name,\n callback: function($$v) {\n _vm.$set(_vm.target, \"name\", $$v)\n },\n expression: \"target.name\"\n }\n }),\n _c(\"input-float\", {\n attrs: { id: \"slug\", label: \"slug\" },\n model: {\n value: _vm.target.slug,\n callback: function($$v) {\n _vm.$set(_vm.target, \"slug\", $$v)\n },\n expression: \"target.slug\"\n }\n }),\n _c(\"input-checkbox\", {\n attrs: { id: \"daily\", label: \"daily\" },\n model: {\n value: _vm.target.daily,\n callback: function($$v) {\n _vm.$set(_vm.target, \"daily\", $$v)\n },\n expression: \"target.daily\"\n }\n }),\n _c(\"input-float\", {\n attrs: { id: \"description\", label: \"description\", multiline: true },\n model: {\n value: _vm.target.description,\n callback: function($$v) {\n _vm.$set(_vm.target, \"description\", $$v)\n },\n expression: \"target.description\"\n }\n }),\n _vm._l(Object.keys(_vm.target.maximum), function(nutrient) {\n return _c(\n \"div\",\n { key: nutrient, staticClass: \"nutrient-input-row\" },\n [\n _c(\n \"span\",\n [\n _c(\"fa-icon\", {\n attrs: {\n icon: [\"fas\", _vm.staticVals.icons.nutrients[nutrient]],\n \"fixed-width\": \"\"\n }\n }),\n _vm._v(\" \" + _vm._s(nutrient) + \" \")\n ],\n 1\n ),\n _c(\"input-float\", {\n attrs: {\n id: \"min:\" + nutrient,\n label:\n \"min (\" +\n (_vm.staticVals.units[nutrient] || \"unknown unit\") +\n \")\"\n },\n model: {\n value: _vm.target.minimum[nutrient],\n callback: function($$v) {\n _vm.$set(_vm.target.minimum, nutrient, $$v)\n },\n expression: \"target.minimum[nutrient]\"\n }\n }),\n _c(\"input-float\", {\n attrs: {\n id: \"max:\" + nutrient,\n label:\n \"max (\" +\n (_vm.staticVals.units[nutrient] || \"unknown unit\") +\n \")\"\n },\n model: {\n value: _vm.target.maximum[nutrient],\n callback: function($$v) {\n _vm.$set(_vm.target.maximum, nutrient, $$v)\n },\n expression: \"target.maximum[nutrient]\"\n }\n })\n ],\n 1\n )\n }),\n _c(\n \"button\",\n {\n staticClass: \"oneline dark\",\n attrs: { type: \"button\" },\n on: { click: _vm.createTarget }\n },\n [_vm._v(\"Create New \")]\n ),\n _c(\n \"button\",\n {\n staticClass: \"oneline dark\",\n attrs: { type: \"button\", disabled: !_vm.canEdit },\n on: { click: _vm.editTarget }\n },\n [_vm._v(\"Edit\")]\n ),\n _c(\n \"button\",\n {\n staticClass: \"oneline dark\",\n attrs: { type: \"button\", disabled: !_vm.canDelete },\n on: { click: _vm.deleteTarget }\n },\n [_vm._v(\"Delete\")]\n )\n ],\n 2\n )\n ])\n ])\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"header-all\" }, [\n _c(\"h2\", [_vm._v(\"All Targets\")])\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/pages/target-manager.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"5d724b87-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/recipe-component.vue?vue&type=template&id=7865208e&": +/*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"5d724b87-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/recipe-component.vue?vue&type=template&id=7865208e& ***! + \*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! exports provided: render, staticRenderFns */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _obj\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { class: ((_obj = {}), (_obj[_vm.$options.name] = true), _obj) },\n [\n _c(\n \"button\",\n {\n staticClass: \"text-only\",\n attrs: { type: \"button\" },\n on: { click: _vm.onClickNote }\n },\n [\n _c(\"fa-icon\", { attrs: { icon: [\"fas\", \"sticky-note\"], size: \"2x\" } })\n ],\n 1\n ),\n _c(\"label\", { attrs: { id: \"name\" } }, [_vm._v(_vm._s(_vm.name))]),\n _c(\"input-float\", {\n attrs: {\n id: _vm.id + \":amount\",\n label: \"Amount\",\n extra: { style: \"min-width: 0;text-align: right\" }\n },\n on: {\n input: function($event) {\n _vm.$emit(\"update:amount\", parseFloat(_vm.synced.amount))\n }\n },\n model: {\n value: _vm.synced.amount,\n callback: function($$v) {\n _vm.$set(_vm.synced, \"amount\", $$v)\n },\n expression: \"synced.amount\"\n }\n }),\n _c(\n \"input-float\",\n {\n attrs: {\n id: _vm.id + \":unit\",\n type: \"select\",\n label: \"Unit\",\n \"hide-default-option\": true\n },\n on: {\n input: function($event) {\n return _vm.$emit(\"update:unit\", _vm.synced.unit)\n }\n },\n model: {\n value: _vm.synced.unit,\n callback: function($$v) {\n _vm.$set(_vm.synced, \"unit\", $$v)\n },\n expression: \"synced.unit\"\n }\n },\n [\n _c(\"option\", { attrs: { value: \"weight\" } }, [_vm._v(\"grams\")]),\n _c(\"option\", { attrs: { value: \"servings\" } }, [_vm._v(\"servings\")])\n ]\n ),\n _c(\n \"button\",\n {\n staticClass: \"text-only\",\n attrs: { type: \"button\" },\n on: {\n click: function($event) {\n return _vm.$emit(\"delete\")\n }\n }\n },\n [_c(\"fa-icon\", { attrs: { icon: [\"fas\", \"minus\"], size: \"2x\" } })],\n 1\n ),\n _c(\"input-float\", {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.hasNote,\n expression: \"hasNote\"\n }\n ],\n staticClass: \"note\",\n attrs: {\n id: _vm.id + \":note\",\n label: \"Note\",\n hint:\n \"Information about this specific ingredient in this specific recipe\",\n multiline: true,\n extra: { class: { \"resizable-vertical\": true } }\n },\n on: {\n input: function($event) {\n return _vm.$emit(\"update:note\", _vm.synced.note)\n }\n },\n model: {\n value: _vm.synced.note,\n callback: function($$v) {\n _vm.$set(_vm.synced, \"note\", $$v)\n },\n expression: \"synced.note\"\n }\n })\n ],\n 1\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack:///./src/components/recipe-component.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%225d724b87-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/postcss-loader/src/index.js?!./src/assets/css/reset.css": +/*!**********************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-3-1!./node_modules/postcss-loader/src??ref--6-oneOf-3-2!./src/assets/css/reset.css ***! + \**********************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"/* http://meyerweb.com/eric/tools/css/reset/\\n v2.0-modified | 20110126\\n License: none (public domain)\\n*/\\n\\nhtml, body, div, span, applet, object, iframe,\\nh1, h2, h3, h4, h5, h6, p, blockquote, pre,\\na, abbr, acronym, address, big, cite, code,\\ndel, dfn, em, img, ins, kbd, q, s, samp,\\nsmall, strike, strong, sub, sup, tt, var,\\nb, u, i, center,\\ndl, dt, dd, ol, ul, li,\\nfieldset, form, label, legend,\\ntable, caption, tbody, tfoot, thead, tr, th, td,\\narticle, aside, canvas, details, embed,\\nfigure, figcaption, footer, header, hgroup,\\nmenu, nav, output, ruby, section, summary,\\ntime, mark, audio, video {\\n margin: 0;\\n\\tpadding: 0;\\n\\tborder: 0;\\n\\tfont-size: 100%;\\n\\tfont: inherit;\\n\\tvertical-align: baseline;\\n}\\n\\n/* make sure to set some focus styles for accessibility */\\n:focus {\\n outline: 0;\\n}\\n\\n/* HTML5 display-role reset for older browsers */\\narticle, aside, details, figcaption, figure,\\nfooter, header, hgroup, menu, nav, section {\\n\\tdisplay: block;\\n}\\n\\nbody {\\n\\tline-height: 1;\\n}\\n\\nol, ul {\\n\\tlist-style: none;\\n}\\n\\nblockquote, q {\\n\\tquotes: none;\\n}\\n\\nblockquote:before, blockquote:after,\\nq:before, q:after {\\n\\tcontent: '';\\n\\tcontent: none;\\n}\\n\\ntable {\\n\\tborder-collapse: collapse;\\n\\tborder-spacing: 0;\\n}\\n\\ninput[type=search]::-webkit-search-cancel-button,\\ninput[type=search]::-webkit-search-decoration,\\ninput[type=search]::-webkit-search-results-button,\\ninput[type=search]::-webkit-search-results-decoration {\\n -webkit-appearance: none;\\n -moz-appearance: none;\\n}\\n\\ninput[type=search] {\\n -webkit-appearance: none;\\n -moz-appearance: none;\\n box-sizing: content-box;\\n}\\n\\ntextarea {\\n overflow: auto;\\n vertical-align: top;\\n resize: vertical;\\n}\\n\\n/**\\n * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.\\n */\\n\\naudio,\\ncanvas,\\nvideo {\\n display: inline-block;\\n *display: inline;\\n *zoom: 1;\\n max-width: 100%;\\n}\\n\\n/**\\n * Prevent modern browsers from displaying `audio` without controls.\\n * Remove excess height in iOS 5 devices.\\n */\\n\\naudio:not([controls]) {\\n display: none;\\n height: 0;\\n}\\n\\n/**\\n * Address styling not present in IE 7/8/9, Firefox 3, and Safari 4.\\n * Known issue: no IE 6 support.\\n */\\n\\n[hidden] {\\n display: none;\\n}\\n\\n/**\\n * 1. Correct text resizing oddly in IE 6/7 when body `font-size` is set using\\n * `em` units.\\n * 2. Prevent iOS text size adjust after orientation change, without disabling\\n * user zoom.\\n */\\n\\nhtml {\\n font-size: 100%; /* 1 */\\n -webkit-text-size-adjust: 100%; /* 2 */\\n -ms-text-size-adjust: 100%; /* 2 */\\n}\\n\\n/**\\n * Address `outline` inconsistency between Chrome and other browsers.\\n */\\n\\na:focus {\\n outline: thin dotted;\\n}\\n\\n/**\\n * Improve readability when focused and also mouse hovered in all browsers.\\n */\\n\\na:active,\\na:hover {\\n outline: 0;\\n}\\n\\n/**\\n * 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3.\\n * 2. Improve image quality when scaled in IE 7.\\n */\\n\\nimg {\\n border: 0; /* 1 */\\n -ms-interpolation-mode: bicubic; /* 2 */\\n}\\n\\n/**\\n * Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11.\\n */\\n\\nfigure {\\n margin: 0;\\n}\\n\\n/**\\n * Correct margin displayed oddly in IE 6/7.\\n */\\n\\nform {\\n margin: 0;\\n}\\n\\n/**\\n * Define consistent border, margin, and padding.\\n */\\n\\nfieldset {\\n border: 1px solid #c0c0c0;\\n margin: 0 2px;\\n padding: 0.35em 0.625em 0.75em;\\n}\\n\\n/**\\n * 1. Correct color not being inherited in IE 6/7/8/9.\\n * 2. Correct text not wrapping in Firefox 3.\\n * 3. Correct alignment displayed oddly in IE 6/7.\\n */\\n\\nlegend {\\n border: 0; /* 1 */\\n padding: 0;\\n white-space: normal; /* 2 */\\n *margin-left: -7px; /* 3 */\\n}\\n\\n/**\\n * 1. Correct font size not being inherited in all browsers.\\n * 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5,\\n * and Chrome.\\n * 3. Improve appearance and consistency in all browsers.\\n */\\n\\nbutton,\\ninput,\\nselect,\\ntextarea {\\n font-size: 100%; /* 1 */\\n margin: 0; /* 2 */\\n vertical-align: baseline; /* 3 */\\n *vertical-align: middle; /* 3 */\\n}\\n\\n/**\\n * Address Firefox 3+ setting `line-height` on `input` using `!important` in\\n * the UA stylesheet.\\n */\\n\\nbutton,\\ninput {\\n line-height: normal;\\n}\\n\\n/**\\n * Address inconsistent `text-transform` inheritance for `button` and `select`.\\n * All other form control elements do not inherit `text-transform` values.\\n * Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+.\\n * Correct `select` style inheritance in Firefox 4+ and Opera.\\n */\\n\\nbutton,\\nselect {\\n text-transform: none;\\n}\\n\\n/**\\n * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`\\n * and `video` controls.\\n * 2. Correct inability to style clickable `input` types in iOS.\\n * 3. Improve usability and consistency of cursor style between image-type\\n * `input` and others.\\n * 4. Remove inner spacing in IE 7 without affecting normal text inputs.\\n * Known issue: inner spacing remains in IE 6.\\n */\\n\\nbutton,\\nhtml input[type=\\\"button\\\"], /* 1 */\\ninput[type=\\\"reset\\\"],\\ninput[type=\\\"submit\\\"] {\\n -webkit-appearance: button; /* 2 */\\n cursor: pointer; /* 3 */\\n *overflow: visible; /* 4 */\\n}\\n\\n/**\\n * Re-set default cursor for disabled elements.\\n */\\n\\nbutton[disabled],\\nhtml input[disabled] {\\n cursor: default;\\n}\\n\\n/**\\n * 1. Address box sizing set to content-box in IE 8/9.\\n * 2. Remove excess padding in IE 8/9.\\n * 3. Remove excess padding in IE 7.\\n * Known issue: excess padding remains in IE 6.\\n */\\n\\ninput[type=\\\"checkbox\\\"],\\ninput[type=\\\"radio\\\"] {\\n box-sizing: border-box; /* 1 */\\n padding: 0; /* 2 */\\n *height: 13px; /* 3 */\\n *width: 13px; /* 3 */\\n}\\n\\n/**\\n * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.\\n * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome\\n * (include `-moz` to future-proof).\\n */\\n\\ninput[type=\\\"search\\\"] {\\n -webkit-appearance: textfield; /* 1 */ /* 2 */\\n box-sizing: content-box;\\n}\\n\\n/**\\n * Remove inner padding and search cancel button in Safari 5 and Chrome\\n * on OS X.\\n */\\n\\ninput[type=\\\"search\\\"]::-webkit-search-cancel-button,\\ninput[type=\\\"search\\\"]::-webkit-search-decoration {\\n -webkit-appearance: none;\\n}\\n\\n/**\\n * Remove inner padding and border in Firefox 3+.\\n */\\n\\nbutton::-moz-focus-inner,\\ninput::-moz-focus-inner {\\n border: 0;\\n padding: 0;\\n}\\n\\n/**\\n * 1. Remove default vertical scrollbar in IE 6/7/8/9.\\n * 2. Improve readability and alignment in all browsers.\\n */\\n\\ntextarea {\\n overflow: auto; /* 1 */\\n vertical-align: top; /* 2 */\\n}\\n\\n/**\\n * Remove most spacing between table cells.\\n */\\n\\ntable {\\n border-collapse: collapse;\\n border-spacing: 0;\\n}\\n\\nhtml,\\nbutton,\\ninput,\\nselect,\\ntextarea {\\n color: #222;\\n}\\n\\n\\n::-moz-selection {\\n background: #b3d4fc;\\n text-shadow: none;\\n}\\n\\n::selection {\\n background: #b3d4fc;\\n text-shadow: none;\\n}\\n\\nimg {\\n vertical-align: middle;\\n}\\n\\nfieldset {\\n border: 0;\\n margin: 0;\\n padding: 0;\\n}\\n\\ntextarea {\\n resize: vertical;\\n}\\n\\n.chromeframe {\\n margin: 0.2em 0;\\n background: #ccc;\\n color: #000;\\n padding: 0.2em 0;\\n}\\n\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/assets/css/reset.css?./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-3-1!./node_modules/postcss-loader/src??ref--6-oneOf-3-2"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/cell-renderers/action-button.vue?vue&type=style&index=0&id=6a6cf40f&scoped=true&lang=css&": +/*!*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/cell-renderers/action-button.vue?vue&type=style&index=0&id=6a6cf40f&scoped=true&lang=css& ***! + \*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"\\nbutton[data-v-6a6cf40f]{\\n padding: 0;margin: 0\\n}\\ndiv[data-v-6a6cf40f]{\\n align-items:stretch;height:100%\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/cell-renderers/action-button.vue?./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/ingredient-manager.vue?vue&type=style&index=0&id=48e555ec&scoped=true&lang=css&": +/*!***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/ingredient-manager.vue?vue&type=style&index=0&id=48e555ec&scoped=true&lang=css& ***! + \***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"\\n#ingredient-manager[data-v-48e555ec] {\\n display: grid;\\n grid-template-columns: 1fr 30em;\\n grid-template-rows: 4em 1fr;\\n gap: 0 var(--padding);\\n grid-template-areas: \\\"header-all header\\\" \\\"ingredients-all ingredient\\\";\\n\\n min-height: calc(100vh - 7em); /* Make it fill as much of the screen as possible to start off*/\\n}\\n#ingredient-manager > .header-all[data-v-48e555ec] {\\n grid-area: header-all;\\n}\\n#ingredient-manager > .ingredients-all[data-v-48e555ec] {\\n grid-area: ingredients-all;\\n resize: vertical;\\n overflow: auto;\\n}\\n#ingredient-manager > .ingredient[data-v-48e555ec] {\\n grid-area: ingredient;\\n}\\n#ingredient-manager > .header[data-v-48e555ec] {\\n grid-area: header;\\n}\\n#ingredient-manager > .ingredients-all > .contained_table[data-v-48e555ec] {\\n height: 100%;\\n}\\n#ingredient-manager > .ingredient[data-v-48e555ec] {\\n max-width: 30em;\\n}\\n#ingredient-manager > .ingredient button[data-v-48e555ec] {\\n margin: 1px;\\n}\\n#ingredient-manager > .ingredient .field[data-v-48e555ec] {\\n margin: 1px;\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/pages/ingredient-manager.vue?./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/layouts/layout-default.vue?vue&type=style&index=1&lang=css&": +/*!*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/layouts/layout-default.vue?vue&type=style&index=1&lang=css& ***! + \*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\nexports.push([module.i, \"@import url(https://fonts.googleapis.com/css2?family=Quicksand&family=Raleway&display=swap);\"]);\n// Module\nexports.push([module.i, \"\\n/* Layout/Typography */\\n:root {\\n --menu-collapsed-width: 5em;\\n\\n --font-family-headings: 'Quicksand', sans-serif;\\n --font-family-content: 'Raleway', sans-serif;\\n\\n --padding: 1em;\\n --padding-thin: 0.5em;\\n --border-radius: 4px;\\n\\n font-family: var(--font-family-content);\\n}\\nbody {\\n margin: 0;\\n background: var(--baby-powder);\\n}\\n.menu {\\n grid-area: menu;\\n}\\n.content {\\n grid-area: content;\\n padding: var(--padding);\\n}\\nh1, h2, h3, h4, h5, h6 {\\n font-family: var(--font-family-headings);\\n margin-top: 0.5em;\\n margin-bottom: 0.25em;\\n}\\nh1 {\\n font-size: 2em;\\n}\\nh2 {\\n font-size: 1.5em;\\n}\\nh3 {\\n font-size: 1.25em;\\n}\\n\\n/* Flex Utilties */\\n/* @todo extract these into sass mixins instead */\\n.flex-row-start {\\n display: flex;\\n flex-direction: row;\\n justify-content: flex-start;\\n align-items: center;\\n}\\n.flex-row-between {\\n display: flex;\\n flex-direction: row;\\n justify-content: space-between;\\n align-items: center;\\n}\\n.flex-row_r-between {\\n display: flex;\\n flex-direction: row-reverse;\\n justify-content: space-between;\\n align-items: center;\\n}\\n.flex-gap-regular {\\n gap: var(--padding);\\n}\\n.flex-row-equalfill {\\n display: flex;\\n flex-direction: row;\\n align-items: center;\\n}\\n.flex-row-equalfill > * {\\n flex: 1;\\n}\\n\\n\\n/* Colors */\\n/* @todo keep these specific colors, but also specify semantic colors that use these for semantic consistency */\\n:root {\\n --gunmetal: hsla(227, 15%, 24%, 1);\\n --baby-powder: hsla(100, 100%, 99%, 1);\\n --pine-green: hsla(173, 71%, 28%, 1);\\n --shamrock-green: hsla(142, 37%, 45%, 1);\\n --brown-sugar: hsla(15, 42%, 50%, 1);\\n}\\n\\n/* Quick Info */\\n.quick-info .page-title {\\n margin: 0;\\n}\\n\\n/* Menu */\\n.menu {\\n background: var(--gunmetal);\\n color: var(--pine-green);\\n}\\n.menu > .nav {\\n height: 100vh;\\n position: -webkit-sticky;\\n position: sticky;\\n top: 0;\\n display: flex;\\n flex-direction: column;\\n}\\n.menu > .nav > .nav-item {\\n width: var(--menu-collapsed-width);\\n height: var(--menu-collapsed-width);\\n display: flex;\\n justify-content: center;\\n align-items: center;\\n color: var(--pine-green);\\n}\\n.menu > .nav > .nav-item:visited {\\n color: var(--pine-green);\\n}\\n.menu > .nav > .nav-item > svg {\\n font-size: 2.5em;\\n}\\n.menu .spacer {\\n flex: 1;\\n}\\n.menu > .nav > .nav-item.router-link-exact-active::after {\\n content: \\\"\\\";\\n width: 0;\\n height: 0;\\n border-top: 0.5em solid transparent;\\n border-right: 1em solid var(--shamrock-green);\\n border-bottom: 0.5em solid transparent;\\n position: absolute;\\n right: -0.2em;\\n}\\n\\n/* Inputs */\\n/* @todo move this to the float input component */\\ninput:focus, textarea:focus {\\n box-shadow: inset 0 0 1px var(--shamrock-green);\\n}\\nbutton {\\n border-radius: var(--border-radius);\\n border: 1px solid black;\\n}\\nbutton.oneline {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\nbutton.dark {\\n background: var(--gunmetal);\\n color: var(--pine-green);\\n font-weight: bold;\\n border-color: var(--pine-green);\\n padding: var(--padding-thin);\\n}\\nbutton.dark:hover {\\n color: var(--shamrock-green);\\n}\\nbutton.dark:active {\\n box-shadow: inset 0 0 0.5em var(--pine-green);\\n}\\nbutton.text-only {\\n border: 0;\\n padding: 0;\\n color: var(--shamrock-green);\\n background: #0000;\\n}\\nbutton.text-only:hover {\\n color: var(--pine-green);\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/pages/layouts/layout-default.vue?./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/recipe-manager.vue?vue&type=style&index=0&id=455c0fa9&scoped=true&lang=css&": +/*!***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/recipe-manager.vue?vue&type=style&index=0&id=455c0fa9&scoped=true&lang=css& ***! + \***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"\\n#recipe-manager[data-v-455c0fa9] {\\n display: grid;\\n grid-template-columns: 1fr 30em;\\n grid-template-rows: -webkit-max-content 1fr -webkit-max-content 1fr;\\n grid-template-rows: max-content 1fr max-content 1fr;\\n gap: 0 var(--padding);\\n grid-template-areas: \\\"header-all-recipes header-recipe\\\" \\\"all-recipes recipe\\\" \\\"header-all-ingredients recipe\\\" \\\"all-ingredients recipe\\\";\\n\\n min-height: calc(100vh - 7em); /* Make it fill the screen as much as possible for less flash when picking a recipe*/\\n}\\n#recipe-manager > .header-all-recipes[data-v-455c0fa9] {\\n grid-area: header-all-recipes;\\n}\\n#recipe-manager > .all-recipes[data-v-455c0fa9] {\\n grid-area: all-recipes;\\n}\\n#recipe-manager > .header-all-ingredients[data-v-455c0fa9] {\\n grid-area: header-all-ingredients;\\n}\\n#recipe-manager > .all-ingredients[data-v-455c0fa9] {\\n grid-area: all-ingredients;\\n}\\n#recipe-manager > .header-recipe[data-v-455c0fa9] {\\n grid-area: header-recipe;\\n}\\n#recipe-manager > .recipe[data-v-455c0fa9] {\\n grid-area: recipe;\\n}\\n.fill-height[data-v-455c0fa9] {\\n height: 100%;\\n}\\n#recipe-manager[data-v-455c0fa9] .field,\\n#recipe-manager[data-v-455c0fa9] button {\\n margin: 1px;\\n}\\n.resizable-vertical[data-v-455c0fa9] {\\n resize: vertical;\\n overflow: auto;\\n}\\n#recipe-components[data-v-455c0fa9] {\\n display: grid;\\n /*grid-template-columns: 1fr [note-start] 8em 7em 2em [note-end];*/\\n /*A somewhat hacky way to make this align with the 3 way split of fields above it*/\\n grid-template-columns: 2em calc(33% + 1px - 2em) [note-start] calc(33% + 3px) 1fr 2em [note-end];\\n margin: var(--padding) 1px;\\n align-items: center;\\n}\\n#recipe-components[data-v-455c0fa9] .recipe-component .note{\\n grid-column: note-start / note-end\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/pages/recipe-manager.vue?./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/recipe-component.vue?vue&type=style&index=0&lang=css&": +/*!*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/recipe-component.vue?vue&type=style&index=0&lang=css& ***! + \*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"\\n.recipe-component {\\n display: contents;\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/recipe-component.vue?./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/informational/target-summary.vue?vue&type=style&index=0&id=68999d32&scoped=true&lang=scss&": +/*!*****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/informational/target-summary.vue?vue&type=style&index=0&id=68999d32&scoped=true&lang=scss& ***! + \*****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \".target-summary[data-v-68999d32] {\\n position: relative;\\n --transition-speed: 0.5s;\\n}\\n.target-summary .bar[data-v-68999d32] {\\n --bar-height: 3px;\\n display: flex;\\n position: relative;\\n}\\n.target-summary .bar .value-portion[data-v-68999d32] {\\n background: black;\\n height: var(--bar-height);\\n transition: all var(--transition-speed);\\n}\\n.target-summary .bar .proposed-portion[data-v-68999d32] {\\n background: rgba(0, 0, 0, 0.5);\\n height: var(--bar-height);\\n transition: all var(--transition-speed);\\n}\\n.target-summary .bar .remaining-portion[data-v-68999d32] {\\n height: 0;\\n transition: all var(--transition-speed);\\n align-self: center;\\n border-top: 1px dashed #0002;\\n}\\n.target-summary .bar .min-val-tick[data-v-68999d32], .target-summary .bar .max-val-tick[data-v-68999d32] {\\n content: \\\"\\\";\\n background-color: black;\\n width: 1px;\\n height: 1em;\\n position: absolute;\\n bottom: var(--bar-height);\\n transition: all var(--transition-speed);\\n}\\n.target-summary .bar .max-val-tick[data-v-68999d32] {\\n right: 0;\\n}\\n.target-summary .bar.under .value-portion[data-v-68999d32] {\\n background: #7c6900;\\n}\\n.target-summary .bar.under .proposed-portion[data-v-68999d32] {\\n background: rgba(124, 105, 0, 0.2);\\n}\\n.target-summary .bar.reached .value-portion[data-v-68999d32] {\\n background: #247b00;\\n}\\n.target-summary .bar.reached .proposed-portion[data-v-68999d32] {\\n background: rgba(36, 123, 0, 0.5);\\n}\\n.target-summary .bar.over .value-portion[data-v-68999d32] {\\n background: #d20032;\\n}\\n.target-summary .bar.over .proposed-portion[data-v-68999d32] {\\n background: rgba(210, 0, 50, 0.5);\\n}\\n.target-summary .label-displayVal[data-v-68999d32] {\\n margin-left: 0.5em;\\n}\\n.target-summary .label-min[data-v-68999d32],\\n .target-summary .label-max[data-v-68999d32] {\\n position: absolute;\\n top: 0;\\n font-size: 0.8em;\\n padding: 0.2em;\\n background: black;\\n color: white;\\n border-radius: var(--border-radius);\\n transition: all var(--transition-speed);\\n}\\n.target-summary .label-min[data-v-68999d32] {\\n transform: translateX(calc(-100% - 0.5em));\\n}\\n.target-summary .label-max[data-v-68999d32] {\\n transform: translateX(-0.5em);\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/informational/target-summary.vue?./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/inputs/input-checkbox.vue?vue&type=style&index=0&id=61c3516c&scoped=true&lang=scss&": +/*!**********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/inputs/input-checkbox.vue?vue&type=style&index=0&id=61c3516c&scoped=true&lang=scss& ***! + \**********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \".input-checkbox input[data-v-61c3516c] {\\n display: none;\\n}\\n.input-checkbox label[data-v-61c3516c] {\\n --label-spacing: calc(1.1em - 2px);\\n background: white;\\n box-sizing: border-box;\\n border: 1px solid var(--gunmetal);\\n padding: calc(var(--label-spacing) / 2) 0.5em calc(var(--label-spacing) / 2);\\n width: 100%;\\n font-family: var(--font-family-content);\\n border-radius: var(--border-radius);\\n color: grey;\\n line-height: 1;\\n opacity: 1;\\n overflow: hidden;\\n white-space: nowrap;\\n text-overflow: ellipsis;\\n top: 0;\\n text-align: left;\\n transform: none;\\n transition: all .2s ease-out;\\n -webkit-user-select: none;\\n -moz-user-select: none;\\n user-select: none;\\n display: flex;\\n align-items: center;\\n}\\n.input-checkbox .fake-checkbox[data-v-61c3516c] {\\n width: 1em;\\n height: 1em;\\n border: 1px solid var(--gunmetal);\\n border-radius: var(--border-radius);\\n padding: 0.1em;\\n background: white;\\n margin-right: 0.5em;\\n}\\n.input-checkbox.checked label[data-v-61c3516c] {\\n box-shadow: inset 0 0 5px 0 rgba(58, 165, 0, 0.75);\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/inputs/input-checkbox.vue?./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/inputs/input-float.vue?vue&type=style&index=0&id=701ddc03&scoped=true&lang=scss&": +/*!*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/inputs/input-float.vue?vue&type=style&index=0&id=701ddc03&scoped=true&lang=scss& ***! + \*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \".field[data-v-701ddc03] {\\n position: relative;\\n /*\\n for inputs and text areas, we know it's empty when the placeholder is shown\\n for selects, it's when the specially crafted data tag is empty\\n\\n In this case we make the label disappear and lower, so that it 'floats up and in' when needed\\n */\\n /* For some reason select elements are 2 px wider than inputs, normalize by going 50/50 */\\n}\\n.field > .field__input:-moz-placeholder-shown + .field__label[data-v-701ddc03] {\\n opacity: 0;\\n transform: translateY(1px);\\n}\\n.field > .field__input:placeholder-shown + .field__label[data-v-701ddc03],\\n .field > select.field__input[data-picked_option=\\\"\\\"] + .field__label[data-v-701ddc03] {\\n opacity: 0;\\n transform: translateY(1px);\\n}\\n.field > .field__label[data-v-701ddc03] {\\n color: #919293;\\n display: block;\\n box-sizing: border-box;\\n font-size: .8em;\\n line-height: 1;\\n opacity: 1;\\n overflow: hidden;\\n white-space: nowrap;\\n text-overflow: ellipsis;\\n padding: .5em 0.6rem;\\n pointer-events: none;\\n position: absolute;\\n top: 0;\\n text-align: left;\\n transform: none;\\n transition: all .2s ease-out;\\n -webkit-user-select: none;\\n -moz-user-select: none;\\n user-select: none;\\n width: 100%;\\n z-index: 1;\\n}\\n.field > .field__input[data-v-701ddc03] {\\n --label-spacing: 1.1em;\\n background: white;\\n box-sizing: border-box;\\n border: 1px solid var(--gunmetal);\\n padding: var(--label-spacing) 0.5em 0;\\n transition: all .1s ease-out;\\n width: 100%;\\n resize: vertical;\\n font-family: var(--font-family-content);\\n border-radius: var(--border-radius);\\n}\\n.field > .field__input[data-v-701ddc03]::-moz-placeholder {\\n font-family: var(--font-family-content);\\n}\\n.field > .field__input[data-v-701ddc03]::placeholder {\\n font-family: var(--font-family-content);\\n}\\n.field > .field__input[data-v-701ddc03]:hover, .field > .field__input[data-v-701ddc03]:focus {\\n border-color: var(--shamrock-green);\\n}\\n.field > .field__input[data-v-701ddc03]:-moz-placeholder-shown {\\n /* Padding when detected empty */\\n padding: calc(var(--label-spacing) / 2) 0.5em calc(var(--label-spacing) / 2);\\n}\\n.field > .field__input[data-v-701ddc03]:placeholder-shown {\\n /* Padding when detected empty */\\n padding: calc(var(--label-spacing) / 2) 0.5em calc(var(--label-spacing) / 2);\\n}\\n.field > select.field__input[data-v-701ddc03] {\\n padding: calc(var(--label-spacing) - 2px) 0.5em 0;\\n}\\n.field > select.field__input[data-picked_option=\\\"\\\"][data-v-701ddc03] {\\n padding: calc(var(--label-spacing) / 2 - 1px) 0.5em calc(var(--label-spacing) / 2 - 1px);\\n /* Any option with a value of \\\"\\\" will be considered unpicked, and thus should look like the placeholder */\\n color: grey;\\n}\\n.field > select.field__input[data-v-701ddc03]:not([data-has-label]) {\\n padding: calc(var(--label-spacing) / 2 - 1px) 0.5em calc(var(--label-spacing) / 2 - 1px);\\n}\\n.field > textarea.field__input[data-v-701ddc03] {\\n height: 4.875em;\\n}\\n.field.disabled > .field__label[data-v-701ddc03] {\\n color: black;\\n}\\n.field.disabled > .field__input[data-v-701ddc03] {\\n background: rgba(255, 255, 255, 0.1);\\n border-color: rgba(0, 0, 0, 0.1);\\n}\\n.field.disabled > .field__input[data-v-701ddc03]::-moz-placeholder {\\n color: black;\\n}\\n.field.disabled > .field__input[data-v-701ddc03]::placeholder {\\n color: black;\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/inputs/input-float.vue?./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/diary.vue?vue&type=style&index=0&id=29671fd8&scoped=true&lang=scss&": +/*!************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/diary.vue?vue&type=style&index=0&id=29671fd8&scoped=true&lang=scss& ***! + \************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \".diary[data-v-29671fd8] {\\n display: grid;\\n grid-template-columns: 1fr 30em;\\n grid-template-rows: 4em 1fr;\\n gap: 0 var(--padding);\\n grid-template-areas: 'header-add header-display' 'diary-add diary-display';\\n height: 100%;\\n}\\n.diary .header-add[data-v-29671fd8] {\\n grid-area: header-add;\\n}\\n.diary .header-display[data-v-29671fd8] {\\n grid-area: header-display;\\n}\\n.diary .add-forms[data-v-29671fd8] {\\n grid-area: diary-add;\\n display: flex;\\n flex-direction: column;\\n}\\n.diary .add-forms .food-selection[data-v-29671fd8] {\\n flex: 1;\\n}\\n.diary .add-forms .food-selection .recipe-grid[data-v-29671fd8], .diary .add-forms .food-selection .ingredient-grid[data-v-29671fd8] {\\n height: 100%;\\n}\\n.diary .display-forms[data-v-29671fd8] {\\n grid-area: diary-display;\\n}\\n.diary .display-forms .time-period-header[data-v-29671fd8] {\\n display: flex;\\n align-items: center;\\n}\\n.diary .display-forms .time-period-header > *[data-v-29671fd8]:first-child {\\n margin-right: 0.5em;\\n}\\n.diary #diary_entry_form[data-v-29671fd8] {\\n display: flex;\\n}\\n.diary #diary_entry_form > *[data-v-29671fd8]:not(:last-child) {\\n margin-right: 0.5em;\\n}\\n.diary .nutrient-input[data-v-29671fd8] {\\n display: flex;\\n align-items: center;\\n}\\n.diary .nutrientTargets[data-v-29671fd8] {\\n display: grid;\\n grid-template-columns: -webkit-max-content 9em 1fr;\\n grid-template-columns: max-content 9em 1fr;\\n grid-gap: 0.5em;\\n align-items: center;\\n}\\n.diary .nutrientTargets .dailyTargetNutrient[data-v-29671fd8] {\\n display: contents;\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/pages/diary.vue?./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/layouts/layout-default.vue?vue&type=style&index=0&id=c75993c2&scoped=true&lang=scss&": +/*!*****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/layouts/layout-default.vue?vue&type=style&index=0&id=c75993c2&scoped=true&lang=scss& ***! + \*****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \".layout-default[data-v-c75993c2] {\\n display: grid;\\n grid-template-columns: var(--menu-collapsed-width) 1fr;\\n grid-template-rows: 0 1fr;\\n gap: 1px 1px;\\n grid-template-areas: \\\"menu quick-info\\\" \\\"menu content\\\";\\n}\\n.layout-default .quick-info[data-v-c75993c2] {\\n grid-area: quick-info;\\n padding: var(--padding);\\n display: flex;\\n align-items: center;\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/pages/layouts/layout-default.vue?./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/pages/target-manager.vue?vue&type=style&index=0&id=54d33f2c&scoped=true&lang=scss&": +/*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/pages/target-manager.vue?vue&type=style&index=0&id=54d33f2c&scoped=true&lang=scss& ***! + \*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \".target-manager[data-v-54d33f2c] {\\n display: grid;\\n grid-template-columns: 1fr 30em;\\n grid-template-rows: 4em 1fr;\\n gap: 0 var(--padding);\\n grid-template-areas: \\\"header-all header-form\\\" \\\"targets-all target-selected\\\";\\n min-height: calc(100vh - 7em);\\n /* Make it fill as much of the screen as possible to start off*/\\n}\\n.target-manager .header-all[data-v-54d33f2c] {\\n grid-area: header-all;\\n}\\n.target-manager .header-form[data-v-54d33f2c] {\\n grid-area: header-form;\\n}\\n.target-manager .targets-all[data-v-54d33f2c] {\\n grid-area: targets-all;\\n}\\n.target-manager .targets-all .targets-table[data-v-54d33f2c] {\\n height: 100%;\\n}\\n.target-manager .target-selected[data-v-54d33f2c] {\\n grid-area: target-selected;\\n}\\n.target-manager .target-selected form[data-v-54d33f2c] {\\n display: grid;\\n grid-template-columns: repeat(3, 1fr);\\n}\\n.target-manager .target-selected form > *[data-v-54d33f2c]:not(.nutrient-input-row) {\\n margin: 1px;\\n}\\n.target-manager .target-selected form #description-container[data-v-54d33f2c] {\\n grid-column: span 3;\\n}\\n.target-manager .target-selected form .nutrient-input-row[data-v-54d33f2c] {\\n display: contents;\\n}\\n.target-manager .target-selected form .nutrient-input-row [data-icon][data-v-54d33f2c] {\\n margin-right: 0.5em;\\n}\\n.target-manager .target-selected form .nutrient-input-row span[data-v-54d33f2c] {\\n align-self: center;\\n}\\n.target-manager .target-selected form .nutrient-input-row > *[data-v-54d33f2c] {\\n margin: 1px;\\n}\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack:///./src/components/pages/target-manager.vue?./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options"); + +/***/ }), + +/***/ "./node_modules/vue-style-loader/index.js?!./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/components/cell-renderers/action-button.vue?vue&type=style&index=0&id=6a6cf40f&scoped=true&lang=css&": +/*!*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\ + !*** ./node_modules/vue-style-loader??ref--6-oneOf-1-0!./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/cell-renderers/action-button.vue?vue&type=style&index=0&id=6a6cf40f&scoped=true&lang=css& ***! + \*********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +eval("// style-loader: Adds some css to the DOM by adding a diff --git a/trouser/src/assets/css/reset.css b/trouser/src/assets/css/reset.css new file mode 100644 index 0000000..7414a74 --- /dev/null +++ b/trouser/src/assets/css/reset.css @@ -0,0 +1,367 @@ +/* http://meyerweb.com/eric/tools/css/reset/ + v2.0-modified | 20110126 + License: none (public domain) +*/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +/* make sure to set some focus styles for accessibility */ +:focus { + outline: 0; +} + +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +body { + line-height: 1; +} + +ol, ul { + list-style: none; +} + +blockquote, q { + quotes: none; +} + +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +input[type=search]::-webkit-search-cancel-button, +input[type=search]::-webkit-search-decoration, +input[type=search]::-webkit-search-results-button, +input[type=search]::-webkit-search-results-decoration { + -webkit-appearance: none; + -moz-appearance: none; +} + +input[type=search] { + -webkit-appearance: none; + -moz-appearance: none; + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +textarea { + overflow: auto; + vertical-align: top; + resize: vertical; +} + +/** + * Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3. + */ + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; + max-width: 100%; +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address styling not present in IE 7/8/9, Firefox 3, and Safari 4. + * Known issue: no IE 6 support. + */ + +[hidden] { + display: none; +} + +/** + * 1. Correct text resizing oddly in IE 6/7 when body `font-size` is set using + * `em` units. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-size: 100%; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ + -ms-text-size-adjust: 100%; /* 2 */ +} + +/** + * Address `outline` inconsistency between Chrome and other browsers. + */ + +a:focus { + outline: thin dotted; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/** + * 1. Remove border when inside `a` element in IE 6/7/8/9 and Firefox 3. + * 2. Improve image quality when scaled in IE 7. + */ + +img { + border: 0; /* 1 */ + -ms-interpolation-mode: bicubic; /* 2 */ +} + +/** + * Address margin not present in IE 6/7/8/9, Safari 5, and Opera 11. + */ + +figure { + margin: 0; +} + +/** + * Correct margin displayed oddly in IE 6/7. + */ + +form { + margin: 0; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct color not being inherited in IE 6/7/8/9. + * 2. Correct text not wrapping in Firefox 3. + * 3. Correct alignment displayed oddly in IE 6/7. + */ + +legend { + border: 0; /* 1 */ + padding: 0; + white-space: normal; /* 2 */ + *margin-left: -7px; /* 3 */ +} + +/** + * 1. Correct font size not being inherited in all browsers. + * 2. Address margins set differently in IE 6/7, Firefox 3+, Safari 5, + * and Chrome. + * 3. Improve appearance and consistency in all browsers. + */ + +button, +input, +select, +textarea { + font-size: 100%; /* 1 */ + margin: 0; /* 2 */ + vertical-align: baseline; /* 3 */ + *vertical-align: middle; /* 3 */ +} + +/** + * Address Firefox 3+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +button, +input { + line-height: normal; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Chrome, Safari 5+, and IE 6+. + * Correct `select` style inheritance in Firefox 4+ and Opera. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + * 4. Remove inner spacing in IE 7 without affecting normal text inputs. + * Known issue: inner spacing remains in IE 6. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ + *overflow: visible; /* 4 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * 1. Address box sizing set to content-box in IE 8/9. + * 2. Remove excess padding in IE 8/9. + * 3. Remove excess padding in IE 7. + * Known issue: excess padding remains in IE 6. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ + *height: 13px; /* 3 */ + *width: 13px; /* 3 */ +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari 5 and Chrome + * on OS X. + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Remove inner padding and border in Firefox 3+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * 1. Remove default vertical scrollbar in IE 6/7/8/9. + * 2. Improve readability and alignment in all browsers. + */ + +textarea { + overflow: auto; /* 1 */ + vertical-align: top; /* 2 */ +} + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +html, +button, +input, +select, +textarea { + color: #222; +} + + +::-moz-selection { + background: #b3d4fc; + text-shadow: none; +} + +::selection { + background: #b3d4fc; + text-shadow: none; +} + +img { + vertical-align: middle; +} + +fieldset { + border: 0; + margin: 0; + padding: 0; +} + +textarea { + resize: vertical; +} + +.chromeframe { + margin: 0.2em 0; + background: #ccc; + color: #000; + padding: 0.2em 0; +} + diff --git a/trouser/src/assets/js/pants_api.js b/trouser/src/assets/js/pants_api.js new file mode 100644 index 0000000..d6e13a6 --- /dev/null +++ b/trouser/src/assets/js/pants_api.js @@ -0,0 +1,513 @@ +/* +* This is a connector for javascript to the PANTS api. +*/ + +/** + * Abstract base class for the various APIs + */ +class _ApiBase { + /** + * Creates an api subclass instance, with a fetch function from the PANTS API collection class + * @param {function} api_fetch_function Fetches api data, takes an absolute api location, and an object of fetch options + * @param {function} api_prefixer_function Converts relative api path to absolute, takes a relative api location + */ + constructor(api_fetch_function, api_prefixer_function){ + this.fetch = api_fetch_function; + this.api_prefix = api_prefixer_function + } + + /** + * Creates a new API object + * @param api_location {string} The relative api location (e.g. 'target/') that this object will be created at + * @param json_details {Object} The information for the target + * @internal + */ + async _create_at_location(api_location, json_details){ + return this.fetch(this.api_prefix(api_location), { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(json_details) + }) + .then(resp => resp.json()); + } + + /** + * Gets a list of api objects, supports searching, limit, offset, ordering + * + * @param {string} api_location relative api_location for this object collection (e.g. 'target/') + * @param {Object} options Options to pass to the api + * @param {number} options.offset Which ingredient to start returning results from + * @param {number} options.limit Maximum number of results to return + * @param {number} options.startRow Which ingredient to start returning results from (obsolete, use offset) + * @param {number} options.endRow The last ingredient to return results from, exclusive (obsolete, use limit) + * @param {string} options.ordering + * @param {string} options.searchKey A string by which results will be filtered + * @param {string} options.filterDict A dictionary of filters, + * key is the property to be filtered on, + * value is filter array [filter operator, property value] or array of filter arrays (to filter same property in multiple ways, e.g. both less than and greater than) + * filter operator is should be in standard js notation, e.g. use '<' to get less than, or '>=' to get greater than or equal to. + * @returns {Promise} + * @internal + */ + async _get_all_at_location(api_location, options) { + // Convert location to URL to ease adding params + let api_location_url = new URL(this.api_prefix(api_location)); + + if(typeof options === 'object'){ + // Get the number of requested results + let offset = options.offset ?? options.startRow ?? 0; + if(offset) api_location_url.searchParams.set('offset', offset.toString()); + + let limit = options.limit ?? (options.endRow - options.startRow); + if (limit) api_location_url.searchParams.set('limit', limit.toString()); + + if(options.sortModel){ + // Handle sorting options + let ordering = []; + for (let id of options.sortModel) { + let param = ''; + param += id.sort === 'desc' ? '-' : ''; + param += id.colId; + ordering.push(param) + } + api_location_url.searchParams.set('ordering', ordering.join(',')); + } + + if(options.searchKey){ + // Handle searching options + api_location_url.searchParams.set('search', options.searchKey); + } + + if(options.filterDict){ + for(const [property, value] of Object.entries(options.filterDict)){ + // If the value is a direct filter array, then make it an array of filter arrays + let filters = value; + if(!Array.isArray(filters[0])) filters = [filters]; + + for(let filterArray of filters){ + if(filterArray[0] in this._jsFilterTranslation){ + api_location_url.searchParams.set(`${property}${this._jsFilterTranslation[filterArray[0]]}`, filterArray[1]); + } else { + console.error(`Filter array has comparator ${filterArray[0]}, which cannot be translated to django filter string.`) + } + } + } + } + } + + // Fetch the data + return this.fetch(api_location_url.toString()).then(resp=>resp.json()); + } + + /** + * Dictionary describing how the given js filter string converts to a django filter string so that the api accepts it + * @type {{}} + * @private + */ + _jsFilterTranslation = { + '<': '__lt', + '<=': '__lte', + '>': '__gt', + '>=': '__gte', + '==': '', + } + + /** + * Updates an API object based on the json object passed in + * @param uri {string} The absolute URI that uniquely identifies the given API object + * @param json_details {Object} The details that will be overwritten onto the API object (details not included are unaffected) + */ + async update(uri, json_details) { + return this.fetch(uri, { + method: 'PATCH', + headers: new Headers({ + 'Content-Type': 'application/json' + }), + body: JSON.stringify(json_details) + }) + .then(resp => resp.json()) + } + + /** + * Deletes the specified api object + * @param uri {string} The absolute URI that uniquely identifies the given target + */ + async delete(uri){ + // Send the command to delete the API object using the api + return this.fetch(uri, { + method: 'DELETE', + }) + } +} + +/** + * Target API subclass + */ +class Target extends _ApiBase{ + + /** + * Creates a new target + * @param json_details {Object} The information for the target + */ + async create(json_details){ + return super._create_at_location('target/', json_details); + } + + /** + * Gets the daily target for the current user + * @return {object} the object specifying the daily target + */ + async getDaily(){ + // Send the command to delete the recipe using the api + return this.fetch(this.api_prefix('daily_target')) + .then(resp=>resp.json()); + } +} + +/** + * DiaryFood API subclass + */ +class DiaryFood extends _ApiBase{ + + /** + * Creates a new DiaryFood + * @param json_details {Object} The information for the DiaryFood + */ + async create(json_details){ + return super._create_at_location('diaryfood/', json_details); + } + + /** + * Gets a list of DiaryFood object, supports searching, limit, offset, ordering + * + * @param {Object} options Options to pass to the api + * @param {number} options.limit Maximum number of results to return + * @param {number} options.offset Which ingredient to start returning results from + * @param {string} options.ordering + * @param {string} options.searchKey A string by which results will be filtered + * + * @returns {Promise} + */ + async get_all(options){ + return super._get_all_at_location('diaryfood/', options) + } +} + +/** + * Encompassing class for the API, manages connecting to the remote resource and ferrying results back + */ +class Pants { + /** + * + * @param {string} api_version The version of the api to use + * @param {Object} authentication Describes what authentication method you are using + * @param {string} authentication.method either "Basic", or "Token" + * @param {string} authentication.token CSRF token to use for requests + * @param {string} authentication.username username to use for basic auth requests + * @param {string} authentication.password password to use for basic auth requests + * @param {string} [api_hostname] The hostname of the server, if not passed in it will use window.location.host (which includes the port) + */ + constructor(api_version, authentication, api_hostname) { + this.api_location = `${api_hostname || window.location.host}/api/${api_version}/`; + this.authentication_method = authentication.method; + if(authentication.method === "Basic"){ + this.api_uname = authentication.username; + this.api_pword = authentication.password; + } + else{ + this.token = authentication.token; + } + } + + /** + * Gets a fully qualified path to a specific api resource, given a relative path + * @param relative_path The relative api path to access, e.g. 'ingredient/280' + */ + get_api_path(relative_path){ + return this.api_location + relative_path + } + + get_basic_auth_credentials() { + return 'Basic ' + btoa(`${this.api_uname}:${this.api_pword}`) + } + + /** + * Fetch, but with authentication automatically handled according to what authentication this API was instantiated with + * @param url + * @param init + * @returns {Promise} + */ + async authenticated_fetch(url, init) { + // Ensure the Headers object is present + init = init || {}; + + if (init.headers === undefined) { + init.headers = new Headers() + } + if(!(init.headers instanceof Headers)){ + // It is valid to just pass in an object, but we only deal with Headers. Convert + var headers = new Headers(); + Object.entries(init.headers).forEach(entry=>{ + headers.set(entry[0], entry[1]); + }) + init.headers = headers; + } + + if (this.authentication_method === "Basic") { + init.headers.set("Authorization", this.get_basic_auth_credentials()); + } else { + init.headers.set("X-CSRFToken", this.token); + } + + return fetch(url, init) + .then(this.handle_api_errors) + .catch(reason => alert(reason)) + } + + /** + * Reusable function for handling errors from the api + */ + async handle_api_errors(response) { + if (!response.ok) { + throw Error(await response.text()) + } + return response + } + + /** + * Creates a new ingredient + * @param json_details {Object} The information for the ingredient + */ + async create_ingredient(json_details){ + return this.authenticated_fetch(this.get_api_path('ingredient/'), { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(json_details) + }) + .then(resp => resp.json()) + } + + /** + * Gets a list of ingredients, supports searching, limit, offset, ordering + * + * @param {Object} options Options to pass to the api + * @param {number} options.limit Maximum number of results to return + * @param {number} options.offset Which ingredient to start returning results from + * @param {string} options.ordering + * @param {string} options.searchKey A string by which results will be filtered + * + * @returns {Promise} + */ + async get_ingredients(options) { + + // Get the number of requested results + let num_requested = options.endRow - options.startRow; + + let api_location = new URL(this.get_api_path('ingredient/')); + api_location.searchParams.set('offset', options.startRow); + api_location.searchParams.set('limit', num_requested); + + // Handle sorting options + let ordering = []; + for (let id of options.sortModel) { + let param = ''; + param += id.sort === 'desc' ? '-' : ''; + param += id.colId; + ordering.push(param) + } + api_location.searchParams.set('ordering', ordering.join(',')); + + if(typeof options.searchKey !== "undefined"){ + // Handle searching options + api_location.searchParams.set('search', options.searchKey); + } + + // Fetch the data + return this.authenticated_fetch(api_location.toString()); + } + + /** + * Updates an ingredient (identified by uri) based on the json object passed in + * @param uri {string} The URI that uniquely identifies the given ingredient + * @param json_details {Object} The details that will be overwritten onto the ingredient (details not included are unaffected) + */ + async edit_ingredient(uri, json_details) { + return this.authenticated_fetch(uri, { + method: 'PATCH', + headers: new Headers({ + 'Content-Type': 'application/json' + }), + body: JSON.stringify(json_details) + }) + .then(resp => resp.json()) + } + + /** + * Deletes the currently selected ingredient + * @param ingredient_uri {string} The ingredient to delete + */ + async delete_ingredient(ingredient_uri){ + // Send the command to delete the ingredient using the api + return this.authenticated_fetch(ingredient_uri, { + method: 'DELETE', + }) + } + + /** + * Gets a list of recipes, supports searching, limit, offset, ordering + * + * @param {Object} options Options to pass to the api + * @param {number} options.limit Maximum number of results to return + * @param {number} options.offset Which ingredient to start returning results from + * @param {string} options.ordering + * @param {string} options.searchKey A string by which results will be filtered + * + * @returns {Promise} + */ + async get_recipes(options){ + + // Get the number of requested results + let num_requested = options.endRow - options.startRow; + + let api_location = new URL(this.get_api_path('recipe/')); + api_location.searchParams.set('offset', options.startRow); + api_location.searchParams.set('limit', num_requested); + + // Handle sorting options + let ordering = []; + for (let id of options.sortModel || []) { + let param = ''; + param += id.sort === 'desc' ? '-' : ''; + param += id.colId; + ordering.push(param) + } + api_location.searchParams.set('ordering', ordering.join(',')); + + if(typeof options.searchKey !== "undefined"){ + // Handle searching options + api_location.searchParams.set('search', options.searchKey); + } + + // Fetch the data + return this.authenticated_fetch(api_location.toString()); + } + + /** + * Gets a single recipe, but this includes components as well + * + * @param {string} recipe_uri the uri for the recipe + * + * @returns {Promise} + */ + async get_recipe_full(recipe_uri){ + // Fetch the data + return this.authenticated_fetch(recipe_uri); + } + + /** + * Creates a new recipe + * @param json_details {Object} The information for the target + */ + async create_recipe(json_details){ + return this.authenticated_fetch(this.get_api_path('recipe/'), { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(json_details) + }) + .then(resp => resp.json()) + } + + /** + * Updates a recipe (identified by uri) based on the json object passed in + * @param uri {string} The URI that uniquely identifies the given recipe + * @param json_details {Object} The details that will be overwritten onto the recipe (details not included are unaffected) + */ + async edit_recipe(uri, json_details) { + return this.authenticated_fetch(uri, { + method: 'PATCH', + headers: new Headers({ + 'Content-Type': 'application/json' + }), + body: JSON.stringify(json_details) + }) + .then(resp => resp.json()) + } + + /** + * Deletes the specified recipe + * @param recipe_uri {string} The recipe to delete + */ + async delete_recipe(recipe_uri){ + // Send the command to delete the recipe using the api + return this.authenticated_fetch(recipe_uri, { + method: 'DELETE', + }) + } + + /** + * Gets a list of all recipe flags + * @returns {Promise} + */ + async get_recipe_flags(){ + let api_location = new URL(this.get_api_path('recipe_flag/')); + // Fetch the data + return this.authenticated_fetch(api_location.toString()).then(resp=>resp.json()); + } + + /** + * Creates a diary food entry with the given details + * @param json_details + * @returns {Promise} + */ + async create_diaryfood(json_details){ + return this.authenticated_fetch(this.get_api_path('diaryfood/'), { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(json_details) + }) + .then(resp => resp.json()) + } + + /** + * Get all diaryfood objects in a list + * @param options {Object} Sort and filter options + * @param options.min_start {string} ISO date string, only return results whose start_time >= this + * @param options.max_start {string} ISO date string, only return results whose start_time <= this + * @returns {Promise} + */ + async get_diaryfood(options){ + // Set up the query string to search if necessary + let api_location = new URL(this.get_api_path('diaryfood/')); + if(options.min_start !== undefined){ + api_location.searchParams.set('start_time__gte', options.min_start); + } + if(options.max_start !== undefined){ + api_location.searchParams.set('start_time__lte', options.max_start); + } + return this.authenticated_fetch(api_location.toString()) + .then(resp=>resp.json()); + } + + async get_target(){ + return this.authenticated_fetch(this.get_api_path('target/')) + .then(resp=>resp.json()) + } + + // @todo have to pass arrow functions to preserve 'this', how to preserve 'this' information? + // Target should probably be subclasses from some API base class, and Pants should just be an api collection class? + Target = new Target((path, options)=>this.authenticated_fetch(path, options), (relative)=>this.get_api_path(relative)); + DiaryFood = new DiaryFood((path, options)=>this.authenticated_fetch(path, options), (relative)=>this.get_api_path(relative)); + + +} + +export default Pants; + diff --git a/trouser/src/assets/logo.png b/trouser/src/assets/logo.png new file mode 100644 index 0000000..f3d2503 Binary files /dev/null and b/trouser/src/assets/logo.png differ diff --git a/trouser/src/components/cell-renderers/action-button.vue b/trouser/src/components/cell-renderers/action-button.vue new file mode 100644 index 0000000..70c9f8d --- /dev/null +++ b/trouser/src/components/cell-renderers/action-button.vue @@ -0,0 +1,38 @@ + + + + + \ No newline at end of file diff --git a/trouser/src/components/informational/target-summary.vue b/trouser/src/components/informational/target-summary.vue new file mode 100644 index 0000000..38d60cd --- /dev/null +++ b/trouser/src/components/informational/target-summary.vue @@ -0,0 +1,222 @@ + + + + + + \ No newline at end of file diff --git a/trouser/src/components/inputs/input-checkbox.vue b/trouser/src/components/inputs/input-checkbox.vue new file mode 100644 index 0000000..3ffdd6a --- /dev/null +++ b/trouser/src/components/inputs/input-checkbox.vue @@ -0,0 +1,93 @@ + + + + + \ No newline at end of file diff --git a/trouser/src/components/inputs/input-float.vue b/trouser/src/components/inputs/input-float.vue new file mode 100644 index 0000000..2f10e25 --- /dev/null +++ b/trouser/src/components/inputs/input-float.vue @@ -0,0 +1,288 @@ + + + + + \ No newline at end of file diff --git a/trouser/src/components/pages/diary.vue b/trouser/src/components/pages/diary.vue new file mode 100644 index 0000000..226cd3a --- /dev/null +++ b/trouser/src/components/pages/diary.vue @@ -0,0 +1,622 @@ + + + + + \ No newline at end of file diff --git a/trouser/src/components/pages/home.vue b/trouser/src/components/pages/home.vue new file mode 100644 index 0000000..2055a01 --- /dev/null +++ b/trouser/src/components/pages/home.vue @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/trouser/src/components/pages/ingredient-manager.vue b/trouser/src/components/pages/ingredient-manager.vue new file mode 100644 index 0000000..7c21525 --- /dev/null +++ b/trouser/src/components/pages/ingredient-manager.vue @@ -0,0 +1,422 @@ + + + + + \ No newline at end of file diff --git a/trouser/src/components/pages/layouts/layout-default.vue b/trouser/src/components/pages/layouts/layout-default.vue new file mode 100644 index 0000000..4f26900 --- /dev/null +++ b/trouser/src/components/pages/layouts/layout-default.vue @@ -0,0 +1,256 @@ + + + + + + + + + diff --git a/trouser/src/components/pages/recipe-manager.vue b/trouser/src/components/pages/recipe-manager.vue new file mode 100644 index 0000000..0b507ed --- /dev/null +++ b/trouser/src/components/pages/recipe-manager.vue @@ -0,0 +1,543 @@ + + + + + \ No newline at end of file diff --git a/trouser/src/components/pages/target-manager.vue b/trouser/src/components/pages/target-manager.vue new file mode 100644 index 0000000..d7a2c4c --- /dev/null +++ b/trouser/src/components/pages/target-manager.vue @@ -0,0 +1,314 @@ + + + + + \ No newline at end of file diff --git a/trouser/src/components/recipe-component.vue b/trouser/src/components/recipe-component.vue new file mode 100644 index 0000000..4ea9caa --- /dev/null +++ b/trouser/src/components/recipe-component.vue @@ -0,0 +1,106 @@ + + + + + \ No newline at end of file diff --git a/trouser/src/main.js b/trouser/src/main.js new file mode 100644 index 0000000..62ce779 --- /dev/null +++ b/trouser/src/main.js @@ -0,0 +1,78 @@ +import Vue from 'vue' +import VueRouter from 'vue-router' + +Vue.use(VueRouter) + +// Prepare reset of styles +import './assets/css/reset.css' + +import App from './App.vue' + + +// Prepare Font Awesome +import {library} from '@fortawesome/fontawesome-svg-core' +import { + faHome, + faCarrot, + faHamburger, + faBook, + faBullseye, + faUser, + faStickyNote, + faMinus, + faCheck, + faMoneyBillAlt, + faBolt, + faEgg, + faBreadSlice, + faTint, + faTintSlash, + faSeedling, + faStroopwafel, + faCubes, +} from '@fortawesome/free-solid-svg-icons' +import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome' + +library.add( + faHome, + faCarrot, + faHamburger, + faBook, + faBullseye, + faUser, + faStickyNote, + faMinus, + faCheck, + faMoneyBillAlt, + faBolt, + faEgg, + faBreadSlice, + faTint, + faTintSlash, + faSeedling, + faStroopwafel, + faCubes, +) +Vue.component('fa-icon', FontAwesomeIcon) + +Vue.config.productionTip = false + +// Import router components +import Home from './components/pages/home' +import IngredientManager from './components/pages/ingredient-manager' +import RecipeManager from './components/pages/recipe-manager' +import Diary from './components/pages/diary' +import TargetManager from '@/components/pages/target-manager' + +new Vue({ + render: h => h(App), + router: new VueRouter({ + routes: [ + {path: '/', component: Home}, + {path: '/ingredient_manager', component: IngredientManager}, + {path: '/recipe_manager', component: RecipeManager}, + {path: '/diary', component: Diary}, + {path: '/target_manager', component: TargetManager}, + ] + }) +}).$mount('#app') diff --git a/trouser/vue.config.js b/trouser/vue.config.js new file mode 100644 index 0000000..7512d4a --- /dev/null +++ b/trouser/vue.config.js @@ -0,0 +1,21 @@ +const path = require("path"); + +//vue.config.js +module.exports = { + chainWebpack: config => { + config + .plugin('html') + .tap(args => { + args[0].title = "Trouser - What goes over Pants"; + return args; + }) + }, + // Configure how the public path when building for production + // Normally you can run this application using npm's built in server (npm serve), but if you instead use + // npm run build -- --mode staging + // Then the .env.staging file for environment variables will be loaded + publicPath: process.env.VUE_APP_STATIC_URL, + // The output will go to the django app folder always + outputDir: path.resolve(__dirname, "..","pants","frontend","static", "frontend"), + indexPath: path.resolve(__dirname, "..","pants","frontend","templates", "frontend", "index.html"), +} \ No newline at end of file