init
This commit is contained in:
commit
92844ad44f
62
.eslintrc.json
Normal file
62
.eslintrc.json
Normal file
@ -0,0 +1,62 @@
|
||||
{
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2019,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"env": {
|
||||
"es6": true,
|
||||
"browser": true
|
||||
},
|
||||
"plugins": [
|
||||
"svelte3"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"**/*.svelte"
|
||||
],
|
||||
"processor": "svelte3/svelte3"
|
||||
}
|
||||
],
|
||||
"rules": {
|
||||
"arrow-spacing": "error",
|
||||
"block-scoped-var": "error",
|
||||
"block-spacing": "error",
|
||||
"brace-style": ["error", "stroustrup", {}],
|
||||
"camelcase": "error",
|
||||
"comma-dangle": ["error", "never"],
|
||||
"comma-spacing": ["error", { "before": false, "after": true }],
|
||||
"comma-style": [1, "last"],
|
||||
"consistent-this": [1, "_this"],
|
||||
"curly": [1, "multi"],
|
||||
"eol-last": 1,
|
||||
"eqeqeq": 1,
|
||||
"func-names": 1,
|
||||
"indent": ["error", 2, { "SwitchCase": 1 }],
|
||||
"lines-around-comment": ["error", { "beforeBlockComment": true, "allowArrayStart": true }],
|
||||
"max-len": [1, 240, 2], // 2 spaces per tab, max 80 chars per line
|
||||
"new-cap": 1,
|
||||
"newline-before-return": "error",
|
||||
"no-array-constructor": 1,
|
||||
"no-inner-declarations": [1, "both"],
|
||||
"no-mixed-spaces-and-tabs": 1,
|
||||
"no-multi-spaces": 2,
|
||||
"no-new-object": 1,
|
||||
"no-shadow-restricted-names": 1,
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"padded-blocks": ["error", { "blocks": "never", "switches": "always" }],
|
||||
"prefer-const": "error",
|
||||
"prefer-template": "error",
|
||||
"one-var": 0,
|
||||
"quote-props": ["error", "always"],
|
||||
"quotes": [1, "single"],
|
||||
"radix": 1,
|
||||
"semi": [1, "always"],
|
||||
"space-before-blocks": [1, "always"],
|
||||
"space-infix-ops": 1,
|
||||
"vars-on-top": 1,
|
||||
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1 }],
|
||||
"spaced-comment": ["error", "always", { "markers": ["/"] }]
|
||||
}
|
||||
|
||||
}
|
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/node_modules/
|
||||
/public/build/
|
||||
|
||||
.DS_Store
|
5
.idea/.gitignore
vendored
Normal file
5
.idea/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
29
.idea/codeStyles/Project.xml
Normal file
29
.idea/codeStyles/Project.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<option name="RIGHT_MARGIN" value="140" />
|
||||
<JSCodeStyleSettings version="0">
|
||||
<option name="FORCE_SEMICOLON_STYLE" value="true" />
|
||||
<option name="USE_DOUBLE_QUOTES" value="false" />
|
||||
<option name="FORCE_QUOTE_STYlE" value="true" />
|
||||
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
|
||||
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
|
||||
<option name="SPACES_WITHIN_IMPORTS" value="true" />
|
||||
</JSCodeStyleSettings>
|
||||
<codeStyleSettings language="JavaScript">
|
||||
<option name="RIGHT_MARGIN" value="240" />
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="1" />
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="ALIGN_MULTILINE_FOR" value="false" />
|
||||
<option name="IF_BRACE_FORCE" value="1" />
|
||||
<option name="DOWHILE_BRACE_FORCE" value="1" />
|
||||
<option name="WHILE_BRACE_FORCE" value="1" />
|
||||
<option name="FOR_BRACE_FORCE" value="1" />
|
||||
<indentOptions>
|
||||
<option name="INDENT_SIZE" value="2" />
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="2" />
|
||||
<option name="TAB_SIZE" value="2" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||
</state>
|
||||
</component>
|
6
.idea/inspectionProfiles/Project_Default.xml
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
6
.idea/jsLibraryMappings.xml
Normal file
6
.idea/jsLibraryMappings.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<includedPredefinedLibrary name="Node.js Core" />
|
||||
</component>
|
||||
</project>
|
6
.idea/jsLinters/eslint.xml
Normal file
6
.idea/jsLinters/eslint.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EslintConfiguration">
|
||||
<custom-configuration-file used="true" path="$PROJECT_DIR$/.eslintrc.json" />
|
||||
</component>
|
||||
</project>
|
6
.idea/misc.xml
Normal file
6
.idea/misc.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/svelte_menu.iml" filepath="$PROJECT_DIR$/.idea/svelte_menu.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
8
.idea/svelte_menu.iml
Normal file
8
.idea/svelte_menu.iml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
93
README.md
Normal file
93
README.md
Normal file
@ -0,0 +1,93 @@
|
||||
*Looking for a shareable component template? Go here --> [sveltejs/component-template](https://github.com/sveltejs/component-template)*
|
||||
|
||||
---
|
||||
|
||||
# svelte app
|
||||
|
||||
This is a project template for [Svelte](https://svelte.dev) apps. It lives at https://github.com/sveltejs/template.
|
||||
|
||||
To create a new project based on this template using [degit](https://github.com/Rich-Harris/degit):
|
||||
|
||||
```bash
|
||||
npx degit sveltejs/template svelte-app
|
||||
cd svelte-app
|
||||
```
|
||||
|
||||
*Note that you will need to have [Node.js](https://nodejs.org) installed.*
|
||||
|
||||
|
||||
## Get started
|
||||
|
||||
Install the dependencies...
|
||||
|
||||
```bash
|
||||
cd svelte-app
|
||||
npm install
|
||||
```
|
||||
|
||||
...then start [Rollup](https://rollupjs.org):
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Navigate to [localhost:5000](http://localhost:5000). You should see your app running. Edit a component file in `src`, save it, and reload the page to see your changes.
|
||||
|
||||
By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`.
|
||||
|
||||
|
||||
## Building and running in production mode
|
||||
|
||||
To create an optimised version of the app:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can run the newly built app with `npm run start`. This uses [sirv](https://github.com/lukeed/sirv), which is included in your package.json's `dependencies` so that the app will work when you deploy to platforms like [Heroku](https://heroku.com).
|
||||
|
||||
|
||||
## Single-page app mode
|
||||
|
||||
By default, sirv will only respond to requests that match files in `public`. This is to maximise compatibility with static fileservers, allowing you to deploy your app anywhere.
|
||||
|
||||
If you're building a single-page app (SPA) with multiple routes, sirv needs to be able to respond to requests for *any* path. You can make it so by editing the `"start"` command in package.json:
|
||||
|
||||
```js
|
||||
"start": "sirv public --single"
|
||||
```
|
||||
|
||||
|
||||
## Deploying to the web
|
||||
|
||||
### With [now](https://zeit.co/now)
|
||||
|
||||
Install `now` if you haven't already:
|
||||
|
||||
```bash
|
||||
npm install -g now
|
||||
```
|
||||
|
||||
Then, from within your project folder:
|
||||
|
||||
```bash
|
||||
cd public
|
||||
now deploy --name my-project
|
||||
```
|
||||
|
||||
As an alternative, use the [Now desktop client](https://zeit.co/download) and simply drag the unzipped project folder to the taskbar icon.
|
||||
|
||||
### With [surge](https://surge.sh/)
|
||||
|
||||
Install `surge` if you haven't already:
|
||||
|
||||
```bash
|
||||
npm install -g surge
|
||||
```
|
||||
|
||||
Then, from within your project folder:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
surge public my-project.surge.sh
|
||||
```
|
3301
package-lock.json
generated
Normal file
3301
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
26
package.json
Normal file
26
package.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "svelte-app",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"dev": "rollup -c -w",
|
||||
"start": "sirv public"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^11.0.0",
|
||||
"@rollup/plugin-node-resolve": "^7.0.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-svelte3": "^2.7.3",
|
||||
"rollup": "^1.20.0",
|
||||
"rollup-plugin-livereload": "^1.0.0",
|
||||
"rollup-plugin-svelte": "^5.0.3",
|
||||
"rollup-plugin-terser": "^5.1.2",
|
||||
"svelte": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.19.2",
|
||||
"debounce": "^1.2.0",
|
||||
"rollup-plugin-replace": "^2.2.0",
|
||||
"sirv-cli": "^0.4.4"
|
||||
}
|
||||
}
|
BIN
public/favicon.png
Normal file
BIN
public/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
503
public/global.css
Normal file
503
public/global.css
Normal file
@ -0,0 +1,503 @@
|
||||
@import url('https://fonts.googleapis.com/css?family=Roboto');
|
||||
|
||||
/* Global Styles */
|
||||
:root {
|
||||
--primary-color: #64B5F6;
|
||||
--dark-color: #333333;
|
||||
--light-color: #f4f4f4;
|
||||
--danger-color: #dc3545;
|
||||
--success-color: #28a745;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
background-color: #fff;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dataRow {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Utilities */
|
||||
.container {
|
||||
max-width: 1100px;
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
/* Text Styles*/
|
||||
.x-large {
|
||||
font-size: 4rem;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: 3rem;
|
||||
line-height: 1.2;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-primary {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.text-dark {
|
||||
color: var(--dark-color);
|
||||
}
|
||||
|
||||
.text-success {
|
||||
color: var(--success-color);
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: var(--danger-color);
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Center All */
|
||||
.all-center {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
margin: auto;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card {
|
||||
padding: 1rem;
|
||||
border: #ccc 1px dotted;
|
||||
margin: 0.7rem 0;
|
||||
}
|
||||
|
||||
/* List */
|
||||
.list {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
|
||||
.list li {
|
||||
padding-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
/* Padding */
|
||||
.p {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
.p-1 {
|
||||
padding: 1rem;
|
||||
}
|
||||
.p-2 {
|
||||
padding: 2rem;
|
||||
}
|
||||
.p-3 {
|
||||
padding: 3rem;
|
||||
}
|
||||
.py {
|
||||
padding: 0.5rem 0;
|
||||
}
|
||||
.py-1 {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
.py-2 {
|
||||
padding: 2rem 0;
|
||||
}
|
||||
.py-3 {
|
||||
padding: 3rem 0;
|
||||
}
|
||||
|
||||
/* Margin */
|
||||
.m {
|
||||
margin: 0.5rem;
|
||||
}
|
||||
.m-1 {
|
||||
margin: 1rem;
|
||||
}
|
||||
.m-2 {
|
||||
margin: 2rem;
|
||||
}
|
||||
.m-3 {
|
||||
margin: 3rem;
|
||||
}
|
||||
.my {
|
||||
margin: 0.5rem 0;
|
||||
}
|
||||
.my-1 {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.my-2 {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
.my-3 {
|
||||
margin: 3rem 0;
|
||||
}
|
||||
|
||||
/* Grid */
|
||||
.grid-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
.grid-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
.grid-4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-gap: 1rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-block;
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
padding: 0.4rem 1.3rem;
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
margin-right: 0.5rem;
|
||||
transition: opacity 0.2s ease-in;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
background: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.btn-block {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
font-size: 0.8rem;
|
||||
padding: 0.3rem 1rem;
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
font-size: 0.6rem;
|
||||
padding: 0.1rem 0.4rem;
|
||||
text-align: center;
|
||||
margin: 0.3rem;
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 0.7rem;
|
||||
margin: 1rem 0;
|
||||
opacity: 0.9;
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn-primary,
|
||||
.bg-primary,
|
||||
.badge-primary,
|
||||
.alert-primary {
|
||||
background: var(--primary-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
||||
.btn-light,
|
||||
.bg-light,
|
||||
.badge-light,
|
||||
.alert-light {
|
||||
background: var(--light-color);
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn-dark,
|
||||
.bg-dark,
|
||||
.badge-dark,
|
||||
.alert-dark {
|
||||
background: var(--dark-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-danger,
|
||||
.bg-danger,
|
||||
.badge-danger,
|
||||
.alert-danger {
|
||||
background: var(--danger-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-success,
|
||||
.bg-success,
|
||||
.badge-success,
|
||||
.alert-success {
|
||||
background: var(--success-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.btn-white,
|
||||
.bg-white,
|
||||
.badge-white,
|
||||
.alert-white {
|
||||
background: #fff;
|
||||
color: #333;
|
||||
border: #ccc solid 1px;
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
opacity: 0.60;
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
.btn:enabled:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.bg-light,
|
||||
.badge-light {
|
||||
border: #ccc solid 1px;
|
||||
}
|
||||
|
||||
.round-img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
input {
|
||||
margin: 1.2rem 0;
|
||||
}
|
||||
|
||||
.form-text {
|
||||
display: block;
|
||||
margin-top: 0.3rem;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
input[type='text'],
|
||||
input[type='email'],
|
||||
input[type='password'],
|
||||
input[type='date'],
|
||||
select,
|
||||
textarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0.4rem;
|
||||
/*font-size: 1.2rem;*/
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
input[type='submit'],
|
||||
button {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
table th,
|
||||
table td {
|
||||
padding: 1rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table th {
|
||||
background: var(--light-color);
|
||||
}
|
||||
|
||||
/* Navbar */
|
||||
.navbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.7rem 2rem;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.navbar ul {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.navbar a {
|
||||
color: #fff;
|
||||
padding: 0.45rem;
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
|
||||
.navbar a:hover {
|
||||
color: var(--light-color);
|
||||
}
|
||||
|
||||
.navbar .welcome span {
|
||||
margin-right: 0.6rem;
|
||||
}
|
||||
|
||||
/* Mobile Styles */
|
||||
@media (max-width: 700px) {
|
||||
.hide-sm {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.grid-2,
|
||||
.grid-3,
|
||||
.grid-4 {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
/* Text Styles */
|
||||
.x-large {
|
||||
font-size: 3rem;
|
||||
}
|
||||
|
||||
.large {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Navbar */
|
||||
.navbar {
|
||||
display: block;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.navbar ul {
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
:root {
|
||||
--primary-color: #64B5F6;
|
||||
--dark-color: #333333;
|
||||
--light-color: #f4f4f4;
|
||||
--danger-color: #dc3545;
|
||||
--success-color: #28a745;
|
||||
--medium-color: #999999;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cardV2 {
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 0 4px 0 rgba(0,0,0,.14), 0 3px 4px 0 rgba(0,0,0,.12), 0 1px 5px 0 rgba(0,0,0,.2);
|
||||
/*display: flex;
|
||||
flex-direction: column;*/
|
||||
min-width: 0;
|
||||
/*position: relative;
|
||||
word-wrap: break-word;*/
|
||||
}
|
||||
|
||||
table {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
margin-bottom: 1rem;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
tr {
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
tbody tr:nth-of-type(odd){
|
||||
background-color: rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
tbody td {
|
||||
border-top: 1px solid #e1e1e1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.modalWindow {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: rgba(0,0,0,0.2);
|
||||
z-index: 99999;
|
||||
opacity:0;
|
||||
pointer-events: none;
|
||||
text-align:center;
|
||||
}
|
||||
.modalWindow:target {
|
||||
opacity:1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.modalWindow > div {
|
||||
width: 500px;
|
||||
position: relative;
|
||||
margin: 10% auto;
|
||||
background: #fff;
|
||||
}
|
18
public/index.html
Normal file
18
public/index.html
Normal file
@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name='viewport' content='width=device-width,initial-scale=1'>
|
||||
|
||||
<title>Menuizer</title>
|
||||
|
||||
<link rel='icon' type='image/png' href='/favicon.png'>
|
||||
<link rel='stylesheet' href='/global.css'>
|
||||
<link rel='stylesheet' href='/build/bundle.css'>
|
||||
|
||||
<script defer src='/build/bundle.js'></script>
|
||||
</head>
|
||||
<!-- svelte -->
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
BIN
recipes.png
Normal file
BIN
recipes.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
76
rollup.config.js
Normal file
76
rollup.config.js
Normal file
@ -0,0 +1,76 @@
|
||||
import svelte from 'rollup-plugin-svelte';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import livereload from 'rollup-plugin-livereload';
|
||||
import replace from 'rollup-plugin-replace';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
|
||||
const production = !process.env.ROLLUP_WATCH;
|
||||
|
||||
export default {
|
||||
input: 'src/main.js',
|
||||
output: {
|
||||
sourcemap: true,
|
||||
format: 'iife',
|
||||
name: 'app',
|
||||
file: 'public/build/bundle.js'
|
||||
},
|
||||
plugins: [
|
||||
svelte({
|
||||
// enable run-time checks when not in production
|
||||
dev: !production,
|
||||
// we'll extract any component CSS out into
|
||||
// a separate file - better for performance
|
||||
css: css => {
|
||||
css.write('public/build/bundle.css');
|
||||
}
|
||||
}),
|
||||
|
||||
// If you have external dependencies installed from
|
||||
// npm, you'll most likely need these plugins. In
|
||||
// some cases you'll need additional configuration -
|
||||
// consult the documentation for details:
|
||||
// https://github.com/rollup/plugins/tree/master/packages/commonjs
|
||||
resolve({
|
||||
browser: true,
|
||||
dedupe: ['svelte']
|
||||
}),
|
||||
commonjs(),
|
||||
replace({
|
||||
exclude: 'node_modules/**',
|
||||
ENV: JSON.stringify(production ? 'production' : 'development'),
|
||||
}),
|
||||
|
||||
// In dev mode, call `npm run start` once
|
||||
// the bundle has been generated
|
||||
!production && serve(),
|
||||
|
||||
// Watch the `public` directory and refresh the
|
||||
// browser on changes when not in production
|
||||
!production && livereload('public'),
|
||||
|
||||
// If we're building for production (npm run build
|
||||
// instead of npm run dev), minify
|
||||
production && terser()
|
||||
],
|
||||
watch: {
|
||||
clearScreen: false
|
||||
}
|
||||
};
|
||||
|
||||
function serve() {
|
||||
let started = false;
|
||||
|
||||
return {
|
||||
writeBundle() {
|
||||
if (!started) {
|
||||
started = true;
|
||||
|
||||
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
|
||||
stdio: ['ignore', 'inherit', 'inherit'],
|
||||
shell: true
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
21
src/App.svelte
Normal file
21
src/App.svelte
Normal file
@ -0,0 +1,21 @@
|
||||
<script>
|
||||
import Header from './components/Header.svelte';
|
||||
import Editor from './components/Editor.svelte';
|
||||
import FilterBar from './components/FilterBar.svelte';
|
||||
import Recipes from './components/Recipes.svelte';
|
||||
import Debug from './components/Debug.svelte';
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
<main>
|
||||
<Header/>
|
||||
<Editor/>
|
||||
<FilterBar/>
|
||||
<Recipes/>
|
||||
</main>
|
20
src/components/Debug.svelte
Normal file
20
src/components/Debug.svelte
Normal file
@ -0,0 +1,20 @@
|
||||
<script>
|
||||
import {state} from '../store/store';
|
||||
|
||||
state.recipes.subscribe(async (v) => {
|
||||
console.log('>> recipes', v);
|
||||
});
|
||||
|
||||
state.currentItem.subscribe(async (v) => {
|
||||
console.log('>> currentItem', v);
|
||||
});
|
||||
|
||||
state.filter.subscribe(async (v) => {
|
||||
console.log('>> filter', v);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
157
src/components/Editor.svelte
Normal file
157
src/components/Editor.svelte
Normal file
@ -0,0 +1,157 @@
|
||||
<script>
|
||||
import { state } from '../store/store';
|
||||
import debounce from 'debounce';
|
||||
|
||||
let _editMode;
|
||||
let _currentItem;
|
||||
let meat;
|
||||
let mealtype;
|
||||
|
||||
let deleteEnabled = false;
|
||||
|
||||
$: {
|
||||
meat = _currentItem.meat.toString();
|
||||
mealtype = _currentItem.mealtype.toString();
|
||||
}
|
||||
|
||||
$: deleteEnabled = (_currentItem.hash === '')
|
||||
|
||||
state.editMode.subscribe(async (v) => {
|
||||
_editMode = v;
|
||||
});
|
||||
|
||||
state.currentItem.subscribe(async (v) => {
|
||||
_currentItem = v;
|
||||
});
|
||||
|
||||
function deleteItem() {
|
||||
console.log('>> DELETE');
|
||||
}
|
||||
|
||||
function closeEditor() {
|
||||
state.closeEditor();
|
||||
}
|
||||
|
||||
async function saveRecipe() {
|
||||
await state.saveRecipe(_currentItem);
|
||||
}
|
||||
|
||||
function pasteHandler(v) {
|
||||
debouncedPasteProcessor(v);
|
||||
}
|
||||
|
||||
function pasteProcessor(item) {
|
||||
const meats = [
|
||||
'x',
|
||||
'chicken',
|
||||
'beef',
|
||||
'pork',
|
||||
'fish',
|
||||
'egg',
|
||||
'vegetable'
|
||||
];
|
||||
|
||||
const newFragment = {};
|
||||
const titleRegEx = /(?:#\s)(.*)(?:\n)/;
|
||||
const linkRegEx = /(?:\[.*]\()(.*)(?:\))/;
|
||||
const foodRegEx = /([vV]egetable|[pP]ork|[cC]hicken|[bB]eef|[fF]ish|[eE]gg)/g;
|
||||
const mealTypeRegEx = /([sS]oup)/g;
|
||||
const foodCount = {};
|
||||
let winnerVal = 0;
|
||||
let winnerId = 0;
|
||||
|
||||
const newTitle = titleRegEx.exec(item.target.value);
|
||||
const newLink = linkRegEx.exec(item.target.value);
|
||||
|
||||
if (newTitle !== null) newFragment.name = newTitle[1];
|
||||
|
||||
if (newLink !== null) newFragment.url = newLink[1];
|
||||
|
||||
const matchedFoods = [...item.target.value.matchAll(foodRegEx)];
|
||||
const mealTypes = [...item.target.value.matchAll(mealTypeRegEx)];
|
||||
|
||||
if (matchedFoods.length > 0) {
|
||||
const deboxed = matchedFoods.map(fooditem => {
|
||||
return fooditem[0].toLowerCase();
|
||||
});
|
||||
|
||||
deboxed.forEach(el => {
|
||||
foodCount[el] = foodCount[el] + 1 || 1;
|
||||
});
|
||||
|
||||
for (const key in foodCount)
|
||||
if (foodCount[key] > winnerVal) {
|
||||
winnerVal = foodCount[key];
|
||||
winnerId = meats.indexOf(key);
|
||||
}
|
||||
|
||||
newFragment.meat = winnerId;
|
||||
}
|
||||
|
||||
if (mealTypes.length > 0)
|
||||
newFragment.mealtype = 2;
|
||||
else
|
||||
newFragment.mealtype = 1;
|
||||
|
||||
_currentItem = {..._currentItem, ...newFragment};
|
||||
}
|
||||
|
||||
const debouncedPasteProcessor = debounce(pasteProcessor, 250);
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
{#if _editMode}
|
||||
<div class="container">
|
||||
<form autocomplete="off">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" name="name" id="name" bind:value={_currentItem.name} required/>
|
||||
|
||||
<label for="url">Url:</label>
|
||||
<input type="text" name="url" id="url" bind:value={_currentItem.url} required/>
|
||||
|
||||
<label for="md">Markdown:</label>
|
||||
<textarea id="md" name="md" cols="50" rows="10" bind:value={_currentItem.md} on:paste={pasteHandler}></textarea>
|
||||
|
||||
<label for="meat">Meat</label>
|
||||
<select id="meat" name="meat" bind:value={meat} required>
|
||||
<option></option>
|
||||
<option value="1">Chicken</option>
|
||||
<option value="2">Beef</option>
|
||||
<option value="3">Pork</option>
|
||||
<option value="4">Fish</option>
|
||||
<option value="5">Egg</option>
|
||||
<option value="6">Vegetable</option>
|
||||
</select>
|
||||
|
||||
<label for="mealtype">Meal type</label>
|
||||
<select id="mealtype" name="mealtype" bind:value={mealtype} required>
|
||||
<option></option>
|
||||
<option value="1">Main</option>
|
||||
<option value="2">Soup</option>
|
||||
<option value="128">Note</option>
|
||||
</select>
|
||||
|
||||
<input id="_id" name="id" type="hidden" bind:value={_currentItem._id} disabled/>
|
||||
<input type="hidden" id="short" name="short" bind:value={_currentItem.short} disabled/>
|
||||
<input type="hidden" id="hash" name="hash" bind:value={_currentItem.hash} disabled/>
|
||||
<input type="hidden" id="lastused" name="lastused" bind:value={_currentItem.lastused} disabled/>
|
||||
|
||||
<div class="my text-right">
|
||||
<button class="btn btn-danger btn-sm" id="delete" type="button" disabled={deleteEnabled} on:click={deleteItem}>
|
||||
Delete
|
||||
</button>
|
||||
<button class="btn btn-sm" type="button" on:click={closeEditor}>
|
||||
Close
|
||||
</button>
|
||||
<button class="btn btn-primary btn-sm" id="save" type="button" on:click={saveRecipe}>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{/if}
|
45
src/components/FilterBar.svelte
Normal file
45
src/components/FilterBar.svelte
Normal file
@ -0,0 +1,45 @@
|
||||
<script>
|
||||
import { state } from '../store/store';
|
||||
|
||||
function updateMeat(event) {
|
||||
const newVal = event.target.value;
|
||||
state.updateMeatFilter(newVal);
|
||||
}
|
||||
|
||||
function updateMeal(event) {
|
||||
const newVal = event.target.value;
|
||||
state.updateMealFilter(newVal);
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.filterBar {
|
||||
background: var(--medium-color);
|
||||
margin-bottom: 1rem;
|
||||
padding: 10px 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<div class="filterBar grid-4">
|
||||
<select on:change={updateMeat}>
|
||||
<option value="0">All</option>
|
||||
<option value="1">Chicken</option>
|
||||
<option value="2">Beef</option>
|
||||
<option value="3">Pork</option>
|
||||
<option value="4">Fish</option>
|
||||
<option value="5">Egg</option>
|
||||
<option value="6">Vegetable</option>
|
||||
</select>
|
||||
|
||||
<select on:change={updateMeal}>
|
||||
<option value="0">All</option>
|
||||
<option value="1">Mains</option>
|
||||
<option value="2">Soups</option>
|
||||
<option value="128">Notes</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
23
src/components/Header.svelte
Normal file
23
src/components/Header.svelte
Normal file
@ -0,0 +1,23 @@
|
||||
<script>
|
||||
import { state } from '../store/store';
|
||||
|
||||
function handleNewRecipe() {
|
||||
console.log('newRecipe');
|
||||
state.newRecipe();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
<header class="navbar bg-primary">
|
||||
<h2>
|
||||
Recipes
|
||||
</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<button class="btn btn-sm" on:click={handleNewRecipe} type="button">New Recipe</button>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
89
src/components/RecipeItem.svelte
Normal file
89
src/components/RecipeItem.svelte
Normal file
@ -0,0 +1,89 @@
|
||||
<script>
|
||||
import { state } from '../store/store';
|
||||
|
||||
export let recipeItem = {};
|
||||
|
||||
let meatClass;
|
||||
let meatText;
|
||||
let url;
|
||||
const meats = ['x', 'Chicken', 'Beef', 'Pork', 'Fish', 'Egg', 'Vegetable'];
|
||||
|
||||
$:{
|
||||
meatText = meats[recipeItem.meat];
|
||||
meatClass = (recipeItem.meat === '') ? '' : meats[recipeItem.meat].toLowerCase();
|
||||
url = `/view/${recipeItem.short}`;
|
||||
}
|
||||
|
||||
function editRecipe(hash) {
|
||||
state.editRecipe(hash);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.recipeItem {
|
||||
display: flex;
|
||||
padding: 0.1rem;
|
||||
border-bottom: 1px #ccc dotted;
|
||||
}
|
||||
|
||||
.recipeItem:nth-of-type(odd) {
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.listItemSix {
|
||||
|
||||
flex: 6;
|
||||
}
|
||||
|
||||
.listItemThree {
|
||||
|
||||
flex: 3;
|
||||
}
|
||||
|
||||
.chicken {
|
||||
background: #8e5241;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.beef {
|
||||
background: #d72414;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.pork {
|
||||
background: #ef96d9;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.fish {
|
||||
background: #005ba0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.egg {
|
||||
background: #fbc003;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.vegetable {
|
||||
background: #00903e;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="recipeItem">
|
||||
<div class="listItemSix"><a href={url}>{recipeItem.name}</a></div>
|
||||
<div class="listItemThree">
|
||||
{#if recipeItem.mealtype ===2}
|
||||
<span class="badge badge-light">Soup</span>
|
||||
{:else if recipeItem.mealtype===128}
|
||||
<span class="badge badge-dark">Note</span>
|
||||
|
||||
{/if}
|
||||
<span class="badge {meatClass}">{meatText}</span>
|
||||
</div>
|
||||
<div class="listItemThree all-center">
|
||||
<button class="btn btn-primary btn-sm" type="button" on:click={editRecipe(recipeItem.hash)}>Edit</button>
|
||||
</div>
|
||||
</div>
|
61
src/components/Recipes.svelte
Normal file
61
src/components/Recipes.svelte
Normal file
@ -0,0 +1,61 @@
|
||||
<script>
|
||||
|
||||
import { state } from '../store/store';
|
||||
import { onMount } from 'svelte';
|
||||
import RecipeItem from './RecipeItem.svelte';
|
||||
|
||||
let _storedRecipes = [];
|
||||
let _recipes = [];
|
||||
|
||||
let _filter = {
|
||||
'meat': '0',
|
||||
'meal': '0'
|
||||
};
|
||||
|
||||
state.recipes.subscribe(async (v) => {
|
||||
_storedRecipes = v;
|
||||
_recipes = doFilter(_storedRecipes);
|
||||
});
|
||||
|
||||
state.filter.subscribe(async (v) => {
|
||||
_filter = v;
|
||||
_recipes = doFilter(_storedRecipes);
|
||||
});
|
||||
|
||||
onMount(async () => {
|
||||
await state.fetchRecipes();
|
||||
});
|
||||
|
||||
function doFilter(v) {
|
||||
const meatFilterMode = parseInt(_filter.meat, 10);
|
||||
const mealFilterMode = parseInt(_filter.meal, 10);
|
||||
const mealsFilter = v.filter(item => mealFilterMode === 0 || item.mealtype === mealFilterMode);
|
||||
const meatsFilter = mealsFilter.filter(item => meatFilterMode === 0 || item.meat === meatFilterMode);
|
||||
|
||||
return meatsFilter.sort((a, b) => {
|
||||
var shortA = a.short; // ignore upper and lowercase
|
||||
var shortB = b.short; // ignore upper and lowercase
|
||||
if (shortA < shortB) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (shortA > shortB) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// names must be equal
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
<div class="container ">
|
||||
{#each _recipes as item}
|
||||
<RecipeItem recipeItem={item}/>
|
||||
{/each}
|
||||
</div>
|
10
src/main.js
Normal file
10
src/main.js
Normal file
@ -0,0 +1,10 @@
|
||||
import App from './App.svelte';
|
||||
|
||||
const app = new App({
|
||||
target: document.body,
|
||||
props: {
|
||||
name: 'world'
|
||||
}
|
||||
});
|
||||
|
||||
export default app;
|
162
src/store/store.js
Normal file
162
src/store/store.js
Normal file
@ -0,0 +1,162 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import axios from 'axios';
|
||||
|
||||
const url = (ENV === 'production') ? 'https://menu.silvrtree.co.uk/recipes' : 'http://localhost:3000/recipes';
|
||||
|
||||
const oldstate = writable({
|
||||
'recipes': [],
|
||||
'currentItem': {
|
||||
'name': '',
|
||||
'url': '',
|
||||
'md': '',
|
||||
'meat': '',
|
||||
'mealtype': '',
|
||||
'_id': '',
|
||||
'short': '',
|
||||
'hash': '',
|
||||
'lastused': ''
|
||||
},
|
||||
'editMode': false,
|
||||
'meatFilterMode':0,
|
||||
'mealFilterMode':0
|
||||
|
||||
});
|
||||
|
||||
function Filter() {
|
||||
const { subscribe, set, update } = writable({
|
||||
'meat':'0',
|
||||
'meal':'0'
|
||||
});
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
'updateMeat': (newVal) => update(v => {
|
||||
return {
|
||||
...v, ...{ 'meat':newVal }
|
||||
};
|
||||
}),
|
||||
'updateMeal': (newVal) => update(v => {
|
||||
return {
|
||||
...v, ...{ 'meal':newVal }
|
||||
};
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
function Recipes() {
|
||||
const { subscribe, set, update } = writable([]);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
set,
|
||||
update
|
||||
};
|
||||
}
|
||||
|
||||
function EditMode() {
|
||||
const { subscribe, set, update } = writable(false);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
'newRecipe': () => update(v => true),
|
||||
'closeEditor': () => update( v => false)
|
||||
};
|
||||
}
|
||||
|
||||
function CurrentItem() {
|
||||
const { subscribe, set, update } = writable({
|
||||
'name': '',
|
||||
'url': '',
|
||||
'md': '',
|
||||
'meat': '',
|
||||
'mealtype': '',
|
||||
'_id': '',
|
||||
'short': '',
|
||||
'hash': '',
|
||||
'lastused': ''
|
||||
});
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
'clearItem': () => update(v => {
|
||||
return {
|
||||
'name': '',
|
||||
'url': '',
|
||||
'md': '',
|
||||
'meat': '',
|
||||
'mealtype': '',
|
||||
'_id': '',
|
||||
'short': '',
|
||||
'hash': '',
|
||||
'lastused': ''
|
||||
};
|
||||
}),
|
||||
'updateItem': (payload) => update(v => {
|
||||
return payload;
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
const state = {
|
||||
'editMode': EditMode(),
|
||||
'currentItem': CurrentItem(),
|
||||
'recipes': Recipes(),
|
||||
'filter': Filter(),
|
||||
|
||||
newRecipe() {
|
||||
console.log('>> Action:newRecipe');
|
||||
this.editMode.newRecipe();
|
||||
this.currentItem.clearItem();
|
||||
},
|
||||
async editRecipe(hash) {
|
||||
const response = await axios.get(`${url}/${hash}`).catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
this.currentItem.updateItem(response.data);
|
||||
this.editMode.newRecipe();
|
||||
},
|
||||
async saveRecipe(payload) {
|
||||
console.log('>> Action:saveRecipe');
|
||||
const data = { ...payload };
|
||||
|
||||
let response;
|
||||
|
||||
if (data.hash === '') {
|
||||
console.log('Create new');
|
||||
response = await axios.post(`${url}`, data).catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
console.log('Update existing');
|
||||
response = await axios.put(`${url}/${data.hash}`, data).catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
}
|
||||
|
||||
if (response.data.changes > 0 || response.data.msg === 'Row inserted') {
|
||||
this.closeEditor();
|
||||
this.fetchRecipes();
|
||||
}
|
||||
},
|
||||
async fetchRecipes() {
|
||||
const response = await axios.get(url);
|
||||
this.recipes.set(response.data);
|
||||
},
|
||||
closeEditor() {
|
||||
this.editMode.closeEditor();
|
||||
this.currentItem.clearItem();
|
||||
},
|
||||
updateMeatFilter(newVal) {
|
||||
this.filter.updateMeat(newVal);
|
||||
},
|
||||
updateMealFilter(newVal) {
|
||||
this.filter.updateMeal(newVal);
|
||||
}
|
||||
};
|
||||
|
||||
// export { currentItem, editMode, actions, state };
|
||||
|
||||
export { state };
|
||||
|
Loading…
Reference in New Issue
Block a user