123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982 |
- <template lang="pug">
- q-layout.fileman(view='hHh lpR lFr', container)
- q-header.card-header
- q-toolbar(dark)
- q-icon(name='img:/_assets/icons/fluent-folder.svg', left, size='md')
- span {{t(`fileman.title`)}}
- q-toolbar(dark)
- q-input(
- dark
- v-model='state.search'
- standout='bg-white text-dark'
- dense
- ref='searchField'
- style='width: 100%;'
- label='Search folder...'
- :debounce='500'
- )
- template(v-slot:prepend)
- q-icon(name='las la-search')
- template(v-slot:append)
- q-icon.cursor-pointer(
- name='las la-times'
- @click='state.search=``'
- v-if='state.search.length > 0'
- :color='$q.dark.isActive ? `blue` : `grey-4`'
- )
- q-toolbar(dark)
- q-space
- q-btn(
- flat
- dense
- no-caps
- color='red-3'
- :aria-label='t(`common.actions.close`)'
- icon='las la-times'
- @click='close'
- )
- q-tooltip(anchor='bottom middle', self='top middle') {{t(`common.actions.close`)}}
- q-drawer.fileman-left(:model-value='true', :width='350')
- .q-px-md.q-pb-sm
- tree(
- ref='treeComp'
- :nodes='state.treeNodes'
- :roots='state.treeRoots'
- v-model:selected='state.currentFolderId'
- @lazy-load='treeLazyLoad'
- :use-lazy-load='true'
- @context-action='treeContextAction'
- :display-mode='state.displayMode'
- )
- q-drawer.fileman-right(:model-value='$q.screen.gt.md', :width='350', side='right')
- .q-pa-md
- template(v-if='currentFileDetails')
- q-img.rounded-borders.q-mb-md(
- src='/_assets/illustrations/fileman-page.svg'
- width='100%'
- fit='cover'
- :ratio='16/10'
- no-spinner
- )
- .fileman-details-row(
- v-for='item of currentFileDetails.items'
- )
- label {{item.label}}
- span {{item.value}}
- q-page-container
- q-page.fileman-center
- //- TOOLBAR -----------------------------------------------------
- q-toolbar.fileman-toolbar
- template(v-if='state.isUploading')
- .fileman-progressbar
- div(:style='`width: ` + state.uploadPercentage + `%`') {{state.uploadPercentage}}%
- q-btn.acrylic-btn.q-ml-sm(
- flat
- dense
- no-caps
- color='negative'
- :aria-label='t(`common.actions.cancel`)'
- icon='las la-square'
- @click='uploadCancel'
- v-if='state.uploadPercentage < 100'
- )
- template(v-else)
- q-space
- q-btn.q-mr-sm(
- flat
- dense
- no-caps
- color='grey'
- :aria-label='t(`fileman.viewOptions`)'
- icon='las la-th-list'
- @click=''
- )
- q-tooltip(anchor='bottom middle', self='top middle') {{t(`fileman.viewOptions`)}}
- q-menu(
- transition-show='jump-down'
- transition-hide='jump-up'
- anchor='bottom right'
- self='top right'
- )
- q-card.q-pa-sm
- .text-center
- small.text-grey {{t(`fileman.viewOptions`)}}
- q-list(dense)
- q-separator.q-my-sm
- q-item(clickable)
- q-item-section(side)
- q-icon(name='las la-list', color='grey', size='xs')
- q-item-section.q-pr-sm Browse using...
- q-item-section(side)
- q-icon(name='las la-angle-right', color='grey', size='xs')
- q-menu(
- anchor='top end'
- self='top start'
- )
- q-list.q-pa-sm(dense)
- q-item(clickable, @click='state.displayMode = `path`')
- q-item-section(side)
- q-icon(
- :name='state.displayMode === `path` ? `las la-check-circle` : `las la-circle`'
- :color='state.displayMode === `path` ? `positive` : `grey`'
- size='xs'
- )
- q-item-section.q-pr-sm Browse Using Paths
- q-item(clickable, @click='state.displayMode = `title`')
- q-item-section(side)
- q-icon(
- :name='state.displayMode === `title` ? `las la-check-circle` : `las la-circle`'
- :color='state.displayMode === `title` ? `positive` : `grey`'
- size='xs'
- )
- q-item-section.q-pr-sm Browse Using Titles
- q-item(clickable, @click='state.isCompact = !state.isCompact')
- q-item-section(side)
- q-icon(
- :name='state.isCompact ? `las la-check-square` : `las la-stop`'
- :color='state.isCompact ? `positive` : `grey`'
- size='xs'
- )
- q-item-section.q-pr-sm Compact List
- q-item(clickable, @click='state.shouldShowFolders = !state.shouldShowFolders')
- q-item-section(side)
- q-icon(
- :name='state.shouldShowFolders ? `las la-check-square` : `las la-stop`'
- :color='state.shouldShowFolders ? `positive` : `grey`'
- size='xs'
- )
- q-item-section.q-pr-sm Show Folders
- q-btn.q-mr-sm(
- flat
- dense
- no-caps
- color='grey'
- :aria-label='t(`common.actions.refresh`)'
- icon='las la-redo-alt'
- @click='reloadFolder(state.currentFolderId)'
- )
- q-tooltip(anchor='bottom middle', self='top middle') {{t(`common.actions.refresh`)}}
- q-separator.q-mr-sm(inset, vertical)
- q-btn.q-mr-sm(
- flat
- dense
- no-caps
- color='blue'
- :label='t(`common.actions.new`)'
- :aria-label='t(`common.actions.new`)'
- icon='las la-plus-circle'
- @click=''
- )
- new-menu(
- :hide-asset-btn='true'
- :show-new-folder='true'
- @new-folder='() => newFolder(state.currentFolderId)'
- )
- q-btn(
- flat
- dense
- no-caps
- color='positive'
- :label='t(`common.actions.upload`)'
- :aria-label='t(`common.actions.upload`)'
- icon='las la-cloud-upload-alt'
- @click='uploadFile'
- )
- .fileman-emptylist(v-if='files.length < 1')
- template(v-if='state.fileListLoading')
- q-spinner.q-mr-sm(color='primary', size='xs', :thickness='3')
- span.text-primary Loading...
- template(v-else)
- q-icon.q-mr-sm(name='las la-exclamation-triangle', size='sm')
- span This folder is empty.
- q-list.fileman-filelist(v-else)
- q-item(
- v-for='item of files'
- :key='item.id'
- clickable
- active-class='active'
- :active='item.id === state.currentFileId'
- @click.native='selectItem(item)'
- @dblclick.native='openItem(item)'
- )
- q-item-section.fileman-filelist-icon(avatar)
- q-icon(:name='item.icon', :size='state.isCompact ? `md` : `xl`')
- q-item-section.fileman-filelist-label
- q-item-label {{item.title}}
- q-item-label(caption, v-if='!state.isCompact') {{item.caption}}
- q-item-section.fileman-filelist-side(side, v-if='item.side')
- .text-caption {{item.side}}
- //- RIGHT-CLICK MENU
- q-menu(
- touch-position
- context-menu
- auto-close
- transition-show='jump-down'
- transition-hide='jump-up'
- )
- q-card.q-pa-sm
- q-list(dense, style='min-width: 150px;')
- q-item(clickable, v-if='item.type === `page`')
- q-item-section(side)
- q-icon(name='las la-edit', color='orange')
- q-item-section Edit
- q-item(clickable, v-if='item.type !== `folder`', @click='openItem(item)')
- q-item-section(side)
- q-icon(name='las la-eye', color='primary')
- q-item-section View
- q-item(clickable, v-if='item.type !== `folder`', @click='copyItemURL(item)')
- q-item-section(side)
- q-icon(name='las la-clipboard', color='primary')
- q-item-section Copy URL
- q-item(clickable)
- q-item-section(side)
- q-icon(name='las la-copy', color='teal')
- q-item-section Duplicate...
- q-item(clickable)
- q-item-section(side)
- q-icon(name='las la-redo', color='teal')
- q-item-section Rename...
- q-item(clickable)
- q-item-section(side)
- q-icon(name='las la-arrow-right', color='teal')
- q-item-section Move to...
- q-item(clickable, @click='delItem(item)')
- q-item-section(side)
- q-icon(name='las la-trash-alt', color='negative')
- q-item-section.text-negative Delete
- q-footer
- q-bar.fileman-path
- small.text-caption.text-grey-7 {{folderPath}}
- input(
- type='file'
- ref='fileIpt'
- multiple
- @change='uploadNewFiles'
- style='display: none'
- )
- </template>
- <script setup>
- import { useI18n } from 'vue-i18n'
- import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
- import { filesize } from 'filesize'
- import { useQuasar } from 'quasar'
- import { DateTime } from 'luxon'
- import { cloneDeep, find } from 'lodash-es'
- import { useRoute, useRouter } from 'vue-router'
- import gql from 'graphql-tag'
- import Fuse from 'fuse.js/dist/fuse.basic.esm'
- import NewMenu from './PageNewMenu.vue'
- import Tree from './TreeNav.vue'
- import fileTypes from '../helpers/fileTypes'
- import { usePageStore } from 'src/stores/page'
- import { useSiteStore } from 'src/stores/site'
- import FolderCreateDialog from 'src/components/FolderCreateDialog.vue'
- import FolderDeleteDialog from 'src/components/FolderDeleteDialog.vue'
- // QUASAR
- const $q = useQuasar()
- // STORES
- const pageStore = usePageStore()
- const siteStore = useSiteStore()
- // ROUTER
- const router = useRouter()
- const route = useRoute()
- // I18N
- const { t } = useI18n()
- // DATA
- const state = reactive({
- loading: 0,
- search: '',
- currentFolderId: null,
- currentFileId: null,
- treeNodes: {},
- treeRoots: [],
- displayMode: 'title',
- isCompact: false,
- shouldShowFolders: true,
- isUploading: false,
- shouldCancelUpload: false,
- uploadPercentage: 0,
- fileList: [],
- fileListLoading: false
- })
- // REFS
- const fileIpt = ref(null)
- const treeComp = ref(null)
- // COMPUTED
- const folderPath = computed(() => {
- if (!state.currentFolderId) {
- return '/'
- } else {
- const folderNode = state.treeNodes[state.currentFolderId] ?? {}
- return folderNode.folderPath ? `/${folderNode.folderPath}/${folderNode.fileName}/` : `/${folderNode.fileName}/`
- }
- })
- const filteredFiles = computed(() => {
- if (state.search) {
- const fuse = new Fuse(state.fileList, {
- keys: [
- 'title',
- 'fileName'
- ]
- })
- return fuse.search(state.search).map(n => n.item)
- } else {
- return state.fileList
- }
- })
- const files = computed(() => {
- return filteredFiles.value.filter(f => {
- console.info(f)
- // -> Show Folders Filter
- if (f.type === 'folder' && !state.shouldShowFolders) {
- return false
- }
- return true
- }).map(f => {
- switch (f.type) {
- case 'folder': {
- f.icon = fileTypes.folder.icon
- f.caption = t('fileman.folderChildrenCount', f.children, { count: f.children })
- break
- }
- case 'page': {
- f.icon = fileTypes.page.icon
- f.caption = t(`fileman.${f.pageType}PageType`)
- break
- }
- case 'asset': {
- f.icon = fileTypes[f.fileType]?.icon ?? ''
- f.side = filesize(f.fileSize)
- if (fileTypes[f.fileType]) {
- f.caption = t(`fileman.${f.fileType}FileType`)
- } else {
- f.caption = t('fileman.unknownFileType', { type: f.fileType.toUpperCase() })
- }
- break
- }
- }
- return f
- })
- })
- const currentFileDetails = computed(() => {
- if (state.currentFileId) {
- const item = find(state.fileList, ['id', state.currentFileId])
- if (item.type === 'folder') {
- return null
- }
- const items = [
- {
- label: t('fileman.detailsTitle'),
- value: item.title
- }
- ]
- switch (item.type) {
- case 'page': {
- items.push({
- label: t('fileman.detailsPageType'),
- value: t(`fileman.${item.pageType}PageType`)
- })
- items.push({
- label: t('fileman.detailsPageEditor'),
- value: item.pageType
- })
- items.push({
- label: t('fileman.detailsPageUpdated'),
- value: DateTime.fromISO(item.updatedAt).toFormat('yyyy-MM-dd \'at\' h:mm ZZZZ')
- })
- items.push({
- label: t('fileman.detailsPageCreated'),
- value: DateTime.fromISO(item.updatedAt).toFormat('yyyy-MM-dd \'at\' h:mm ZZZZ')
- })
- break
- }
- case 'asset': {
- items.push({
- label: t('fileman.detailsAssetType'),
- value: fileTypes[item.fileType] ? t(`fileman.${item.fileType}FileType`) : t('fileman.unknownFileType', { type: item.fileType.toUpperCase() })
- })
- items.push({
- label: t('fileman.detailsAssetSize'),
- value: filesize(item.fileSize)
- })
- break
- }
- }
- return {
- thumbnail: '',
- items
- }
- } else {
- return null
- }
- })
- // WATCHERS
- watch(() => state.currentFolderId, async (newValue) => {
- await loadTree(newValue)
- })
- // METHODS
- function close () {
- siteStore.overlay = null
- }
- async function treeLazyLoad (nodeId, { done, fail }) {
- await loadTree(nodeId, ['folder'])
- done()
- }
- async function loadTree (parentId, types) {
- if (!parentId) {
- parentId = null
- }
- if (parentId === state.currentFolderId) {
- state.fileListLoading = true
- state.currentFileId = null
- state.fileList = []
- }
- try {
- const resp = await APOLLO_CLIENT.query({
- query: gql`
- query loadTree (
- $siteId: UUID!
- $parentId: UUID
- $types: [TreeItemType]
- ) {
- tree (
- siteId: $siteId
- parentId: $parentId
- types: $types
- ) {
- __typename
- ... on TreeItemFolder {
- id
- folderPath
- fileName
- title
- childrenCount
- }
- ... on TreeItemPage {
- id
- folderPath
- fileName
- title
- createdAt
- updatedAt
- editor
- }
- ... on TreeItemAsset {
- id
- folderPath
- fileName
- title
- createdAt
- updatedAt
- fileSize
- }
- }
- }
- `,
- variables: {
- siteId: siteStore.id,
- parentId,
- types
- },
- fetchPolicy: 'network-only'
- })
- const items = cloneDeep(resp?.data?.tree)
- if (items?.length > 0) {
- const newTreeRoots = []
- for (const item of items) {
- switch (item.__typename) {
- case 'TreeItemFolder': {
- // -> Tree Nodes
- if (!state.treeNodes[item.id]) {
- state.treeNodes[item.id] = {
- folderPath: item.folderPath,
- fileName: item.fileName,
- title: item.title,
- children: state.treeNodes[item.id]?.children ?? []
- }
- }
- // -> Set Ancestors / Tree Roots
- if (item.folderPath) {
- if (!state.treeNodes[parentId].children.includes(item.id)) {
- state.treeNodes[parentId].children.push(item.id)
- }
- } else {
- newTreeRoots.push(item.id)
- }
- // -> File List
- if (parentId === state.currentFolderId) {
- state.fileList.push({
- id: item.id,
- type: 'folder',
- title: item.title,
- fileName: item.fileName,
- children: 0
- })
- }
- break
- }
- case 'TreeItemAsset': {
- if (parentId === state.currentFolderId) {
- state.fileList.push({
- id: item.id,
- type: 'asset',
- title: item.title,
- fileType: 'pdf',
- fileSize: 19000,
- folderPath: item.folderPath,
- fileName: item.fileName
- })
- }
- break
- }
- case 'TreeItemPage': {
- if (parentId === state.currentFolderId) {
- state.fileList.push({
- id: item.id,
- type: 'page',
- title: item.title,
- pageType: 'markdown',
- updatedAt: '2022-11-24T18:27:00Z',
- folderPath: item.folderPath,
- fileName: item.fileName
- })
- }
- break
- }
- }
- }
- if (newTreeRoots.length > 0) {
- state.treeRoots = newTreeRoots
- }
- }
- } catch (err) {
- $q.notify({
- type: 'negative',
- message: 'Failed to load folder tree.',
- caption: err.message
- })
- }
- if (parentId === state.currentFolderId) {
- nextTick(() => {
- state.fileListLoading = false
- })
- }
- if (parentId) {
- treeComp.value.setLoaded(parentId)
- }
- }
- function treeContextAction (nodeId, action) {
- switch (action) {
- case 'newFolder': {
- newFolder(nodeId)
- break
- }
- case 'del': {
- delFolder(nodeId)
- break
- }
- }
- }
- // --------------------------------------
- // FOLDER METHODS
- // --------------------------------------
- function newFolder (parentId) {
- $q.dialog({
- component: FolderCreateDialog,
- componentProps: {
- parentId
- }
- }).onOk(() => {
- loadTree(parentId)
- })
- }
- function delFolder (folderId, mustReload = false) {
- $q.dialog({
- component: FolderDeleteDialog,
- componentProps: {
- folderId,
- folderName: state.treeNodes[folderId].title
- }
- }).onOk(() => {
- for (const nodeId in state.treeNodes) {
- if (state.treeNodes[nodeId].children.includes(folderId)) {
- state.treeNodes[nodeId].children = state.treeNodes[nodeId].children.filter(c => c !== folderId)
- }
- }
- delete state.treeNodes[folderId]
- if (state.treeRoots.includes(folderId)) {
- state.treeRoots = state.treeRoots.filter(n => n !== folderId)
- }
- if (mustReload) {
- loadTree(state.currentFolderId, null)
- }
- })
- }
- function reloadFolder (folderId) {
- loadTree(folderId, null)
- treeComp.value.resetLoaded()
- }
- // --------------------------------------
- // UPLOAD METHODS
- // --------------------------------------
- function uploadFile () {
- fileIpt.value.click()
- }
- async function uploadNewFiles () {
- if (!fileIpt.value.files?.length) {
- return
- }
- console.info(fileIpt.value.files)
- state.isUploading = true
- state.uploadPercentage = 0
- state.loading++
- nextTick(() => {
- setTimeout(async () => {
- try {
- const totalFiles = fileIpt.value.files.length
- let idx = 0
- for (const fileToUpload of fileIpt.value.files) {
- idx++
- state.uploadPercentage = totalFiles > 1 ? Math.round(idx / totalFiles * 100) : 90
- const resp = await APOLLO_CLIENT.mutate({
- mutation: gql`
- mutation uploadAssets (
- $siteId: UUID!
- $files: [Upload!]!
- ) {
- uploadAssets (
- siteId: $siteId
- files: $files
- ) {
- operation {
- succeeded
- message
- }
- }
- }
- `,
- variables: {
- siteId: siteStore.id,
- files: [fileToUpload]
- }
- })
- if (!resp?.data?.uploadAssets?.operation?.succeeded) {
- throw new Error(resp?.data?.uploadAssets?.operation?.message || 'An unexpected error occured.')
- }
- }
- state.uploadPercentage = 100
- $q.notify({
- type: 'positive',
- message: t('fileman.uploadSuccess')
- })
- } catch (err) {
- $q.notify({
- type: 'negative',
- message: 'Failed to upload file.',
- caption: err.message
- })
- }
- state.loading--
- fileIpt.value.value = null
- setTimeout(() => {
- state.isUploading = false
- state.uploadPercentage = 0
- }, 1500)
- }, 400)
- })
- }
- function uploadCancel () {
- state.isUploading = false
- state.uploadPercentage = 0
- }
- // --------------------------------------
- // ITEM LIST ACTIONS
- // --------------------------------------
- function selectItem (item) {
- if (item.type === 'folder') {
- state.currentFolderId = item.id
- treeComp.value.setOpened(item.id)
- } else {
- state.currentFileId = item.id
- }
- }
- function openItem (item) {
- switch (item.type) {
- case 'folder': {
- return
- }
- case 'page': {
- const pagePath = item.folderPath ? `${item.folderPath}/${item.fileName}` : item.fileName
- router.push(`/${pagePath}`)
- close()
- break
- }
- case 'asset': {
- // TODO: Open asset
- close()
- break
- }
- }
- }
- async function copyItemURL (item) {
- try {
- switch (item.type) {
- case 'page': {
- const pagePath = item.folderPath ? `${item.folderPath}/${item.fileName}` : item.fileName
- await navigator.clipboard.writeText(`${window.location.origin}/${pagePath}`)
- break
- }
- case 'asset': {
- // TODO: Copy asset URL to clibpard
- break
- }
- default: {
- throw new Error('Invalid Item Type')
- }
- }
- $q.notify({
- type: 'positive',
- message: t('fileman.copyURLSuccess')
- })
- } catch (err) {
- $q.notify({
- type: 'negative',
- message: 'Failed to copy URL to clipboard.',
- caption: err.message
- })
- }
- }
- function delItem (item) {
- switch (item.type) {
- case 'folder': {
- delFolder(item.id, true)
- break
- }
- }
- }
- // MOUNTED
- onMounted(() => {
- loadTree()
- })
- </script>
- <style lang="scss">
- .fileman {
- &-left {
- @at-root .body--light & {
- background-color: $blue-grey-1;
- }
- @at-root .body--dark & {
- background-color: $dark-4;
- }
- }
- &-center {
- @at-root .body--light & {
- background-color: #FFF;
- }
- @at-root .body--dark & {
- background-color: $dark-6;
- }
- }
- &-right {
- @at-root .body--light & {
- background-color: $grey-1;
- }
- @at-root .body--dark & {
- background-color: $dark-5;
- }
- }
- &-toolbar {
- @at-root .body--light & {
- background-color: $grey-1;
- }
- @at-root .body--dark & {
- background-color: $dark-5;
- }
- }
- &-path {
- @at-root .body--light & {
- background-color: $blue-grey-1 !important;
- }
- @at-root .body--dark & {
- background-color: $dark-4 !important;
- }
- }
- &-emptylist {
- padding: 16px;
- font-style: italic;
- display: flex;
- align-items: center;
- @at-root .body--light & {
- color: $grey-6;
- }
- @at-root .body--dark & {
- color: $dark-4;
- }
- }
- &-filelist {
- padding: 8px 12px;
- > .q-item {
- padding: 8px 6px;
- border-radius: 8px;
- &.active {
- background-color: var(--q-primary);
- color: #FFF;
- .fileman-filelist-label .q-item__label--caption {
- color: rgba(255,255,255,.7);
- }
- .fileman-filelist-side .text-caption {
- color: rgba(255,255,255,.7);
- }
- }
- }
- }
- &-details-row {
- display: flex;
- flex-direction: column;
- padding: 5px 0;
- label {
- font-size: .7rem;
- font-weight: 500;
- @at-root .body--light & {
- color: $grey-6;
- }
- @at-root .body--dark & {
- color: $blue-grey-4;
- }
- }
- span {
- font-size: .85rem;
- @at-root .body--light & {
- color: $grey-8;
- }
- @at-root .body--dark & {
- color: $blue-grey-2;
- }
- }
- & + .fileman-details-row {
- margin-top: 5px;
- }
- }
- &-progressbar {
- width: 100%;
- flex: 1;
- height: 12px;
- border-radius: 3px;
- @at-root .body--light & {
- background-color: $blue-grey-2;
- }
- @at-root .body--dark & {
- background-color: $dark-4 !important;
- }
- > div {
- height: 12px;
- background-color: $positive;
- border-radius: 3px 0 0 3px;
- background-image: linear-gradient(
- -45deg,
- rgba(255, 255, 255, 0.3) 25%,
- transparent 25%,
- transparent 50%,
- rgba(255, 255, 255, 0.3) 50%,
- rgba(255, 255, 255, 0.3) 75%,
- transparent 75%,
- transparent
- );
- background-size: 50px 50px;
- background-position: 0 0;
- animation: fileman-progress 2s linear infinite;
- box-shadow: 0 0 5px 0 $positive;
- font-size: 9px;
- letter-spacing: 2px;
- font-weight: 700;
- color: #FFF;
- display: flex;
- justify-content: center;
- align-items: center;
- overflow: hidden;
- transition: all 1s ease;
- }
- }
- }
- @keyframes fileman-progress {
- 0% {
- background-position: 0 0;
- }
- 100% {
- background-position: -50px -50px;
- }
- }
- </style>
|