Skip to content

Commit

Permalink
feat: add component SkeletonLoading
Browse files Browse the repository at this point in the history
Signed-off-by: Luka Trovic <[email protected]>
  • Loading branch information
luka-nextcloud committed Aug 1, 2023
1 parent 5cfac93 commit b982efa
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 9 deletions.
3 changes: 3 additions & 0 deletions src/components/Editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
:has-connection-issue="hasConnectionIssue"
@reconnect="reconnect" />

<SkeletonLoading v-if="!contentLoaded" />
<Wrapper v-if="displayed"
:sync-error="syncError"
:has-connection-issue="hasConnectionIssue"
Expand Down Expand Up @@ -117,10 +118,12 @@ import ContentContainer from './Editor/ContentContainer.vue'
import Status from './Editor/Status.vue'
import MainContainer from './Editor/MainContainer.vue'
import Wrapper from './Editor/Wrapper.vue'
import SkeletonLoading from './SkeletonLoading.vue'
export default {
name: 'Editor',
components: {
SkeletonLoading,
DocumentStatus,
Wrapper,
MainContainer,
Expand Down
6 changes: 0 additions & 6 deletions src/components/Editor/Wrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
<div class="text-editor__wrapper"
:class="{
'has-conflicts': hasSyncCollission,
'icon-loading': !contentLoaded && !hasConnectionIssue,
'is-rich-workspace': $isRichWorkspace,
'is-rich-editor': $isRichEditor,
'show-color-annotations': showAuthorAnnotations
Expand Down Expand Up @@ -159,11 +158,6 @@ export default {
.ProseMirror {
margin-top: 0 !important;
}
&.icon-loading {
.text-editor__main {
opacity: 0.3;
}
}
}
</style>
166 changes: 166 additions & 0 deletions src/components/SkeletonLoading.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
<template>
<div class="placeholder-main placeholder-main-text">
<!-- Placeholder animation -->
<template v-for="(suffix, gradientIndex) in ['-regular', '-reverse']">
<svg :key="'gradient' + suffix" :class="'placeholder-gradient placeholder-gradient' + suffix">
<defs>
<linearGradient :id="'placeholder-gradient' + suffix">
<stop offset="0%" :stop-color="(gradientIndex === 0) ? colorPlaceholderLight : colorPlaceholderDark" />
<stop offset="100%" :stop-color="(gradientIndex === 0) ? colorPlaceholderDark : colorPlaceholderLight" />
</linearGradient>
</defs>
</svg>

<ul :key="'list' + suffix" :class="'placeholder-list placeholder-list' + suffix">
<li v-for="index in count" :key="'placeholder' + suffix + index">
<svg class="text-placeholder"
xmlns="http://www.w3.org/2000/svg"
:fill="'url(#placeholder-gradient' + suffix + ')'">
<rect class="text-placeholder-line-one" :style="textPlaceholderData[0]" />
<rect class="text-placeholder-line-two" :style="textPlaceholderData[1]" />
<rect class="text-placeholder-line-three" :style="textPlaceholderData[2]" />
<rect class="text-placeholder-line-four" :style="textPlaceholderData[3]" />
</svg>
</li>
</ul>
</template>
</div>
</template>

<script>
const bodyStyles = window.getComputedStyle(document.body)
const colorPlaceholderDark = bodyStyles.getPropertyValue('--color-placeholder-dark')
const colorPlaceholderLight = bodyStyles.getPropertyValue('--color-placeholder-light')
export default {
name: 'SkeletonLoading',
props: {
count: {
type: Number,
default: 5,
},
},
setup() {
return {
colorPlaceholderDark,
colorPlaceholderLight,
}
},
computed: {
textPlaceholderData() {
const data = []
for (let i = 0; i < 4; i++) {
// generate random widths
data.push('width: ' + (Math.floor(Math.random() * 50) + 60) + '%')
}
return data
},
},
}
</script>

<style lang="scss" scoped>
$margin: 8px;
$messages-list-max-width: 670px;
.placeholder-main {
max-width: $messages-list-max-width;
position: relative;
margin-bottom: auto;
z-index: 1;
&-text {
margin: 50px auto 0;
width: 100%;
}
}
#rich-workspace .placeholder-main-text {
margin: 40px 0 0;
}
.placeholder-list {
position: absolute;
transform: translateZ(0);
}
.placeholder-list-regular {
animation: pulse 2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
.placeholder-list-reverse {
animation: pulse-reverse 2s;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
.placeholder-gradient {
position: fixed;
height: 0;
width: 0;
z-index: -1;
}
.text-placeholder {
width: min($messages-list-max-width, 100vw);
height: 6em;
margin: $margin auto;
padding: 4px 8px 0 14px;
display: block;
&-line-one,
&-line-two,
&-line-three,
&-line-four {
width: 670px;
height: 1em;
}
&-line-one {
y: 0.33em;
width: 175px;
}
&-line-two {
y: 1.66em;
}
&-line-three {
y: 3em;
}
&-line-four {
y: 4.33em;
}
}
@keyframes pulse {
0% {
opacity: 1;
}
50% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes pulse-reverse {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
9 changes: 6 additions & 3 deletions src/views/RichWorkspace.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
-->

<template>
<div v-if="enabled" id="rich-workspace" :class="{'icon-loading': !loaded || !ready, 'focus': focus, 'dark': darkTheme, 'creatable': canCreate }">
<div v-if="enabled" id="rich-workspace" :class="{'focus': focus, 'dark': darkTheme, 'creatable': canCreate }">
<SkeletonLoading v-if="!loaded || !ready" />
<Editor v-if="file"
v-show="ready"
:key="file.path"
Expand All @@ -44,13 +45,15 @@
import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import { subscribe, unsubscribe } from '@nextcloud/event-bus'
import SkeletonLoading from '../components/SkeletonLoading.vue'
const IS_PUBLIC = !!(document.getElementById('isPublic'))
const WORKSPACE_URL = generateOcsUrl('apps/text' + (IS_PUBLIC ? '/public' : '') + '/workspace', 2)
export default {
name: 'RichWorkspace',
components: {
SkeletonLoading,
Editor: () => import(/* webpackChunkName: "editor" */'./../components/Editor.vue'),
},
props: {
Expand Down Expand Up @@ -268,7 +271,7 @@ export default {
overflow: hidden;
}
#rich-workspace:not(.focus):not(.icon-loading):not(.empty):after {
#rich-workspace:not(.focus):not(.empty):after {
content: '';
position: absolute;
z-index: 1;
Expand All @@ -280,7 +283,7 @@ export default {
height: 4em;
}
#rich-workspace.dark:not(.focus):not(.icon-loading):after {
#rich-workspace.dark:not(.focus):after {
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--color-main-background));
}
Expand Down

0 comments on commit b982efa

Please sign in to comment.