commit 53f09941af9fd33023a0c2caf257fac11a9b18b1 Author: Knut Ahlers Date: Sat Apr 28 00:38:23 2018 +0200 Initial version of frontend diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..3d6b9be --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,198 @@ +{ + "parserOptions": { + "ecmaVersion": 8, + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + }, + "sourceType": "module" + }, + + "env": { + "es6": true, + "node": false + }, + + "plugins": [ + "import", + "node", + "promise", + "standard" + ], + + "globals": { + "document": false, + "navigator": false, + "window": false + }, + + "rules": { + "accessor-pairs": "error", + "arrow-spacing": ["error", { "before": true, "after": true }], + "block-spacing": ["error", "always"], + "brace-style": ["error", "1tbs", { "allowSingleLine": true }], + "camelcase": ["error", { "properties": "never" }], + "comma-dangle": ["error", "always-multiline"], + "comma-spacing": ["error", { "before": false, "after": true }], + "comma-style": ["error", "last"], + "constructor-super": "error", + "curly": ["error", "multi-line"], + "dot-location": ["error", "property"], + "eol-last": "error", + "eqeqeq": ["error", "always", { "null": "ignore" }], + "func-call-spacing": ["error", "never"], + "generator-star-spacing": ["error", { "before": true, "after": true }], + "handle-callback-err": ["error", "^(err|error)$" ], + "indent": ["error", 2, { + "SwitchCase": 1, + "VariableDeclarator": 1, + "outerIIFEBody": 1, + "MemberExpression": 1, + "FunctionDeclaration": { "parameters": 1, "body": 1 }, + "FunctionExpression": { "parameters": 1, "body": 1 }, + "CallExpression": { "arguments": 1 }, + "ArrayExpression": 1, + "ObjectExpression": 1, + "ImportDeclaration": 1, + "flatTernaryExpressions": false, + "ignoreComments": false + }], + "key-spacing": ["error", { "beforeColon": false, "afterColon": true }], + "keyword-spacing": ["error", { "before": true, "after": true }], + "new-cap": ["error", { "newIsCap": true, "capIsNew": false }], + "new-parens": "error", + "no-array-constructor": "error", + "no-caller": "error", + "no-class-assign": "error", + "no-compare-neg-zero": "error", + "no-cond-assign": "error", + "no-const-assign": "error", + "no-constant-condition": ["error", { "checkLoops": false }], + "no-control-regex": "error", + "no-debugger": "error", + "no-delete-var": "error", + "no-dupe-args": "error", + "no-dupe-class-members": "error", + "no-dupe-keys": "error", + "no-duplicate-case": "error", + "no-empty-character-class": "error", + "no-empty-pattern": "error", + "no-eval": "error", + "no-ex-assign": "error", + "no-extend-native": "error", + "no-extra-bind": "error", + "no-extra-boolean-cast": "error", + "no-extra-parens": ["error", "functions"], + "no-fallthrough": "error", + "no-floating-decimal": "error", + "no-func-assign": "error", + "no-global-assign": "error", + "no-implied-eval": "error", + "no-inner-declarations": ["error", "functions"], + "no-invalid-regexp": "error", + "no-irregular-whitespace": "error", + "no-iterator": "error", + "no-label-var": "error", + "no-labels": ["error", { "allowLoop": false, "allowSwitch": false }], + "no-lone-blocks": "error", + "no-mixed-operators": ["error", { + "groups": [ + ["==", "!=", "===", "!==", ">", ">=", "<", "<="], + ["&&", "||"], + ["in", "instanceof"] + ], + "allowSamePrecedence": true + }], + "no-mixed-spaces-and-tabs": "error", + "no-multi-spaces": "error", + "no-multi-str": "error", + "no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 0 }], + "no-negated-in-lhs": "error", + "no-new": "error", + "no-new-func": "error", + "no-new-object": "error", + "no-new-require": "error", + "no-new-symbol": "error", + "no-new-wrappers": "error", + "no-obj-calls": "error", + "no-octal": "error", + "no-octal-escape": "error", + "no-path-concat": "error", + "no-proto": "error", + "no-redeclare": "error", + "no-regex-spaces": "error", + "no-return-assign": ["error", "except-parens"], + "no-return-await": "error", + "no-self-assign": "error", + "no-self-compare": "error", + "no-sequences": "error", + "no-shadow-restricted-names": "error", + "no-sparse-arrays": "error", + "no-tabs": "error", + "no-template-curly-in-string": "error", + "no-this-before-super": "error", + "no-throw-literal": "error", + "no-trailing-spaces": "error", + "no-undef": "error", + "no-undef-init": "error", + "no-unexpected-multiline": "error", + "no-unmodified-loop-condition": "error", + "no-unneeded-ternary": ["error", { "defaultAssignment": false }], + "no-unreachable": "error", + "no-unsafe-finally": "error", + "no-unsafe-negation": "error", + "no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true, "allowTaggedTemplates": true }], + "no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": true }], + "no-use-before-define": ["error", { "functions": false, "classes": false, "variables": false }], + "no-useless-call": "error", + "no-useless-computed-key": "error", + "no-useless-constructor": "error", + "no-useless-escape": "error", + "no-useless-rename": "error", + "no-useless-return": "error", + "no-whitespace-before-property": "error", + "no-with": "error", + "object-property-newline": ["error", { "allowMultiplePropertiesPerLine": true }], + "one-var": ["error", { "initialized": "never" }], + "operator-linebreak": ["error", "after", { "overrides": { "?": "before", ":": "before" } }], + "padded-blocks": ["error", { "blocks": "never", "switches": "never", "classes": "never" }], + "prefer-promise-reject-errors": "error", + "quotes": ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": true }], + "rest-spread-spacing": ["error", "never"], + "semi": ["error", "always"], + "semi-spacing": ["error", { "before": false, "after": true }], + "space-before-blocks": ["error", "always"], + "space-before-function-paren": ["error", "never"], + "space-in-parens": ["error", "never"], + "space-infix-ops": "error", + "space-unary-ops": ["error", { "words": true, "nonwords": false }], + "spaced-comment": ["error", "always", { + "line": { "markers": ["*package", "!", "/", ",", "="] }, + "block": { "balanced": true, "markers": ["*package", "!", ",", ":", "::", "flow-include"], "exceptions": ["*"] } + }], + "symbol-description": "error", + "template-curly-spacing": ["error", "never"], + "template-tag-spacing": ["error", "never"], + "unicode-bom": ["error", "never"], + "use-isnan": "error", + "valid-typeof": ["error", { "requireStringLiterals": true }], + "wrap-iife": ["error", "any", { "functionPrototypeMethods": true }], + "yield-star-spacing": ["error", "both"], + "yoda": ["error", "never"], + + "import/export": "error", + "import/first": "error", + "import/no-duplicates": "error", + "import/no-webpack-loader-syntax": "error", + + "node/no-deprecated-api": "error", + "node/process-exit-as-throw": "error", + + "promise/param-names": "error", + + "standard/array-bracket-even-spacing": ["error", "either"], + "standard/computed-property-even-spacing": ["error", "even"], + "standard/no-callback-literal": "error", + "standard/object-curly-even-spacing": ["error", "either"] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f731824 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +frontend/albums.json diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c231d01 --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +default: + +lint: + docker run --rm -ti -v $(CURDIR):$(CURDIR) -w $(CURDIR) luzifer/eslint frontend/*.js + +pack: + go-bindata -modtime 1 frontend/... + +publish: + curl -sSLo golang.sh https://raw.githubusercontent.com/Luzifer/github-publish/master/golang.sh + bash golang.sh diff --git a/bindata.go b/bindata.go new file mode 100644 index 0000000..81e2d7b --- /dev/null +++ b/bindata.go @@ -0,0 +1,452 @@ +// Code generated by go-bindata. DO NOT EDIT. +// sources: +// frontend/albums.json +// frontend/app.js +// frontend/index.html + +package main + + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + + +type asset struct { + bytes []byte + info fileInfoEx +} + +type fileInfoEx interface { + os.FileInfo + MD5Checksum() string +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time + md5checksum string +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) MD5Checksum() string { + return fi.md5checksum +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _bindataFrontendAlbumsjson = []byte( + "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xbc\x94\xc1\x4e\x03\x21\x10\x86\xef\x3c\xc5\x64\xce\xab\x0c\xb4\xeb\xae" + + "\x9b\x18\xe3\x0b\x78\xf2\x66\x7a\xa0\x15\x5b\x12\xa8\x8d\x0b\x1e\x6c\xf6\xdd\x8d\xd8\x60\x43\xb2\x5e\xb0\x1c\x20" + + "\x24\x33\xf3\xe5\xe3\x3f\xcc\x91\x01\xa0\xb2\xeb\xe0\x46\x1c\xe0\x99\x01\x00\x1c\xe3\x0d\x80\xe6\x05\x07\x90\x24" + + "\x7a\x5a\xca\x9e\x88\x44\xbb\x68\x52\xcd\xa9\xad\xfe\x9d\x39\x9f\x8b\xf5\xd7\x60\xed\x68\x3e\x35\x0e\x80\x3b\xef" + + "\x0f\xe3\xc0\xf9\xc1\xaa\x8d\x36\x6e\x7b\xbd\x79\x73\x5c\xc8\x9e\x78\x27\x89\xef\x95\x0f\xef\xfa\xfe\xe3\x4e\x60" + + "\x73\x4e\xf0\xbb\xe0\xd6\x7b\x65\xec\x2c\xa2\x25\x8a\x67\x96\x60\xbc\x8d\x02\x8f\xb1\x01\x53\x6d\x3a\xbd\x56\xe9" + + "\x3b\xa9\xf5\x49\x8f\xfe\xea\xe1\x3b\x10\x10\x3f\x03\x53\xf3\x77\x2a\x9d\xbc\xbd\x64\x2a\xb2\x38\x95\x9c\x30\x9b" + + "\x4a\xf3\x6f\xd2\x8b\x62\xe9\x9c\x50\x41\x7a\x59\x2c\x9d\x13\x2a\x48\xb7\xc5\xd2\x39\xa1\x82\xf4\x4d\xb1\x74\x4e" + + "\xa8\x20\xdd\x15\x4b\xe7\x84\xb2\xf5\x24\x4f\xeb\x89\x01\xac\xd8\xc4\xbe\x02\x00\x00\xff\xff\x58\x74\x83\x74\xca" + + "\x05\x00\x00") + +func bindataFrontendAlbumsjsonBytes() ([]byte, error) { + return bindataRead( + _bindataFrontendAlbumsjson, + "frontend/albums.json", + ) +} + + + +func bindataFrontendAlbumsjson() (*asset, error) { + bytes, err := bindataFrontendAlbumsjsonBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{ + name: "frontend/albums.json", + size: 1482, + md5checksum: "", + mode: os.FileMode(436), + modTime: time.Unix(1, 0), + } + + a := &asset{bytes: bytes, info: info} + + return a, nil +} + +var _bindataFrontendAppjs = []byte( + "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x54\xc1\x6e\xc3\x36\x0c\xbd\xe7\x2b\x08\x34\x80\xe4\xc2\x71\xd6\x9e" + + "\x06\x17\x29\xb0\xae\x41\xda\x53\x0f\x2b\xb0\xe3\xa0\x58\xb4\xad\x42\x96\x0c\x89\x4e\xda\x15\xf9\xf7\xc1\xb2\xe4" + + "\x24\x5b\xb1\x2b\xf9\xf4\xf8\xf4\xf8\xa4\xf5\x2d\x34\xda\xee\x85\x86\x65\x59\x0b\xed\x11\x5e\x84\x91\x1a\xf7\xc2" + + "\xf9\x58\xb8\x5d\x2f\x16\x95\x16\xde\xc3\x4e\x68\x8d\xee\x0b\xbe\x17\x00\x95\x35\x9e\xdc\x50\x91\x75\x3c\x0b\x15" + + "\xb8\x38\x5a\x38\x6c\x94\x27\x74\x2f\xa8\x7b\x74\x9c\xa9\x7a\x47\x2c\x07\x6a\x95\x2f\xda\x19\xf6\xa4\x9a\x06\xdd" + + "\x7b\x2b\x4c\xf6\x10\x18\x42\x1f\x9d\xb3\xee\x2f\xea\x35\x6c\x2e\x29\x2b\xdb\xf5\x4a\x23\x5f\x72\x76\x13\x20\x2b" + + "\xc2\xae\xd7\x82\x90\x65\x45\x4b\x9d\xe6\xd9\x25\x8b\xd0\xfb\xa1\xfb\x7f\x96\x00\xf9\x91\xe5\x4c\x63\x7b\x52\xd6" + + "\x78\x24\xd8\xc4\x5b\x02\xac\xd7\xb0\x43\x83\x4e\x68\x88\xed\xd8\x90\xf6\x68\xb4\x15\xb2\x84\x60\x5d\x1e\xcb\x1e" + + "\x35\x8e\x46\x95\xc0\x54\xd7\xb0\xfc\x4c\xf3\xde\x0e\xdd\xde\x08\xa5\x13\x03\xa5\x42\x09\xe4\x86\x99\x21\x94\xff" + + "\x54\x92\xda\x12\x7e\xfd\x25\x55\xf1\x33\x9c\x7f\xed\x44\x83\x25\x30\xef\xaa\x99\xdb\xb7\xf6\x18\x9a\x4f\x5f\xcf" + + "\x58\x8b\x41\xd3\x95\xa6\xd3\x68\xd4\x69\xbc\xa6\x54\xbe\xd7\xe2\x6b\x3b\x1a\xca\x3b\xf4\x5e\x34\x08\x1b\x60\x2c" + + "\x2d\x75\xc9\x59\x51\x59\x43\x42\x19\x74\xab\x5a\x0f\x4a\xb2\xac\x10\x7d\x8f\x46\xf2\xeb\x7d\xf1\x64\x50\xe4\x89" + + "\xb3\xa6\xb5\x84\x69\x3f\xad\x9e\x1f\xee\x72\x38\xdc\xe7\xc9\xcb\x34\x58\xd5\xc0\x0f\x77\xf0\x08\x87\xfb\x6c\xb6" + + "\xde\x21\x0d\xce\x24\x68\x51\x9b\x20\x21\xee\xfd\xb4\xf8\x01\xa2\xcc\x01\x9d\xc7\x33\x2e\x08\x51\x46\x91\x12\x5a" + + "\xfd\x8d\x7c\x70\x6a\xbe\x6b\x21\x3e\xc4\xe7\x58\xc9\xe7\x89\xe1\x76\x25\xf0\x0c\x36\x8f\x53\x24\xae\x2c\x63\xbf" + + "\xdb\x41\x4b\x30\x96\xa0\x46\xaa\x5a\x08\xa1\xf2\x05\xcb\xf2\xd9\x0c\x6a\xad\x2c\x81\xed\xb6\xef\xe7\xfd\x0c\x55" + + "\x85\xde\x97\xc0\xa5\x20\x71\xe6\xee\x9d\x1d\xeb\xbf\x05\x92\xa9\x97\x5c\x9c\xb5\x5f\x63\xc2\xbc\xe7\x40\x32\x49" + + "\xd6\x48\x51\x04\x6c\x60\xee\x4e\xef\xc1\x4f\x46\x45\x8d\xde\x3a\xe2\x5c\xe4\xb0\x0f\x02\xf6\x85\x92\xb0\x02\x51" + + "\x28\x99\x9e\x40\x04\xd6\xd6\x6d\x45\xd5\xf2\x69\x58\x00\x27\x7b\xe6\x69\x5b\x8d\x1d\x9a\xf1\x99\x2c\xf9\xf5\x03" + + "\x8c\xa7\xe2\x92\x42\xa2\x6e\x9a\xe9\x2b\x59\x1d\x9d\xe8\xcf\x71\xba\x24\x9a\xe1\x97\xc5\x42\xab\xa6\xa5\xf8\x0f" + + "\x4d\x63\x86\x5e\x0a\x42\xf9\x16\xd6\xfd\x07\xd2\x1c\x42\x80\x38\xe4\x55\x96\x13\x49\xa1\x64\xf2\xff\x94\xe4\x5c" + + "\xf8\xfa\x1f\x26\xdb\xd3\xe8\xe1\xf7\x29\x59\x1b\xa3\xf5\xb6\xff\xc0\x8a\x0a\xe1\xbd\x6a\x0c\xff\x3e\xe5\xff\xfa" + + "\x2a\x42\x94\x53\xd8\x4e\x8b\xc5\x92\xf3\xd9\xb3\xd1\xaf\xa8\x0b\x36\x60\xf0\x98\x7e\x55\x1e\xf0\xb1\x55\x5c\xe4" + + "\x93\xc5\x25\x7c\x78\x6b\x58\xf6\xb0\x18\x15\xff\x13\x00\x00\xff\xff\xc1\x5d\x6e\x02\xb7\x05\x00\x00") + +func bindataFrontendAppjsBytes() ([]byte, error) { + return bindataRead( + _bindataFrontendAppjs, + "frontend/app.js", + ) +} + + + +func bindataFrontendAppjs() (*asset, error) { + bytes, err := bindataFrontendAppjsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{ + name: "frontend/app.js", + size: 1463, + md5checksum: "", + mode: os.FileMode(436), + modTime: time.Unix(1, 0), + } + + a := &asset{bytes: bytes, info: info} + + return a, nil +} + +var _bindataFrontendIndexhtml = []byte( + "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xb4\x58\xfb\x73\xda\xb8\x13\xff\xbd\x7f\x85\xce\x9d\xef\x4c\x3a\xa9\x6c" + + "\xcc\x2b\x40\x21\x73\x84\x34\x25\x0f\xf2\x20\x49\x9b\xf4\x37\xd9\x96\x6d\x81\x2c\x39\x92\xcc\x23\x4c\xfe\xf7\xef" + + "\xc8\xd8\x60\x48\xb8\xe6\xee\x7a\x74\x0a\xb6\xb4\xaf\xcf\xee\x4a\xbb\x9b\xf6\x1f\x1e\x77\xd5\x3c\xc6\x20\x54\x11" + + "\x3d\xfc\xd0\xd6\x3f\x80\x22\x16\x74\x0c\xcc\x8c\xc3\x0f\x00\xb4\x43\x8c\x3c\xfd\x00\x40\xfb\x0f\x08\xc1\x10\x3f" + + "\x25\x44\x60\x0f\x44\x58\x21\xa0\x50\x20\x01\x84\xd9\x7e\xba\xe4\x86\x48\x48\xac\x3a\x46\xa2\x7c\xd8\x30\x8a\x5b" + + "\xa1\x52\x31\xd4\xfc\x93\x8e\xf1\x00\xef\xbb\xb0\xc7\xa3\x18\x29\xe2\x50\x6c\x00\x97\x33\x85\x99\xea\x18\xa7\x5f" + + "\x3b\xd8\x0b\xf0\x06\x27\x43\x11\xee\x18\x13\x82\xa7\x31\x17\xaa\x40\x3c\x25\x9e\x0a\x3b\x1e\x9e\x10\x17\xc3\xf4" + + "\xe5\x33\x20\x8c\x28\x82\x28\x94\x2e\xa2\xb8\x63\x7f\x06\x32\x14\x84\x8d\xa1\xe2\xd0\x27\xaa\xc3\xb8\x71\xf8\x61" + + "\x0d\xe8\x88\x73\x25\x95\x40\x31\xe8\xdd\xde\xae\xb1\x50\xc2\xc6\x40\x60\xda\x31\xa4\x9a\x53\x2c\x43\x8c\x95\x01" + + "\x42\x81\xfd\x8e\xa1\x71\xc8\x96\x65\xb9\x1e\x1b\x49\xd3\xa5\x3c\xf1\x7c\x8a\x04\x36\x5d\x1e\x59\x68\x84\x66\x16" + + "\x25\x8e\xb4\xd4\x94\x28\x85\x05\x74\x72\x0d\x56\xd5\x2c\x99\x25\xcb\x95\xd2\x5a\xad\x99\x11\x61\xa6\x2b\xa5\x91" + + "\xaa\x5d\x7e\x08\x53\x38\x10\x44\xcd\x3b\x86\x0c\x51\xb9\x56\x87\x17\xdd\x46\xf3\x79\x7f\xdc\xf4\x47\xc1\xe0\xfc" + + "\xc6\x1a\x3f\x55\xaf\xae\xca\x03\xe1\x37\xbe\x53\xf5\x18\x51\xeb\xfb\xd7\xdb\xfd\x61\x50\xf2\xc3\x72\xa9\x63\x00" + + "\x57\x70\x29\xb9\x20\x01\x61\x1d\x03\x31\xce\xe6\x11\x4f\xa4\x01\xac\xdf\x87\x2d\xb5\x7f\x8a\x94\x1b\x66\xa0\x3c" + + "\x24\xc6\x74\xfe\x77\x71\x39\xe1\x71\xd5\x3a\xf6\x7a\xdd\xf8\xb2\xfb\x48\xaf\xe2\xc9\xb9\x94\xf7\xa8\x1c\x1e\x97" + + "\x8e\x93\xc6\x4c\x04\x57\x13\xf5\x58\x9d\x96\x6b\x32\x1c\xfc\x35\xae\xdf\x06\x8c\x92\x20\x54\x01\xa2\x14\x8b\xb9" + + "\x65\x9b\x75\xb3\x99\xc6\xab\xb8\xfc\x3e\x68\x0d\xe1\xf7\x9d\x33\xb1\x3f\x4a\x2a\x57\x6e\xa9\xd9\x1c\x9d\x9c\x0d" + + "\x86\xf6\xac\x7b\x9d\x34\x7a\x77\xd7\xfd\xfb\x46\x72\x5d\x3b\xab\x3c\x58\xdf\xbb\x8f\xbf\x0b\x5a\x22\xb1\xe9\x73" + + "\xa6\xd0\x14\x4b\x1e\x2d\x91\x09\x4c\x31\x92\x58\x5a\x93\x9a\x59\x32\xed\x65\xf6\x21\x4a\xff\x1a\x40\xa5\x51\x85" + + "\xfb\x5e\xe9\xba\x51\x61\xcd\x31\xba\x19\xf4\xa6\xa3\xc6\x49\x75\x78\x76\x54\xaf\xab\xe7\xd3\xe9\xd5\x79\x24\x3c" + + "\xa7\x5a\xdf\x8f\xb9\x38\xb6\xae\x26\xe2\x6c\xbf\x72\xf0\xe3\xe9\x74\x70\x70\xcf\x8f\xd4\xb4\x7f\x55\xbf\xa4\xc1" + + "\x4e\x50\x39\xa4\x14\xc8\x61\x66\x83\xe9\x22\xe1\x81\x05\x70\x13\x21\xb9\x68\x81\x98\x6b\x8b\xc4\x17\xf0\xb2\x41" + + "\x90\x7e\x43\x12\x05\x90\x4f\xb0\xa0\x68\x0e\x16\x39\x29\xc4\x13\xcc\x94\x6c\x01\xc6\x19\xfe\x02\x9e\x21\x61\x1e" + + "\x9e\xb5\x40\x65\x4b\x86\x99\x85\xb1\x15\x6a\x11\x80\x44\x01\x58\xac\xa9\xed\x5f\x52\xb7\x98\x0a\xa1\x1b\x12\xea" + + "\xed\xd9\x9f\x8a\xac\xe5\xbf\xc3\x5a\xd6\xac\x4a\x20\x26\x7d\x2e\xa2\x16\x10\x5c\x21\x85\xf7\x60\xd9\xc3\xc1\xa7" + + "\xe5\x06\x45\x0a\x3f\xee\xd9\xa5\x78\x56\x58\x78\xd8\x83\x76\x39\x9e\x7d\xfa\x3b\xba\x2a\x6f\xeb\x02\xb5\x6d\x5d" + + "\xb0\xb1\xa5\x0b\xbc\xa5\x0b\xe4\xca\x34\x70\xe2\x22\xc5\x45\x1a\x05\x49\x14\xe1\xac\x05\x90\x23\x39\x4d\x14\xfe" + + "\x02\x84\x3e\x35\x2d\x60\xe3\xe8\x0b\x50\x78\xa6\xa0\x0c\x91\xc7\xa7\x2d\x50\x02\x25\x50\x89\x67\xe0\x63\xb9\xa4" + + "\xff\x7d\x01\x8a\xc7\x19\xdd\xa6\xaa\x14\x08\x57\x7b\x2d\x9f\x08\xa9\x96\x78\x3e\xed\xd0\xb6\x0a\x04\xdc\x0e\x62" + + "\x16\xe4\x14\x58\xc6\xb6\x72\x07\x30\x2b\x12\xe8\x23\x02\x79\xa2\xbe\x80\xb4\x86\xb4\x80\x5d\x2a\xfd\xaf\x20\x84" + + "\xa1\x09\x4c\x4f\x20\xd1\x29\xca\xa9\xce\x50\x11\x38\x68\xaf\x5c\xab\x7d\xce\xff\x9b\xb5\xd4\x53\x19\xcf\x9f\x11" + + "\xf6\x08\x02\x7b\x11\x9a\xc1\x4c\x28\x38\xa8\x1f\x98\xcd\xd4\xc7\xbb\x3e\x0b\x60\x4e\x61\x2c\xb8\x0b\x16\xb9\x29" + + "\xb5\xd4\x92\x95\x2d\x6f\xc9\x6d\x36\xed\x4c\x2e\x62\x1e\xd8\x8b\x08\xcb\xb7\x0e\xea\x4b\x75\x6f\xc8\xad\x54\x7e" + + "\x25\xd7\xb6\x9b\xcd\x1d\x72\x9b\xcd\xf2\x2e\xb9\xe5\xda\xdb\x72\xd7\xcc\x76\xb9\x54\xfa\x2b\x27\xbc\xed\x87\x72" + + "\xd1\x0f\x6d\x2b\xbb\x3d\x96\x6f\x8a\x28\x8a\x0f\xaf\x43\xae\xb8\x6c\x5b\xcb\x37\xdd\xbc\x58\x79\xf7\xd2\x76\xb8" + + "\x37\xcf\xca\x1f\x43\x13\xe0\x52\x24\x65\xc7\x60\x68\xe2\x20\x01\x96\x3f\x10\xcf\x62\xc4\x3c\x48\x03\xe0\x93\x19" + + "\xf6\xa0\xc3\x95\xe2\x51\xbe\x9b\x96\x00\xe0\x04\xcb\x07\x23\xbf\xb8\xda\x68\x53\x18\x74\x04\x62\x5e\x7e\x35\x7f" + + "\x34\x56\x56\xa1\x15\x87\x93\x28\xc5\xd9\x16\x9b\xe2\x41\x40\xb1\x30\x80\xee\xc7\x3a\xc6\x92\xc6\x00\x1e\x52\x28" + + "\xdb\xeb\x18\x2e\xa7\x14\xc5\x12\x1b\xe0\xc3\xa6\xbb\x96\x54\x48\x04\xba\xf1\xfa\xb8\x94\x78\x9b\xc4\xba\x59\xc2" + + "\x5e\x6f\xd9\x2c\x19\x00\x09\x82\xa0\x6e\x9d\x04\xa7\x2b\xc5\xaf\xc8\xb6\x44\xa7\x4c\x4b\xcf\x60\xaf\x63\xf8\x88" + + "\x6a\xfd\xe9\x2a\x45\x8e\x2e\x48\x77\xa9\x75\xda\x4d\x24\x40\xfa\x74\xad\x7c\xa3\x2f\xf9\x18\xed\x40\x0a\x89\xab" + + "\x49\xdb\x96\x26\x59\xf9\xc6\x5a\x02\x3f\xcc\x8f\x51\xdb\x23\xab\x68\xe5\xf0\xf3\x88\xac\xdd\x41\xbc\x9d\x70\x0a" + + "\xb6\x24\x74\xcb\x12\x9d\x09\x11\x85\x28\x51\xbc\x40\x97\x56\xdb\x02\x25\x24\x0a\x47\xc6\xe1\x46\xa0\xd3\xdb\x60" + + "\xbb\xfe\xa2\x90\x62\x21\xcd\x08\x5b\xc6\x52\x4e\x9a\x88\x1d\xe3\x07\x76\x24\x51\xd8\x38\x6c\xaf\xc4\xfa\x48\x02" + + "\x1f\xc1\x90\x47\x7a\xd9\x22\x87\xa0\xcf\x23\x1c\xa3\x00\xeb\x44\x69\x5b\x94\xfc\x06\x7b\xc6\x2c\x51\x26\x61\x79" + + "\x23\x6a\xe4\xf6\xdc\x65\xef\x1b\xf6\x38\xda\x1e\xb5\xda\xd1\x26\xfd\x79\x91\x3c\x13\x1f\x8b\xd7\x26\xb5\xad\x84" + + "\xae\x43\xe6\x91\x49\x76\xb4\x2c\x86\x26\xf9\x99\xdc\x08\x1c\x53\x88\x30\x2c\xa0\x4f\x13\xe2\xad\xcf\x4e\x81\x46" + + "\xf0\x29\x88\x14\xac\x80\xc8\x81\xb5\x62\xd4\x36\x13\x00\x46\x1e\xb4\xcb\xc0\x83\x3e\xc5\x33\x30\x4a\xa4\x22\xfe" + + "\x1c\x66\xf3\x00\xa4\xd8\x57\x40\xef\xc0\xa9\x40\xf1\x32\x2f\xf2\x62\x95\xae\x1c\x16\xac\xdd\x32\x3d\x7d\x5c\xcf" + + "\x05\xa3\x9b\x04\x8b\x39\x48\xeb\xce\x67\xa0\x42\xcc\xc0\x35\x8f\x63\x2c\xcc\x91\xcc\xde\xd7\xa3\xc3\x59\x61\x72" + + "\x90\xae\x20\xb1\x02\x52\xb8\xef\x6e\x3a\x47\x4f\x5a\x97\x55\x31\x2b\xa6\x9d\xbd\xa4\x4d\xe6\x48\x6e\x9e\xc6\xd7" + + "\x5d\xe6\x49\x10\xf7\x1c\xeb\xfc\xec\x86\x5e\x5c\xfa\x57\x49\xd3\x56\xa8\x52\xe6\xd6\xe5\xe0\xe7\x8c\xaa\xe9\x90" + + "\x37\x6e\x54\x34\x1e\x0c\xbd\x6e\xd2\xd8\xdd\x65\xea\x33\x98\x1a\xfd\xcf\x11\xc4\xb9\x6b\x2c\xdb\xb4\xab\xa6\x9d" + + "\x2f\xbc\x0f\xc5\xed\x5d\x79\x80\x5d\xf1\x20\xce\x50\x57\x3e\x45\x7e\x3c\x6e\x3e\x0c\x6f\x4e\xef\xe8\x31\x9f\x0f" + + "\xa2\x7b\x15\x9c\x1f\x7d\x65\xde\x31\x91\xb7\xee\x7f\x8a\x62\xd7\xc4\x36\xda\x1e\xd8\x7e\x0d\xa9\xb6\x5f\x2a\x3f" + + "\x27\xb5\xfb\xfb\x8b\x9b\xf1\xd5\xc1\xd4\xfe\x76\x2a\xea\x13\x5f\xf5\x82\x81\x7f\xe2\xfd\x74\xbb\x7d\x7c\xac\x4e" + + "\xd8\xf9\x4f\x79\x24\xdf\x05\x69\x9d\x98\x17\xba\xfc\x7c\x5b\x26\xf5\xbf\xca\xba\x37\x46\x9d\xd1\x1b\x93\xce\xaf" + + "\xb1\xb2\xaf\xee\xc8\xbb\x69\x38\x27\x55\x6e\xcd\xce\x4f\x7a\xb7\x3f\x8e\x9a\xdd\xf1\xcf\xfd\xfe\xf5\x8f\xa8\xe7" + + "\x8c\xfb\x97\x4f\x49\xf8\xb5\xf6\x78\x79\xe1\xbd\x0f\xeb\x3f\x06\x14\xc0\x10\xc9\xd0\xb2\xcd\x92\x59\xcd\xdf\xde" + + "\x89\x41\xf4\xea\xf1\x65\x75\x68\xf3\x68\x24\xd4\x60\x5a\xaa\xb3\x93\x41\xaf\x3b\x7c\x7e\x7c\x9a\x25\xd5\x39\xfa" + + "\xce\x87\x77\xfd\x9f\x68\x7f\x7a\xf7\x3c\xfd\xaf\x31\xa8\x30\x89\x1c\x86\x08\xd5\x67\xc9\x2c\x6d\x2c\xbd\x13\x4d" + + "\x6f\x6c\x5d\xff\xb8\xb9\xe7\x7d\xe9\x36\xbd\xf2\x43\x75\x7e\xdf\xbd\x98\x08\x79\x60\xdf\xf0\x9a\x2b\xf7\x83\xd3" + + "\xfe\xf1\x8f\x23\x5a\xfe\x16\x38\xef\xbb\x16\xfe\x31\x9c\x10\x31\x8f\x62\x07\x09\xa9\xef\x06\x7d\x9a\x6c\xbb\xb8" + + "\xf8\x3e\x38\xfb\x67\x83\xbe\x7c\x18\xce\xf1\x9d\x9c\x4a\x4b\x3d\x3b\xa7\x61\xed\xb1\x7f\x33\x1b\x7a\xe7\xbd\xe4" + + "\x72\x14\x4d\x2e\xdd\xbb\x13\xf5\x58\x3f\xbe\x78\xdf\xfd\xf0\x1a\x0e\x8a\x63\x6d\xc7\x2e\x1a\x5d\x47\x10\x75\x92" + + "\x08\x2a\x1c\xc5\x7a\x36\xca\xfb\x34\x3d\xd6\x58\x33\xb8\x86\xb4\xa6\x78\xab\xca\xa5\xd3\x48\xde\x43\x2e\x67\xa2" + + "\x69\x48\x14\x06\x59\xb7\xeb\x53\x8e\xb2\x32\xb6\x58\x7c\x24\xfe\x37\x05\x48\x84\x02\x2c\x4d\x8a\x59\xa0\x42\x60" + + "\xbf\xbc\x64\x87\x73\xb1\xb0\xf4\xfe\xcb\x4b\xa1\x58\x2e\x16\x1f\x31\x72\xc3\x8c\xe7\xe5\x65\x5d\x45\xf5\x04\x54" + + "\xb0\x41\x8f\xd0\xc0\xe1\xc2\xd3\x6d\x41\xc1\xfb\xa9\x33\x16\x8b\x55\xbe\xbd\xbc\x14\x63\x83\xa8\x4a\x77\x75\x1b" + + "\xf1\xf2\xb2\xc1\x98\x76\xa0\x19\xb7\x9f\x50\x2a\xc9\x33\xde\x32\xcd\xd2\xa6\x15\x6d\xda\xf2\xcb\xc6\x58\x1f\x42" + + "\xbb\x54\xca\xcb\x7c\x5a\xd1\x5d\x4e\x93\x88\xbd\x2a\xf9\x98\x79\x9b\xbd\x5b\x58\x3b\x5c\x99\xd8\xb6\xc2\x5a\x71" + + "\x73\xa7\x4f\x8b\x02\xb6\x9b\x34\x97\x72\x86\xc1\xab\x99\x77\xd9\x24\x6d\x08\xcf\x02\x52\x68\x93\x76\x35\x1b\x3b" + + "\xb3\x0c\x0b\xc1\xc5\xbf\xcd\x32\xdd\x4b\x6d\xfb\x29\xf2\xa0\x8b\x59\xda\xdc\xed\xec\xad\x66\x12\xda\x25\x3d\xdf" + + "\x42\x19\xc1\x06\xc8\xda\xad\x7a\xfa\x40\x03\x58\xdd\x74\x74\x81\x19\x51\x2c\x14\x48\xbf\xa1\x87\x58\xa0\xb5\x2c" + + "\x16\x11\x96\x12\x05\x69\x18\x0a\x7e\x78\xa7\x5b\xda\xd6\x72\x64\x6b\x5b\xcb\xbf\x4d\xff\x3f\x00\x00\xff\xff\x86" + + "\xd2\x72\xac\xac\x16\x00\x00") + +func bindataFrontendIndexhtmlBytes() ([]byte, error) { + return bindataRead( + _bindataFrontendIndexhtml, + "frontend/index.html", + ) +} + + + +func bindataFrontendIndexhtml() (*asset, error) { + bytes, err := bindataFrontendIndexhtmlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{ + name: "frontend/index.html", + size: 5804, + md5checksum: "", + mode: os.FileMode(436), + modTime: time.Unix(1, 0), + } + + a := &asset{bytes: bytes, info: info} + + return a, nil +} + + +// +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +// +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, &os.PathError{Op: "open", Path: name, Err: os.ErrNotExist} +} + +// +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +// nolint: deadcode +// +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or could not be loaded. +// +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, &os.PathError{Op: "open", Path: name, Err: os.ErrNotExist} +} + +// +// AssetNames returns the names of the assets. +// nolint: deadcode +// +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// +// _bindata is a table, holding each asset generator, mapped to its name. +// +var _bindata = map[string]func() (*asset, error){ + "frontend/albums.json": bindataFrontendAlbumsjson, + "frontend/app.js": bindataFrontendAppjs, + "frontend/index.html": bindataFrontendIndexhtml, +} + +// +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +// +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, &os.PathError{ + Op: "open", + Path: name, + Err: os.ErrNotExist, + } + } + } + } + if node.Func != nil { + return nil, &os.PathError{ + Op: "open", + Path: name, + Err: os.ErrNotExist, + } + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} + +var _bintree = &bintree{Func: nil, Children: map[string]*bintree{ + "frontend": {Func: nil, Children: map[string]*bintree{ + "albums.json": {Func: bindataFrontendAlbumsjson, Children: map[string]*bintree{}}, + "app.js": {Func: bindataFrontendAppjs, Children: map[string]*bintree{}}, + "index.html": {Func: bindataFrontendIndexhtml, Children: map[string]*bintree{}}, + }}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} diff --git a/frontend/app.js b/frontend/app.js new file mode 100644 index 0000000..98fd6d7 --- /dev/null +++ b/frontend/app.js @@ -0,0 +1,63 @@ +/* global $:false Handlebars:false */ + +class Gallery { + constructor() { + Handlebars.registerHelper('ifGt', this.handlebarsBiggerThan); + this.error_tpl = Handlebars.compile($('#error-template').html()); + this.album_tpl = Handlebars.compile($('#album-template').html()); + + this.optionset = { + // General options + download: false, + selector: 'img', + // Thumbnails + thumbnail: true, + thumbWidth: 80, + exThumbImage: 'src', + showThumbByDefault: false, + }; + } + + displayError(message = '') { + $('.container-fluid').append(this.error_tpl({ + message, + })); + } + + handlebarsBiggerThan(v1, v2, options) { + if (v1 > v2) { + return options.fn(this); + } + return options.inverse(this); + } + + initialize(uri) { + $.ajax(uri, { + error: () => this.displayError('Could not fetch albums.'), + method: 'GET', + success: (data) => this.processAlbums(data), + }); + } + + processAlbums(albumData) { + let albums = albumData.albums; + albums.sort((a, b) => b.id - a.id); + + albums.forEach((album) => { + let albumElement = $(this.album_tpl(album)); + $('#gallery-wrap').append(albumElement); + albumElement.lightGallery(this.updatedOptionSet({ + galleryId: album.id, + })); + }); + } + + updatedOptionSet(opts = {}) { + return Object.assign({}, this.optionset, opts); + } +} + +$(() => { + let gallery = new Gallery(); + gallery.initialize('albums.json'); +}); diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..d268ee7 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + Photos + + + + +
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + +