diff --git a/docs/src/App.vue b/docs/src/App.vue index 8a1b9d4..50c76e2 100644 --- a/docs/src/App.vue +++ b/docs/src/App.vue @@ -101,6 +101,10 @@ Sidenav + + Spinner + + Subheader diff --git a/docs/src/config.js b/docs/src/config.js index 3f5a58f..c43949d 100644 --- a/docs/src/config.js +++ b/docs/src/config.js @@ -8,6 +8,10 @@ Vue.material.theme.registerAll({ primary: 'blue', accent: 'pink' }, + blue: { + primary: 'blue', + accent: 'pink' + }, indigo: { primary: 'indigo', accent: 'pink' @@ -21,12 +25,8 @@ Vue.material.theme.registerAll({ accent: 'blue' }, orange: { - primary: 'orange', - accent: 'green' - }, - blue: { - primary: 'blue', - accent: 'pink' + primary: 'deep-orange', + accent: 'purple' }, green: { primary: 'green', diff --git a/docs/src/pages/components/Spinner.vue b/docs/src/pages/components/Spinner.vue new file mode 100644 index 0000000..9ed8315 --- /dev/null +++ b/docs/src/pages/components/Spinner.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/docs/src/routes.js b/docs/src/routes.js index 31898f5..34450f3 100644 --- a/docs/src/routes.js +++ b/docs/src/routes.js @@ -21,6 +21,7 @@ import Radio from './pages/components/Radio'; import InkRipple from './pages/components/InkRipple'; import Select from './pages/components/Select'; import Sidenav from './pages/components/Sidenav'; +import Spinner from './pages/components/Spinner'; import Subheader from './pages/components/Subheader'; import Switch from './pages/components/Switch'; import Table from './pages/components/Table'; @@ -141,6 +142,11 @@ const components = [ name: 'components:sidenav', component: Sidenav }, + { + path: '/components/spinner', + name: 'components:spinner', + component: Spinner + }, { path: '/components/switch', name: 'components:switch', diff --git a/src/components/mdSpinner/index.js b/src/components/mdSpinner/index.js new file mode 100644 index 0000000..a18138b --- /dev/null +++ b/src/components/mdSpinner/index.js @@ -0,0 +1,8 @@ +import mdSpinner from './mdSpinner.vue'; +import mdSpinnerTheme from './mdSpinner.theme'; + +export default function install(Vue) { + Vue.component('md-spinner', Vue.extend(mdSpinner)); + + Vue.material.styles.push(mdSpinnerTheme); +} diff --git a/src/components/mdSpinner/mdSpinner.scss b/src/components/mdSpinner/mdSpinner.scss new file mode 100644 index 0000000..1fe84e0 --- /dev/null +++ b/src/components/mdSpinner/mdSpinner.scss @@ -0,0 +1,97 @@ +@import '../../core/stylesheets/variables.scss'; + +.md-spinner { + display: inline-block; + position: relative; + pointer-events: none; + will-change: transform, opacity; + + &.md-indeterminate { + .md-spinner-draw { + animation: spinner-rotate 1.9s linear infinite; + transform: rotate(0deg) translateZ(0); + } + + .md-spinner-path { + stroke-dasharray: 2, 200; + animation: spinner-dash 1.425s ease-in-out infinite; + } + } + + &.md-spinner-leave-active { + opacity: 0; + transform: scale(.9) translateZ(0); + transition: $swift-ease-out; + } + + &:not(.md-indeterminate) { + &.md-spinner-enter-active { + transition-duration: 1.8s; + + .md-spinner-draw { + animation: spinner-initial-rotate 1.79s $swift-ease-out-timing-function infinite; + } + } + } +} + +.md-spinner-draw { + width: 100%; + height: 100%; + margin: auto; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + transform: rotate(270deg) translateZ(0); + transform-origin: center center; + will-change: transform, opacity; +} + +.md-spinner-path { + fill: none; + stroke-dashoffset: 0; + stroke-miterlimit: 10; + stroke-width: 3.2; + transition: $swift-ease-out; +} + +@keyframes spinner-rotate { + to { + transform: rotate(360deg) translateZ(0); + } +} + +@keyframes spinner-initial-rotate { + 0% { + opacity: 0; + transform: rotate(-90deg) translateZ(0); + } + + 10% { + opacity: 1; + } + + 100% { + opacity: 1; + transform: rotate(270deg) translateZ(0); + } +} + +@keyframes spinner-dash { + 0% { + stroke-dasharray: 2, 200; + stroke-dashoffset: 0; + } + + 50% { + stroke-dasharray: 89, 200; + stroke-dashoffset: -35px; + } + + 100% { + stroke-dasharray: 89, 200; + stroke-dashoffset: -124px; + } +} diff --git a/src/components/mdSpinner/mdSpinner.theme b/src/components/mdSpinner/mdSpinner.theme new file mode 100644 index 0000000..2478a1b --- /dev/null +++ b/src/components/mdSpinner/mdSpinner.theme @@ -0,0 +1,20 @@ +.THEME_NAME { + .md-spinner, + &.md-spinner { + .md-spinner-path { + stroke: #{'PRIMARY-COLOR'} + } + + &.md-accent { + .md-spinner-path { + stroke: #{'ACCENT-COLOR'} + } + } + + &.md-warn { + .md-spinner-path { + stroke: #{'WARN-COLOR'} + } + } + } +} diff --git a/src/components/mdSpinner/mdSpinner.vue b/src/components/mdSpinner/mdSpinner.vue new file mode 100644 index 0000000..6a03227 --- /dev/null +++ b/src/components/mdSpinner/mdSpinner.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/src/index.js b/src/index.js index bc8fb4d..2d575de 100644 --- a/src/index.js +++ b/src/index.js @@ -15,6 +15,7 @@ import MdMenu from './components/mdMenu'; import MdRadio from './components/mdRadio'; import MdSelect from './components/mdSelect'; import MdSidenav from './components/mdSidenav'; +import MdSpinner from './components/mdSpinner'; import MdSubheader from './components/mdSubheader'; import MdSwitch from './components/mdSwitch'; import MdTable from './components/mdTable'; @@ -41,6 +42,7 @@ const options = { MdRadio, MdSelect, MdSidenav, + MdSpinner, MdSubheader, MdSwitch, MdTable,