photos/js/photos-src_views_Faces_vue....

1 line
48 KiB
XML

{"version":3,"file":"photos-src_views_Faces_vue.js?v=fe346feb46b84eee5aa0","mappings":"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","sources":["webpack:///photos/src/mixins/FaceCoverMixin.js","webpack:///photos/src/mixins/FetchFacesMixin.js","webpack:///photos/src/services/DavRequest.js","webpack:///photos/src/utils/CancelableRequest.js","webpack:///photos/src/components/FaceCover.vue?vue&type=style&index=0&id=2a995501&lang=scss&scoped=true&","webpack:///photos/src/components/Loader.vue?vue&type=style&index=0&lang=scss&","webpack:///photos/src/views/Faces.vue?vue&type=style&index=0&id=40b27884&lang=scss&scoped=true&","webpack:///photos/src/components/Loader.vue","webpack:///photos/src/components/Loader.vue?vue&type=script&lang=js&","webpack://photos/./src/components/Loader.vue?eb1b","webpack://photos/./src/components/Loader.vue?5508","webpack:///photos/src/components/Loader.vue?vue&type=template&id=7bbb2dd6&","webpack:///photos/src/views/Faces.vue?vue&type=template&id=40b27884&scoped=true&","webpack:///photos/src/components/FaceCover.vue","webpack:///photos/src/components/FaceCover.vue?vue&type=script&lang=js&","webpack://photos/./src/components/FaceCover.vue?a054","webpack:///photos/src/views/Faces.vue","webpack:///photos/src/views/Faces.vue?vue&type=script&lang=js&","webpack://photos/./src/components/FaceCover.vue?d6a7","webpack:///photos/src/components/FaceCover.vue?vue&type=template&id=2a995501&scoped=true&","webpack://photos/./src/views/Faces.vue?a062","webpack://photos/./src/views/Faces.vue?a265"],"sourcesContent":["/**\n * @copyright Copyright (c) 2022 Marcel Klehr <mklehr@gmx.net>\n *\n * @author Marcel Klehr <mklehr@gmx.net>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\nimport { mapGetters } from 'vuex'\nimport he from 'he'\n\nexport default {\n\tname: 'FaceCoverMixin',\n\n\tcomputed: {\n\t\t...mapGetters([\n\t\t\t'faces',\n\t\t\t'facesFiles',\n\t\t\t'files',\n\t\t]),\n\t},\n\n\tmethods: {\n\t\tgetFaceCover(faceName) {\n\t\t return (this.facesFiles[faceName] || [])\n\t\t\t .slice(0, 25)\n\t\t\t .map(fileId => this.files[fileId])\n\t\t\t .map(file => ({ ...file, faceDetections: JSON.parse(he.decode(file.faceDetections)) }))\n\t\t\t // sort larges face first\n\t\t\t .sort((a, b) =>\n\t\t\t\t b.faceDetections.find(d => d.title === faceName).width\n\t\t\t\t - a.faceDetections.find(d => d.title === faceName).width\n\t\t\t )\n\t\t\t // sort fewest face detections first\n\t\t\t .sort((a, b) =>\n\t\t\t\t a.faceDetections.length\n\t\t\t\t - b.faceDetections.length\n\t\t\t )[0]\n\t\t},\n\n\t\t/**\n\t\t * This will produce an inline style to apply to images\n\t\t * to zoom toward the detected face\n\t\t *\n\t\t * @param faceName\n\t\t * @return {{}|{transform: string, width: string, transformOrigin: string}}\n\t\t */\n\t\tgetCoverStyle(faceName) {\n\t\t\tconst cover = this.getFaceCover(faceName)\n\t\t\tif (!cover) {\n\t\t\t\treturn {}\n\t\t\t}\n\t\t\tconst detections = cover.faceDetections\n\n\t\t\tconst detection = detections.find(detection => detection.title === faceName)\n\n\t\t\t// Zoom into the picture so that the face fills the --photos-face-width box nicely\n\t\t\t// if the face is larger than the image, we don't zoom out (reason for the Math.max)\n\t\t\tconst zoom = Math.max(1, (1 / detection.width) * 0.4)\n\n\t\t\tconst horizontalCenterOfFace = (detection.x + detection.width / 2) * 100\n\t\t\tconst verticalCenterOfFace = (detection.y + detection.height / 2) * 100\n\n\t\t\treturn {\n\t\t\t\t// We assume that the image is inside a div with width: var(--photos-face-width)\n\t\t\t\twidth: '100%',\n\t\t\t\t// we translate the image so that the center of the detected face is in the center of the --photos-face-width box\n\t\t\t\t// and add the zoom\n\t\t\t\ttransform: `translate(calc( var(--photos-face-width)/2 - ${horizontalCenterOfFace}% ), calc( var(--photos-face-width)/2 - ${verticalCenterOfFace}% )) scale(${zoom})`,\n\t\t\t\t// this is necessary for the zoom to zoom toward the center of the face\n\t\t\t\ttransformOrigin: `${horizontalCenterOfFace}% ${verticalCenterOfFace}%`,\n\t\t\t}\n\t\t},\n\t},\n}\n","/**\n * @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>\n *\n * @author Louis Chemineau <louis@chmn.me>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\nimport { mapActions, mapGetters } from 'vuex'\n\nimport { showError } from '@nextcloud/dialogs'\nimport { getCurrentUser } from '@nextcloud/auth'\n\nimport client from '../services/DavClient.js'\nimport logger from '../services/logger.js'\nimport cancelableRequest from '../utils/CancelableRequest.js'\nimport DavRequest from '../services/DavRequest'\nimport { genFileInfo } from '../utils/fileUtils'\n\nexport default {\n\tname: 'FetchFacesMixin',\n\n\tdata() {\n\t\treturn {\n\t\t\terrorFetchingFaces: null,\n\t\t\tloadingFaces: false,\n\t\t\terrorFetchingFiles: null,\n\t\t\tloadingFiles: false,\n\t\t\tcancelFacesRequest: () => { },\n\t\t\tcancelFilesRequest: () => {},\n\t\t}\n\t},\n\n\tasync beforeMount() {\n\t\tthis.fetchFaces()\n\t},\n\n\tbeforeDestroy() {\n\t\tthis.cancelFacesRequest('Changed view')\n\t\tthis.cancelFilesRequest('Changed view')\n\t},\n\n\tcomputed: {\n\t\t...mapGetters([\n\t\t\t'faces',\n\t\t]),\n\t},\n\n\tmethods: {\n\t\t...mapActions([\n\t\t\t'appendFiles',\n\t\t]),\n\n\t\tasync fetchFaces() {\n\t\t\tif (this.loadingFaces) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (Object.keys(this.faces).length) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tthis.loadingFaces = true\n\t\t\t\tthis.errorFetchingFaces = null\n\n\t\t\t\tconst { request, cancel } = cancelableRequest(client.getDirectoryContents)\n\t\t\t\tthis.cancelFacesRequest = cancel\n\n\t\t\t\tconst faces = await request(`/recognize/${getCurrentUser()?.uid}/faces/`)\n\t\t\t\tthis.$store.dispatch('addFaces', { faces })\n\t\t\t\tlogger.debug(`[FetchFacesMixin] Fetched ${faces.length} new faces: `, faces)\n\t\t\t} catch (error) {\n\t\t\t\tif (error.response && error.response.status) {\n\t\t\t\t\tif (error.response.status === 404) {\n\t\t\t\t\t\tthis.errorFetchingFaces = 404\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.errorFetchingFaces = error\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlogger.error(t('photos', 'Failed to fetch faces list.'), error)\n\t\t\t\tshowError(t('photos', 'Failed to fetch faces list.'))\n\t\t\t} finally {\n\t\t\t\tthis.cancelFacesRequest = () => { }\n\t\t\t\tthis.loadingFaces = false\n\t\t\t}\n\t\t},\n\n\t\tasync fetchFaceContent(faceName, force) {\n\t\t\tif (this.loadingFiles) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tif (!force && this.facesFiles[faceName] && this.facesFiles[faceName].length) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tthis.errorFetchingFiles = null\n\t\t\t\tthis.loadingFiles = true\n\n\t\t\t\tconst { request, cancel } = cancelableRequest(client.getDirectoryContents)\n\t\t\t\tthis.cancelFilesRequest = cancel\n\n\t\t\t\tlet { data: fetchedFiles } = await request(\n\t\t\t\t\t`/recognize/${getCurrentUser()?.uid}/faces/${faceName}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tdata: DavRequest,\n\t\t\t\t\t\tdetails: true,\n\t\t\t\t\t}\n\t\t\t\t)\n\n\t\t\t\tfetchedFiles = fetchedFiles\n\t\t\t\t\t.map(file => genFileInfo(file))\n\t\t\t\t\t.map(file => ({ ...file, filename: file.realpath.replace(`/${getCurrentUser().uid}/files`, '') }))\n\n\t\t\t\tconst fileIds = fetchedFiles.map(file => '' + file.fileid)\n\n\t\t\t\tthis.appendFiles(fetchedFiles)\n\n\t\t\t\tif (fetchedFiles.length > 0) {\n\t\t\t\t\tawait this.$store.commit('addFilesToFace', { faceName, fileIdsToAdd: fileIds })\n\t\t\t\t}\n\n\t\t\t\tlogger.debug(`[FetchFacesMixin] Fetched ${fileIds.length} new files: `, fileIds)\n\t\t\t} catch (error) {\n\t\t\t\tif (error.response && error.response.status) {\n\t\t\t\t\tif (error.response.status === 404) {\n\t\t\t\t\t\tthis.errorFetchingFiles = 404\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.errorFetchingFiles = error\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// cancelled request, moving on...\n\t\t\t\tlogger.error('Error fetching face files', error)\n\t\t\t} finally {\n\t\t\t\tthis.loadingFiles = false\n\t\t\t\tthis.cancelFilesRequest = () => { }\n\t\t\t}\n\t\t},\n\t},\n}\n","/**\n * @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @author John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\nconst props = `\n\t<oc:fileid />\n\t<d:getlastmodified />\n\t<d:getetag />\n\t<d:getcontenttype />\n\t<d:getcontentlength />\n\t<nc:realpath />\n\t<nc:has-preview />\n\t<nc:file-metadata-size />\n\t<nc:face-detections />\n\t<oc:favorite />\n\t<d:resourcetype />`\n\nexport { props }\nexport default `<?xml version=\"1.0\"?>\n\t\t\t<d:propfind xmlns:d=\"DAV:\"\n\t\t\t\txmlns:oc=\"http://owncloud.org/ns\"\n\t\t\t\txmlns:nc=\"http://nextcloud.org/ns\"\n\t\t\t\txmlns:ocs=\"http://open-collaboration-services.org/ns\">\n\t\t\t\t<d:prop>\n\t\t\t\t\t${props}\n\t\t\t\t</d:prop>\n\t\t\t</d:propfind>`\n","/**\n * @copyright Copyright (c) 2019 Marco Ambrosini <marcoambrosini@pm.me>\n *\n * @author Marco Ambrosini <marcoambrosini@pm.me>\n *\n * @author John Molakvoæ <skjnldsv@protonmail.com>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\n\nimport axios from '@nextcloud/axios'\n/**\n * Create a cancel token\n *\n * @return {CancelTokenSource}\n */\nconst createCancelToken = () => axios.CancelToken.source()\n\n/**\n * Creates a cancelable axios 'request object'.\n *\n * @param {Function} request the axios promise request\n * @return {object}\n */\nconst CancelableRequest = function(request) {\n\t/**\n\t * Generate an axios cancel token\n\t */\n\tconst cancelToken = createCancelToken()\n\n\t/**\n\t * Execute the request\n\t *\n\t * @param {string} url the url to send the request to\n\t * @param {object} [options] optional config for the request\n\t */\n\tconst fetch = async function(url, options) {\n\t\treturn request(\n\t\t\turl,\n\t\t\tObject.assign({ cancelToken: cancelToken.token }, options)\n\t\t)\n\t}\n\n\treturn {\n\t\trequest: fetch,\n\t\tcancel: cancelToken.cancel,\n\t}\n}\n\nexport default CancelableRequest\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".face-cover[data-v-2a995501]{display:flex;flex-direction:column;padding:10px;border-radius:var(--border-radius-large)}.face-cover__crop-container[data-v-2a995501]{overflow:hidden;width:250px;height:250px;border-radius:250px;position:relative;background:var(--color-background-darker);--photos-face-width: 250px}@media only screen and (max-width: 1020px){.face-cover__crop-container[data-v-2a995501]{width:95px;height:95px;--photos-face-width: 95px}}.face-cover[data-v-2a995501]:hover,.face-cover[data-v-2a995501]:focus{background:var(--color-background-hover)}.face-cover__details[data-v-2a995501]{display:flex;flex-direction:column;width:250px;margin-top:4px;text-align:center}@media only screen and (max-width: 1020px){.face-cover__details[data-v-2a995501]{width:95px}}.face-cover__details__first-line[data-v-2a995501]{display:flex;height:2em;overflow:hidden;text-overflow:ellipsis}.face-cover__details__second-line[data-v-2a995501]{color:var(--color-text-maxcontrast)}.face-cover__details__name[data-v-2a995501]{flex-grow:1;margin:0}\", \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/FaceCover.vue\"],\"names\":[],\"mappings\":\"AAuHA,6BACC,YAAA,CACA,qBAAA,CACA,YAAA,CACA,wCAAA,CAEA,6CACC,eAAA,CACA,WAAA,CACA,YAAA,CACA,mBAAA,CACA,iBAAA,CACA,yCAAA,CACA,0BAAA,CAEA,2CATD,6CAUE,UAAA,CACA,WAAA,CACA,yBAAA,CAAA,CAIF,sEACC,wCAAA,CAGD,sCACC,YAAA,CACA,qBAAA,CACA,WAAA,CACA,cAAA,CACA,iBAAA,CAEA,2CAPD,sCAQE,UAAA,CAAA,CAGD,kDACC,YAAA,CACA,UAAA,CACA,eAAA,CACA,sBAAA,CAGD,mDACC,mCAAA,CAGD,4CACC,WAAA,CACA,QAAA\",\"sourcesContent\":[\"$sizes: (\\\"400\\\": (\\\"count\\\": 3, \\\"marginTop\\\": 66, \\\"marginW\\\": 8), \\\"700\\\": (\\\"count\\\": 4, \\\"marginTop\\\": 66, \\\"marginW\\\": 8), \\\"1024\\\": (\\\"count\\\": 5, \\\"marginTop\\\": 66, \\\"marginW\\\": 44), \\\"1280\\\": (\\\"count\\\": 4, \\\"marginTop\\\": 66, \\\"marginW\\\": 44), \\\"1440\\\": (\\\"count\\\": 5, \\\"marginTop\\\": 88, \\\"marginW\\\": 66), \\\"1600\\\": (\\\"count\\\": 6, \\\"marginTop\\\": 88, \\\"marginW\\\": 66), \\\"2048\\\": (\\\"count\\\": 7, \\\"marginTop\\\": 88, \\\"marginW\\\": 66), \\\"2560\\\": (\\\"count\\\": 8, \\\"marginTop\\\": 88, \\\"marginW\\\": 88), \\\"3440\\\": (\\\"count\\\": 9, \\\"marginTop\\\": 88, \\\"marginW\\\": 88), \\\"max\\\": (\\\"count\\\": 10, \\\"marginTop\\\": 88, \\\"marginW\\\": 88));\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n.face-cover {\\n\\tdisplay: flex;\\n\\tflex-direction: column;\\n\\tpadding: 10px;\\n\\tborder-radius: var(--border-radius-large);\\n\\n\\t&__crop-container {\\n\\t\\toverflow: hidden;\\n\\t\\twidth: 250px;\\n\\t\\theight: 250px;\\n\\t\\tborder-radius: 250px;\\n\\t\\tposition: relative;\\n\\t\\tbackground: var(--color-background-darker);\\n\\t\\t--photos-face-width: 250px;\\n\\n\\t\\t@media only screen and (max-width: 1020px) {\\n\\t\\t\\twidth: 95px;\\n\\t\\t\\theight: 95px;\\n\\t\\t\\t--photos-face-width: 95px;\\n\\t\\t}\\n\\t}\\n\\n\\t&:hover, &:focus {\\n\\t\\tbackground: var(--color-background-hover);\\n\\t}\\n\\n\\t&__details {\\n\\t\\tdisplay: flex;\\n\\t\\tflex-direction: column;\\n\\t\\twidth: 250px;\\n\\t\\tmargin-top: 4px;\\n\\t\\ttext-align: center;\\n\\n\\t\\t@media only screen and (max-width: 1020px) {\\n\\t\\t\\twidth: 95px;\\n\\t\\t}\\n\\n\\t\\t&__first-line {\\n\\t\\t\\tdisplay: flex;\\n\\t\\t\\theight: 2em;\\n\\t\\t\\toverflow: hidden;\\n\\t\\t\\ttext-overflow: ellipsis;\\n\\t\\t}\\n\\n\\t\\t&__second-line {\\n\\t\\t\\tcolor: var(--color-text-maxcontrast);\\n\\t\\t}\\n\\n\\t\\t&__name {\\n\\t\\t\\tflex-grow: 1;\\n\\t\\t\\tmargin: 0;\\n\\t\\t}\\n\\t}\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".loader{display:grid;height:60px}\", \"\",{\"version\":3,\"sources\":[\"webpack://./src/components/Loader.vue\"],\"names\":[],\"mappings\":\"AAsCA,QACC,YAAA,CACA,WAAA\",\"sourcesContent\":[\"$sizes: (\\\"400\\\": (\\\"count\\\": 3, \\\"marginTop\\\": 66, \\\"marginW\\\": 8), \\\"700\\\": (\\\"count\\\": 4, \\\"marginTop\\\": 66, \\\"marginW\\\": 8), \\\"1024\\\": (\\\"count\\\": 5, \\\"marginTop\\\": 66, \\\"marginW\\\": 44), \\\"1280\\\": (\\\"count\\\": 4, \\\"marginTop\\\": 66, \\\"marginW\\\": 44), \\\"1440\\\": (\\\"count\\\": 5, \\\"marginTop\\\": 88, \\\"marginW\\\": 66), \\\"1600\\\": (\\\"count\\\": 6, \\\"marginTop\\\": 88, \\\"marginW\\\": 66), \\\"2048\\\": (\\\"count\\\": 7, \\\"marginTop\\\": 88, \\\"marginW\\\": 66), \\\"2560\\\": (\\\"count\\\": 8, \\\"marginTop\\\": 88, \\\"marginW\\\": 88), \\\"3440\\\": (\\\"count\\\": 9, \\\"marginTop\\\": 88, \\\"marginW\\\": 88), \\\"max\\\": (\\\"count\\\": 10, \\\"marginTop\\\": 88, \\\"marginW\\\": 88));\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n.loader {\\n\\tdisplay: grid;\\n\\theight: 60px;\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","// Imports\nimport ___CSS_LOADER_API_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/sourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".faces[data-v-40b27884]{display:flex;flex-direction:column;height:calc(100vh - var(--header-height));padding-left:64px}@media only screen and (max-width: 1020px){.faces[data-v-40b27884]{padding:0}}.faces__header[data-v-40b27884]{display:flex;min-height:60px;align-items:center}.faces__header button[data-v-40b27884]{margin-right:32px}.faces__list[data-v-40b27884]{padding-top:24px;padding-bottom:32px;flex-grow:1;display:flex;flex-wrap:wrap;overflow:scroll;gap:32px;align-content:flex-start}.faces__empty[data-v-40b27884]{display:flex;flex-direction:column;align-items:center}.faces__empty__button[data-v-40b27884]{margin-top:32px}.empty-content-with-illustration[data-v-40b27884] .empty-content__icon{width:200px;height:200px}.empty-content-with-illustration[data-v-40b27884] .empty-content__icon svg{width:200px;height:200px}\", \"\",{\"version\":3,\"sources\":[\"webpack://./src/views/Faces.vue\"],\"names\":[],\"mappings\":\"AAqGA,wBACC,YAAA,CACA,qBAAA,CACA,yCAAA,CACA,iBAAA,CAEA,2CAND,wBAOE,SAAA,CAAA,CAGD,gCACC,YAAA,CACA,eAAA,CACA,kBAAA,CAEA,uCACC,iBAAA,CAIF,8BACC,gBAAA,CACA,mBAAA,CACA,WAAA,CACA,YAAA,CACA,cAAA,CACA,eAAA,CACA,QAAA,CACA,wBAAA,CAGD,+BACC,YAAA,CACA,qBAAA,CACA,kBAAA,CAEA,uCACC,eAAA,CAKH,wEACC,WAAA,CACA,YAAA,CAEA,4EACC,WAAA,CACA,YAAA\",\"sourcesContent\":[\"$sizes: (\\\"400\\\": (\\\"count\\\": 3, \\\"marginTop\\\": 66, \\\"marginW\\\": 8), \\\"700\\\": (\\\"count\\\": 4, \\\"marginTop\\\": 66, \\\"marginW\\\": 8), \\\"1024\\\": (\\\"count\\\": 5, \\\"marginTop\\\": 66, \\\"marginW\\\": 44), \\\"1280\\\": (\\\"count\\\": 4, \\\"marginTop\\\": 66, \\\"marginW\\\": 44), \\\"1440\\\": (\\\"count\\\": 5, \\\"marginTop\\\": 88, \\\"marginW\\\": 66), \\\"1600\\\": (\\\"count\\\": 6, \\\"marginTop\\\": 88, \\\"marginW\\\": 66), \\\"2048\\\": (\\\"count\\\": 7, \\\"marginTop\\\": 88, \\\"marginW\\\": 66), \\\"2560\\\": (\\\"count\\\": 8, \\\"marginTop\\\": 88, \\\"marginW\\\": 88), \\\"3440\\\": (\\\"count\\\": 9, \\\"marginTop\\\": 88, \\\"marginW\\\": 88), \\\"max\\\": (\\\"count\\\": 10, \\\"marginTop\\\": 88, \\\"marginW\\\": 88));\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n.faces {\\n\\tdisplay: flex;\\n\\tflex-direction: column;\\n\\theight: calc(100vh - var(--header-height));\\n\\tpadding-left: 64px;\\n\\n\\t@media only screen and (max-width: 1020px) {\\n\\t\\tpadding: 0;\\n\\t}\\n\\n\\t&__header {\\n\\t\\tdisplay: flex;\\n\\t\\tmin-height: 60px;\\n\\t\\talign-items: center;\\n\\n\\t\\tbutton {\\n\\t\\t\\tmargin-right: 32px;\\n\\t\\t}\\n\\t}\\n\\n\\t&__list {\\n\\t\\tpadding-top: 24px;\\n\\t\\tpadding-bottom: 32px;\\n\\t\\tflex-grow: 1;\\n\\t\\tdisplay: flex;\\n\\t\\tflex-wrap: wrap;\\n\\t\\toverflow: scroll;\\n\\t\\tgap: 32px;\\n\\t\\talign-content: flex-start;\\n\\t}\\n\\n\\t&__empty {\\n\\t\\tdisplay: flex;\\n\\t\\tflex-direction: column;\\n\\t\\talign-items: center;\\n\\n\\t\\t&__button {\\n\\t\\t\\tmargin-top: 32px;\\n\\t\\t}\\n\\t}\\n}\\n\\n.empty-content-with-illustration ::v-deep .empty-content__icon {\\n\\twidth: 200px;\\n\\theight: 200px;\\n\\n\\tsvg {\\n\\t\\twidth: 200px;\\n\\t\\theight: 200px;\\n\\t}\\n}\\n\"],\"sourceRoot\":\"\"}]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","<!--\n - @copyright Copyright (c) 2020 Corentin Mors\n -\n - @license AGPL-3.0-or-later\n -\n - @author Corentin Mors <medias@pixelswap.fr>\n -\n - This program is free software: you can redistribute it and/or modify\n - it under the terms of the GNU Affero General Public License as\n - published by the Free Software Foundation, either version 3 of the\n - License, or (at your option) any later version.\n -\n - This program is distributed in the hope that it will be useful,\n - but WITHOUT ANY WARRANTY; without even the implied warranty of\n - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n - GNU Affero General Public License for more details.\n -\n - You should have received a copy of the GNU Affero General Public License\n - along with this program. If not, see <http://www.gnu.org/licenses/>.\n -\n -->\n\n<template>\n\t<div class=\"loader\">\n\t\t<slot name=\"icon\">\n\t\t\t<span class=\"icon-loading\" />\n\t\t</slot>\n\t</div>\n</template>\n\n<script>\nexport default {\n\tname: 'Loader',\n}\n</script>\n\n<style lang=\"scss\">\n.loader {\n\tdisplay: grid;\n\theight: 60px;\n}\n</style>\n","import mod from \"-!../../node_modules/babel-loader/lib/index.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Loader.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/babel-loader/lib/index.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Loader.vue?vue&type=script&lang=js&\"","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js??clonedRuleSet-2[0].rules[0].use[3]!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Loader.vue?vue&type=style&index=0&lang=scss&\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\n\n options.insert = insertFn.bind(null, \"head\");\n \noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js??clonedRuleSet-2[0].rules[0].use[3]!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Loader.vue?vue&type=style&index=0&lang=scss&\";\n export default content && content.locals ? content.locals : undefined;\n","import { render, staticRenderFns } from \"./Loader.vue?vue&type=template&id=7bbb2dd6&\"\nimport script from \"./Loader.vue?vue&type=script&lang=js&\"\nexport * from \"./Loader.vue?vue&type=script&lang=js&\"\nimport style0 from \"./Loader.vue?vue&type=style&index=0&lang=scss&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:\"loader\"},[_vm._t(\"icon\",function(){return [_c('span',{staticClass:\"icon-loading\"})]})],2)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return (_vm.errorFetchingFaces)?_c('EmptyContent',[_vm._v(\"\\n\\t\"+_vm._s(_vm.t('photos', 'An error occurred'))+\"\\n\")]):_c('div',{staticClass:\"faces\"},[(_vm.loadingFaces)?_c('Loader'):_vm._e(),_vm._v(\" \"),(_vm.noFaces && !_vm.loadingFaces)?_c('div',{staticClass:\"faces__empty\"},[_c('EmptyContent',{staticClass:\"empty-content-with-illustration\",scopedSlots:_vm._u([{key:\"icon\",fn:function(){return [_c('AccountBoxMultipleOutline')]},proxy:true},{key:\"desc\",fn:function(){return [_vm._v(\"\\n\\t\\t\\t\\t\"+_vm._s(_vm.t('photos', 'This might take some time depending on the size of your photo library.'))+\"\\n\\t\\t\\t\")]},proxy:true}],null,false,3796275108)},[_vm._v(\" \"),_vm._v(\"\\n\\t\\t\\t\"+_vm._s(_vm.t('photos', 'Recognized people will show up here'))+\"\\n\\t\\t\")])],1):(!_vm.noFaces)?_c('div',{staticClass:\"faces__list\"},_vm._l((_vm.orderedFaces),function(face){return _c('FaceCover',{key:face.basename,attrs:{\"base-name\":face.basename}})}),1):_vm._e()],1)}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","<!--\n - @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>\n - @copyright Copyright (c) 2022 Marcel Klehr <mklehr@gmx.net>\n -\n - @author Louis Chemineau <louis@chmn.me>\n - @author Marcel Klehr <mklehr@gmx.net>\n -\n - @license AGPL-3.0-or-later\n -\n - This program is free software: you can redistribute it and/or modify\n - it under the terms of the GNU Affero General Public License as\n - published by the Free Software Foundation, either version 3 of the\n - License, or (at your option) any later version.\n -\n - This program is distributed in the hope that it will be useful,\n - but WITHOUT ANY WARRANTY; without even the implied warranty of\n - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n - GNU Affero General Public License for more details.\n -\n - You should have received a copy of the GNU Affero General Public License\n - along with this program. If not, see <http://www.gnu.org/licenses/>.\n -\n -->\n\n<template>\n\t<router-link class=\"face-cover\" :to=\"`/faces/${baseName}`\">\n\t\t<div class=\"face-cover__crop-container\">\n\t\t\t<img ref=\"image\"\n\t\t\t\tclass=\"face-cover__image\"\n\t\t\t\t:src=\"coverUrl\"\n\t\t\t\t:style=\"coverDimensions\">\n\t\t</div>\n\t\t<div class=\"face-cover__details\">\n\t\t\t<div class=\"face-cover__details__first-line\">\n\t\t\t\t<h2 :class=\"{'face-cover__details__name': true, 'hidden-visually': baseName.match(/^[0-9]+$/)}\">\n\t\t\t\t\t{{ baseName }}\n\t\t\t\t</h2>\n\t\t\t</div>\n\t\t\t<div v-if=\"facesFiles[baseName]\" class=\"face-cover__details__second-line\">\n\t\t\t\t{{ n('photos', '%n photos', '%n photos', facesFiles[baseName].length,) }}\n\t\t\t</div>\n\t\t</div>\n\t</router-link>\n</template>\n\n<script>\nimport { mapGetters } from 'vuex'\nimport { generateUrl } from '@nextcloud/router'\nimport FetchFacesMixin from '../mixins/FetchFacesMixin.js'\nimport FaceCoverMixin from '../mixins/FaceCoverMixin.js'\n\nexport default {\n\tname: 'FaceCover',\n\n\tmixins: [\n\t\tFetchFacesMixin,\n\t\tFaceCoverMixin,\n\t],\n\n\tprops: {\n\t\tbaseName: {\n\t\t\ttype: String,\n\t\t\trequired: true,\n\t\t},\n\t},\n\n\tcomputed: {\n\t\t...mapGetters([\n\t\t\t'files',\n\t\t\t'faces',\n\t\t\t'facesFiles',\n\t\t]),\n\n\t\t/**\n\t\t * @return {Face}\n\t\t */\n\t\tface() {\n\t\t\treturn this.faces[this.baseName]\n\t\t},\n\n\t\t/**\n\t\t * @return {string}\n\t\t */\n\t\tcoverUrl() {\n\t\t\tif (!this.cover) {\n\t\t\t\treturn ''\n\t\t\t}\n\n\t\t\treturn generateUrl(`/core/preview?fileId=${this.cover.fileid}&x=${512}&y=${512}&forceIcon=0&a=1`)\n\t\t},\n\n\t\tcover() {\n\t\t\treturn this.getFaceCover(this.face.basename)\n\t\t},\n\n\t\tcoverDimensions() {\n\t\t\tif (!this.cover) return {}\n\t\t\treturn this.getCoverStyle(this.face.basename)\n\t\t},\n\t},\n\n\tasync beforeMount() {\n\t\tawait this.fetchFiles()\n\t},\n\n\tbeforeDestroy() {\n\t\tthis.cancelFilesRequest('Changed view')\n\t},\n\n\tmethods: {\n\t\tasync fetchFiles() {\n\t\t\tawait this.fetchFaceContent(this.face.basename)\n\t\t},\n\t},\n}\n</script>\n\n<style lang=\"scss\" scoped>\n.face-cover {\n\tdisplay: flex;\n\tflex-direction: column;\n\tpadding: 10px;\n\tborder-radius: var(--border-radius-large);\n\n\t&__crop-container {\n\t\toverflow: hidden;\n\t\twidth: 250px;\n\t\theight: 250px;\n\t\tborder-radius: 250px;\n\t\tposition: relative;\n\t\tbackground: var(--color-background-darker);\n\t\t--photos-face-width: 250px;\n\n\t\t@media only screen and (max-width: 1020px) {\n\t\t\twidth: 95px;\n\t\t\theight: 95px;\n\t\t\t--photos-face-width: 95px;\n\t\t}\n\t}\n\n\t&:hover, &:focus {\n\t\tbackground: var(--color-background-hover);\n\t}\n\n\t&__details {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\twidth: 250px;\n\t\tmargin-top: 4px;\n\t\ttext-align: center;\n\n\t\t@media only screen and (max-width: 1020px) {\n\t\t\twidth: 95px;\n\t\t}\n\n\t\t&__first-line {\n\t\t\tdisplay: flex;\n\t\t\theight: 2em;\n\t\t\toverflow: hidden;\n\t\t\ttext-overflow: ellipsis;\n\t\t}\n\n\t\t&__second-line {\n\t\t\tcolor: var(--color-text-maxcontrast);\n\t\t}\n\n\t\t&__name {\n\t\t\tflex-grow: 1;\n\t\t\tmargin: 0;\n\t\t}\n\t}\n}\n</style>\n","import mod from \"-!../../node_modules/babel-loader/lib/index.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./FaceCover.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/babel-loader/lib/index.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./FaceCover.vue?vue&type=script&lang=js&\"","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js??clonedRuleSet-2[0].rules[0].use[3]!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./FaceCover.vue?vue&type=style&index=0&id=2a995501&lang=scss&scoped=true&\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\n\n options.insert = insertFn.bind(null, \"head\");\n \noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js??clonedRuleSet-2[0].rules[0].use[3]!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./FaceCover.vue?vue&type=style&index=0&id=2a995501&lang=scss&scoped=true&\";\n export default content && content.locals ? content.locals : undefined;\n","<!--\n - @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>\n - @copyright Copyright (c) 2022 Marcel Klehr <mklehr@gmx.net>\n -\n - @author Louis Chemineau <louis@chmn.me>\n - @author Marcel Klehr <mklehr@gmx.net>\n -\n - @license AGPL-3.0-or-later\n -\n - This program is free software: you can redistribute it and/or modify\n - it under the terms of the GNU Affero General Public License as\n - published by the Free Software Foundation, either version 3 of the\n - License, or (at your option) any later version.\n -\n - This program is distributed in the hope that it will be useful,\n - but WITHOUT ANY WARRANTY; without even the implied warranty of\n - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n - GNU Affero General Public License for more details.\n -\n - You should have received a copy of the GNU Affero General Public License\n - along with this program. If not, see <http://www.gnu.org/licenses/>.\n -\n -->\n<template>\n\t<!-- Errors handlers-->\n\t<EmptyContent v-if=\"errorFetchingFaces\">\n\t\t{{ t('photos', 'An error occurred') }}\n\t</EmptyContent>\n\n\t<!-- Face list -->\n\t<div v-else class=\"faces\">\n\t\t<Loader v-if=\"loadingFaces\" />\n\n\t\t<!-- No faces -->\n\t\t<div v-if=\"noFaces && !loadingFaces\" class=\"faces__empty\">\n\t\t\t<EmptyContent class=\"empty-content-with-illustration\">\n\t\t\t\t<template #icon>\n\t\t\t\t\t<AccountBoxMultipleOutline />\n\t\t\t\t</template>\n\t\t\t\t<template #desc>\n\t\t\t\t\t{{ t('photos', 'This might take some time depending on the size of your photo library.') }}\n\t\t\t\t</template>\n\t\t\t\t{{ t('photos', 'Recognized people will show up here') }}\n\t\t\t</EmptyContent>\n\t\t</div>\n\n\t\t<div v-else-if=\"!noFaces\" class=\"faces__list\">\n\t\t\t<FaceCover v-for=\"face in orderedFaces\"\n\t\t\t\t:key=\"face.basename\"\n\t\t\t\t:base-name=\"face.basename\" />\n\t\t</div>\n\t</div>\n</template>\n\n<script>\nimport { EmptyContent } from '@nextcloud/vue'\nimport AccountBoxMultipleOutline from 'vue-material-design-icons/AccountBoxMultipleOutline'\n\nimport FetchFacesMixin from '../mixins/FetchFacesMixin.js'\nimport Loader from '../components/Loader.vue'\nimport FaceCover from '../components/FaceCover.vue'\nimport { mapGetters } from 'vuex'\n\nexport default {\n\tname: 'Faces',\n\tcomponents: {\n\t\tFaceCover,\n\t\tEmptyContent,\n\t\tLoader,\n\t\tAccountBoxMultipleOutline,\n\t},\n\n\tmixins: [\n\t\tFetchFacesMixin,\n\t],\n\n\tcomputed: {\n\t\t...mapGetters([\n\t\t\t'facesFiles',\n\t\t]),\n\n\t\t/**\n\t\t * @return {boolean} Whether the list of face is empty or not.\n\t\t */\n\t\tnoFaces() {\n\t\t\treturn Object.keys(this.faces).length === 0\n\t\t},\n\n\t\torderedFaces() {\n\t\t\treturn Object.values(this.faces).sort((a, b) => {\n\t\t\t\tif (!this.facesFiles[b.basename] || !this.facesFiles[a.basename]) {\n\t\t\t\t\treturn 0\n\t\t\t\t}\n\t\t\t\treturn this.facesFiles[b.basename].length - this.facesFiles[a.basename].length\n\t\t\t})\n\t\t},\n\t},\n}\n</script>\n<style lang=\"scss\" scoped>\n.faces {\n\tdisplay: flex;\n\tflex-direction: column;\n\theight: calc(100vh - var(--header-height));\n\tpadding-left: 64px;\n\n\t@media only screen and (max-width: 1020px) {\n\t\tpadding: 0;\n\t}\n\n\t&__header {\n\t\tdisplay: flex;\n\t\tmin-height: 60px;\n\t\talign-items: center;\n\n\t\tbutton {\n\t\t\tmargin-right: 32px;\n\t\t}\n\t}\n\n\t&__list {\n\t\tpadding-top: 24px;\n\t\tpadding-bottom: 32px;\n\t\tflex-grow: 1;\n\t\tdisplay: flex;\n\t\tflex-wrap: wrap;\n\t\toverflow: scroll;\n\t\tgap: 32px;\n\t\talign-content: flex-start;\n\t}\n\n\t&__empty {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\n\t\t&__button {\n\t\t\tmargin-top: 32px;\n\t\t}\n\t}\n}\n\n.empty-content-with-illustration ::v-deep .empty-content__icon {\n\twidth: 200px;\n\theight: 200px;\n\n\tsvg {\n\t\twidth: 200px;\n\t\theight: 200px;\n\t}\n}\n</style>\n","import mod from \"-!../../node_modules/babel-loader/lib/index.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Faces.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/babel-loader/lib/index.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Faces.vue?vue&type=script&lang=js&\"","import { render, staticRenderFns } from \"./FaceCover.vue?vue&type=template&id=2a995501&scoped=true&\"\nimport script from \"./FaceCover.vue?vue&type=script&lang=js&\"\nexport * from \"./FaceCover.vue?vue&type=script&lang=js&\"\nimport style0 from \"./FaceCover.vue?vue&type=style&index=0&id=2a995501&lang=scss&scoped=true&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"2a995501\",\n null\n \n)\n\nexport default component.exports","var render = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('router-link',{staticClass:\"face-cover\",attrs:{\"to\":(\"/faces/\" + _vm.baseName)}},[_c('div',{staticClass:\"face-cover__crop-container\"},[_c('img',{ref:\"image\",staticClass:\"face-cover__image\",style:(_vm.coverDimensions),attrs:{\"src\":_vm.coverUrl}})]),_vm._v(\" \"),_c('div',{staticClass:\"face-cover__details\"},[_c('div',{staticClass:\"face-cover__details__first-line\"},[_c('h2',{class:{'face-cover__details__name': true, 'hidden-visually': _vm.baseName.match(/^[0-9]+$/)}},[_vm._v(\"\\n\\t\\t\\t\\t\"+_vm._s(_vm.baseName)+\"\\n\\t\\t\\t\")])]),_vm._v(\" \"),(_vm.facesFiles[_vm.baseName])?_c('div',{staticClass:\"face-cover__details__second-line\"},[_vm._v(\"\\n\\t\\t\\t\"+_vm._s(_vm.n('photos', '%n photos', '%n photos', _vm.facesFiles[_vm.baseName].length))+\"\\n\\t\\t\")]):_vm._e()])])}\nvar staticRenderFns = []\n\nexport { render, staticRenderFns }","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js??clonedRuleSet-2[0].rules[0].use[3]!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Faces.vue?vue&type=style&index=0&id=40b27884&lang=scss&scoped=true&\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\n\n options.insert = insertFn.bind(null, \"head\");\n \noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js??clonedRuleSet-2[0].rules[0].use[3]!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Faces.vue?vue&type=style&index=0&id=40b27884&lang=scss&scoped=true&\";\n export default content && content.locals ? content.locals : undefined;\n","import { render, staticRenderFns } from \"./Faces.vue?vue&type=template&id=40b27884&scoped=true&\"\nimport script from \"./Faces.vue?vue&type=script&lang=js&\"\nexport * from \"./Faces.vue?vue&type=script&lang=js&\"\nimport style0 from \"./Faces.vue?vue&type=style&index=0&id=40b27884&lang=scss&scoped=true&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n \"40b27884\",\n null\n \n)\n\nexport default component.exports"],"names":["name","computed","mapGetters","methods","getFaceCover","faceName","this","facesFiles","slice","map","fileId","files","file","faceDetections","JSON","parse","he","sort","a","b","find","d","title","width","length","getCoverStyle","cover","detection","zoom","Math","max","horizontalCenterOfFace","x","verticalCenterOfFace","y","height","transform","transformOrigin","data","errorFetchingFaces","loadingFaces","errorFetchingFiles","loadingFiles","cancelFacesRequest","cancelFilesRequest","beforeMount","fetchFaces","beforeDestroy","mapActions","Object","keys","faces","cancelableRequest","client","request","cancel","getCurrentUser","uid","$store","dispatch","logger","response","status","t","showError","fetchFaceContent","force","DavRequest","details","fetchedFiles","genFileInfo","filename","realpath","replace","fileIds","fileid","appendFiles","commit","fileIdsToAdd","props","cancelToken","axios","url","options","assign","token","___CSS_LOADER_EXPORT___","push","module","id","styleTagTransform","setAttributes","insert","domAPI","insertStyleElement","_vm","_h","$createElement","_c","_self","staticClass","_t","attrs","baseName","ref","style","coverUrl","_v","class","match","_s","n","_e","noFaces","scopedSlots","_u","key","fn","proxy","_l","face","basename"],"sourceRoot":""}