晴空项目
This commit is contained in:
commit
c63b38b713
182
Layout.vue
182
Layout.vue
@ -1,182 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="theme-container"
|
||||
:class="pageClasses"
|
||||
@touchstart="onTouchStart"
|
||||
@touchend="onTouchEnd">
|
||||
<Password v-if="!isHasKey"></Password>
|
||||
|
||||
<div v-else>
|
||||
<Navbar v-if="shouldShowNavbar" @toggle-sidebar="toggleSidebar"/>
|
||||
|
||||
<div class="sidebar-mask" @click="toggleSidebar(false)"></div>
|
||||
|
||||
<Sidebar :items="sidebarItems" @toggle-sidebar="toggleSidebar">
|
||||
<slot name="sidebar-top" slot="top"/>
|
||||
<slot name="sidebar-bottom" slot="bottom"/>
|
||||
</Sidebar>
|
||||
|
||||
<div class="custom-layout" v-if="$page.frontmatter.layout">
|
||||
<component :is="$page.frontmatter.layout"/>
|
||||
</div>
|
||||
|
||||
<Home v-else-if="$page.frontmatter.home"/>
|
||||
|
||||
<Page v-else :sidebar-items="sidebarItems" @tagChange="tagChange">
|
||||
<slot name="page-top" slot="top"/>
|
||||
<slot name="page-bottom" slot="bottom"/>
|
||||
</Page>
|
||||
|
||||
<Valine :valineRefresh="valineRefresh"></Valine>
|
||||
|
||||
<router-view></router-view>
|
||||
<SWUpdatePopup :updateEvent="swUpdateEvent"/>
|
||||
<BackToTop></BackToTop>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Vue from "vue";
|
||||
import nprogress from "nprogress";
|
||||
import Home from "./pages/Home/";
|
||||
import Navbar from "./components/Navbar/";
|
||||
import Page from "./pages/Page/";
|
||||
import Sidebar from "./components/Sidebar/";
|
||||
import SWUpdatePopup from "./components/SWUpdatePopup/";
|
||||
import { resolveSidebarItems } from "./util/"
|
||||
import BackToTop from "./components/BackToTop/"
|
||||
import Valine from './components/Valine/'
|
||||
import Password from './components/Password/'
|
||||
|
||||
export default {
|
||||
components: { Home, Page, Sidebar, Navbar, SWUpdatePopup, BackToTop, Valine, Password },
|
||||
|
||||
data() {
|
||||
return {
|
||||
isSidebarOpen: false,
|
||||
swUpdateEvent: null,
|
||||
valineRefresh: false,
|
||||
isHasKey: true
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
shouldShowNavbar() {
|
||||
const { themeConfig } = this.$site;
|
||||
const { frontmatter } = this.$page;
|
||||
if (frontmatter.navbar === false || themeConfig.navbar === false) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
this.$title ||
|
||||
themeConfig.logo ||
|
||||
themeConfig.repo ||
|
||||
themeConfig.nav ||
|
||||
this.$themeLocaleConfig.nav
|
||||
);
|
||||
},
|
||||
|
||||
shouldShowSidebar() {
|
||||
const { frontmatter } = this.$page;
|
||||
return (
|
||||
!frontmatter.layout &&
|
||||
!frontmatter.home &&
|
||||
frontmatter.sidebar !== false &&
|
||||
this.sidebarItems.length
|
||||
);
|
||||
},
|
||||
|
||||
sidebarItems() {
|
||||
return resolveSidebarItems(
|
||||
this.$page,
|
||||
this.$route,
|
||||
this.$site,
|
||||
this.$localePath
|
||||
);
|
||||
},
|
||||
|
||||
pageClasses() {
|
||||
const userPageClass = this.$page.frontmatter.pageClass;
|
||||
return [
|
||||
{
|
||||
"no-navbar": !this.shouldShowNavbar,
|
||||
"sidebar-open": this.isSidebarOpen,
|
||||
"no-sidebar": !this.shouldShowSidebar
|
||||
},
|
||||
userPageClass
|
||||
];
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
window.addEventListener("scroll", this.onScroll);
|
||||
|
||||
// configure progress bar
|
||||
nprogress.configure({ showSpinner: false });
|
||||
|
||||
this.$router.beforeEach((to, from, next) => {
|
||||
if (to.path !== from.path && !Vue.component(to.name)) {
|
||||
nprogress.start();
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
this.$router.afterEach(() => {
|
||||
nprogress.done();
|
||||
this.isSidebarOpen = false;
|
||||
});
|
||||
|
||||
this.$on("sw-updated", this.onSWUpdated);
|
||||
|
||||
const keyPage = this.$site.themeConfig.keyPage
|
||||
if (!keyPage) {
|
||||
this.isHasKey = true
|
||||
return
|
||||
}
|
||||
|
||||
const keys = keyPagekeys
|
||||
this.isHasKey = keys && keys.indexOf(sessionStorage.getItem('key')) > -1
|
||||
},
|
||||
|
||||
methods: {
|
||||
tagChange () {
|
||||
this.valineRefresh = true
|
||||
setTimeout(() => {
|
||||
this.valineRefresh = false
|
||||
}, 300)
|
||||
},
|
||||
toggleSidebar(to) {
|
||||
this.isSidebarOpen = typeof to === "boolean" ? to : !this.isSidebarOpen;
|
||||
},
|
||||
|
||||
// side swipe
|
||||
onTouchStart(e) {
|
||||
this.touchStart = {
|
||||
x: e.changedTouches[0].clientX,
|
||||
y: e.changedTouches[0].clientY
|
||||
};
|
||||
},
|
||||
|
||||
onTouchEnd(e) {
|
||||
const dx = e.changedTouches[0].clientX - this.touchStart.x;
|
||||
const dy = e.changedTouches[0].clientY - this.touchStart.y;
|
||||
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
|
||||
if (dx > 0 && this.touchStart.x <= 80) {
|
||||
this.toggleSidebar(true);
|
||||
} else {
|
||||
this.toggleSidebar(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
onSWUpdated(e) {
|
||||
this.swUpdateEvent = e;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="prismjs/themes/prism-tomorrow.css"></style>
|
||||
<style src="./styles/theme.styl" lang="stylus"></style>
|
||||
|
155
components/AlgoliaSearchBox.vue
Normal file
155
components/AlgoliaSearchBox.vue
Normal file
@ -0,0 +1,155 @@
|
||||
<template>
|
||||
<form
|
||||
id="search-form"
|
||||
class="algolia-search-wrapper search-box"
|
||||
role="search"
|
||||
>
|
||||
<input
|
||||
id="algolia-search-input"
|
||||
class="search-query"
|
||||
>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['options'],
|
||||
|
||||
mounted () {
|
||||
this.initialize(this.options, this.$lang)
|
||||
},
|
||||
|
||||
methods: {
|
||||
initialize (userOptions, lang) {
|
||||
Promise.all([
|
||||
import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.js'),
|
||||
import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.css')
|
||||
]).then(([docsearch]) => {
|
||||
docsearch = docsearch.default
|
||||
const { algoliaOptions = {}} = userOptions
|
||||
docsearch(Object.assign(
|
||||
{},
|
||||
userOptions,
|
||||
{
|
||||
inputSelector: '#algolia-search-input',
|
||||
// #697 Make docsearch work well at i18n mode.
|
||||
algoliaOptions: Object.assign({
|
||||
'facetFilters': [`lang:${lang}`].concat(algoliaOptions.facetFilters || [])
|
||||
}, algoliaOptions)
|
||||
}
|
||||
))
|
||||
})
|
||||
},
|
||||
|
||||
update (options, lang) {
|
||||
this.$el.innerHTML = '<input id="algolia-search-input" class="search-query">'
|
||||
this.initialize(options, lang)
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
$lang (newValue) {
|
||||
this.update(this.options, newValue)
|
||||
},
|
||||
|
||||
options (newValue) {
|
||||
this.update(newValue, this.$lang)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.algolia-search-wrapper
|
||||
& > span
|
||||
vertical-align middle
|
||||
.algolia-autocomplete
|
||||
line-height normal
|
||||
.ds-dropdown-menu
|
||||
background-color #fff
|
||||
border 1px solid #999
|
||||
border-radius 4px
|
||||
font-size 16px
|
||||
margin 6px 0 0
|
||||
padding 4px
|
||||
text-align left
|
||||
&:before
|
||||
border-color #999
|
||||
[class*=ds-dataset-]
|
||||
border none
|
||||
padding 0
|
||||
.ds-suggestions
|
||||
margin-top 0
|
||||
.ds-suggestion
|
||||
border-bottom 1px solid $borderColor
|
||||
.algolia-docsearch-suggestion--highlight
|
||||
color #2c815b
|
||||
.algolia-docsearch-suggestion
|
||||
border-color $borderColor
|
||||
padding 0
|
||||
.algolia-docsearch-suggestion--category-header
|
||||
padding 5px 10px
|
||||
margin-top 0
|
||||
background $accentColor
|
||||
color #fff
|
||||
font-weight 600
|
||||
.algolia-docsearch-suggestion--highlight
|
||||
background rgba(255, 255, 255, 0.6)
|
||||
.algolia-docsearch-suggestion--wrapper
|
||||
padding 0
|
||||
.algolia-docsearch-suggestion--title
|
||||
font-weight 600
|
||||
margin-bottom 0
|
||||
color $textColor
|
||||
.algolia-docsearch-suggestion--subcategory-column
|
||||
vertical-align top
|
||||
padding 5px 7px 5px 5px
|
||||
border-color $borderColor
|
||||
background #f1f3f5
|
||||
&:after
|
||||
display none
|
||||
.algolia-docsearch-suggestion--subcategory-column-text
|
||||
color #555
|
||||
.algolia-docsearch-footer
|
||||
border-color $borderColor
|
||||
.ds-cursor .algolia-docsearch-suggestion--content
|
||||
background-color #e7edf3 !important
|
||||
color $textColor
|
||||
|
||||
@media (min-width: $MQMobile)
|
||||
.algolia-search-wrapper
|
||||
.algolia-autocomplete
|
||||
.algolia-docsearch-suggestion
|
||||
.algolia-docsearch-suggestion--subcategory-column
|
||||
float none
|
||||
width 150px
|
||||
min-width 150px
|
||||
display table-cell
|
||||
.algolia-docsearch-suggestion--content
|
||||
float none
|
||||
display table-cell
|
||||
width 100%
|
||||
vertical-align top
|
||||
.ds-dropdown-menu
|
||||
min-width 515px !important
|
||||
|
||||
@media (max-width: $MQMobile)
|
||||
.algolia-search-wrapper
|
||||
.ds-dropdown-menu
|
||||
min-width calc(100vw - 4rem) !important
|
||||
max-width calc(100vw - 4rem) !important
|
||||
.algolia-docsearch-suggestion--wrapper
|
||||
padding 5px 7px 5px 5px !important
|
||||
.algolia-docsearch-suggestion--subcategory-column
|
||||
padding 0 !important
|
||||
background white !important
|
||||
.algolia-docsearch-suggestion--subcategory-column-text:after
|
||||
content " > "
|
||||
font-size 10px
|
||||
line-height 14.4px
|
||||
display inline-block
|
||||
width 5px
|
||||
margin -3px 3px 0
|
||||
vertical-align middle
|
||||
|
||||
</style>
|
109
components/BackToTop.vue
Normal file
109
components/BackToTop.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<transition :name="transitionName">
|
||||
<div v-show="visible" :style="customStyle" class="back-to-ceiling" @click="backToTop">
|
||||
<i class="iconfont reco-up"></i>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BackToTop',
|
||||
props: {
|
||||
visibilityHeight: {
|
||||
type: Number,
|
||||
default: 400
|
||||
},
|
||||
backPosition: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
customStyle: {
|
||||
type: Object,
|
||||
default: function() {
|
||||
return {
|
||||
right: '1rem',
|
||||
bottom: '3rem',
|
||||
width: '2.5rem',
|
||||
height: '2.5rem',
|
||||
'border-radius': '.25rem',
|
||||
'line-height': '2.5rem',
|
||||
backgroundColor: 'rgba(231, 234, 241,.5)'
|
||||
}
|
||||
}
|
||||
},
|
||||
transitionName: {
|
||||
type: String,
|
||||
default: 'fade'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: false,
|
||||
interval: null,
|
||||
isMoving: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
window.addEventListener('scroll', this.handleScroll)
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('scroll', this.handleScroll)
|
||||
if (this.interval) {
|
||||
clearInterval(this.interval)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleScroll() {
|
||||
this.visible = window.pageYOffset > this.visibilityHeight
|
||||
},
|
||||
backToTop() {
|
||||
if (this.isMoving) return
|
||||
const start = window.pageYOffset
|
||||
let i = 0
|
||||
this.isMoving = true
|
||||
this.interval = setInterval(() => {
|
||||
const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500))
|
||||
if (next <= this.backPosition) {
|
||||
window.scrollTo(0, this.backPosition)
|
||||
clearInterval(this.interval)
|
||||
this.isMoving = false
|
||||
} else {
|
||||
window.scrollTo(0, next)
|
||||
}
|
||||
i++
|
||||
}, 16.7)
|
||||
},
|
||||
easeInOutQuad(t, b, c, d) {
|
||||
if ((t /= d / 2) < 1) return c / 2 * t * t + b
|
||||
return -c / 2 * (--t * (t - 2) - 1) + b
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.back-to-ceiling
|
||||
position: fixed;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
i
|
||||
font-size 1.6rem
|
||||
color $accentColor
|
||||
.back-to-ceiling:hover {
|
||||
background: #d5dbe7;
|
||||
}
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity .5s;
|
||||
}
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0
|
||||
}
|
||||
.back-to-ceiling .Icon {
|
||||
fill: #9aaabf;
|
||||
background: none;
|
||||
}
|
||||
</style>
|
118
components/Background.vue
Normal file
118
components/Background.vue
Normal file
@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div id="particles-oli-wrapper"></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
mounted() {
|
||||
const keyPage = this.$site.themeConfig.keyPage
|
||||
let color = '#fb9b5f'
|
||||
let lineColor = '#fb9b5f'
|
||||
if (keyPage) {
|
||||
color = keyPage.color || color
|
||||
lineColor = keyPage.lineColor || lineColor
|
||||
}
|
||||
|
||||
const script = document.createElement("script");
|
||||
script.src = "https://cdn.jsdelivr.net/npm/particles.js@2.0.0/particles.min.js";
|
||||
|
||||
document.body.append(script);
|
||||
script.onload = function() {
|
||||
particlesJS("particles-oli-wrapper", {
|
||||
particles: {
|
||||
number: {
|
||||
value: 40,
|
||||
density: {
|
||||
enable: true,
|
||||
value_area: 800
|
||||
}
|
||||
},
|
||||
color: {
|
||||
value: color
|
||||
},
|
||||
shape: {
|
||||
type: "circle",
|
||||
stroke: {
|
||||
width: 0,
|
||||
color: "#000000"
|
||||
},
|
||||
polygon: {
|
||||
nb_sides: 5
|
||||
}
|
||||
},
|
||||
opacity: {
|
||||
value: 0.3,
|
||||
random: false,
|
||||
anim: {
|
||||
enable: false,
|
||||
speed: 1,
|
||||
opacity_min: 0.1,
|
||||
sync: false
|
||||
}
|
||||
},
|
||||
size: {
|
||||
value: 20,
|
||||
random: true,
|
||||
anim: {
|
||||
enable: false,
|
||||
speed: 30,
|
||||
size_min: 0.1,
|
||||
sync: false
|
||||
}
|
||||
},
|
||||
line_linked: {
|
||||
enable: true,
|
||||
distance: 250,
|
||||
color: lineColor,
|
||||
opacity: 0.2,
|
||||
width: 1
|
||||
},
|
||||
move: {
|
||||
enable: true,
|
||||
speed: 3,
|
||||
direction: "none",
|
||||
random: true,
|
||||
straight: false,
|
||||
out_mode: "out",
|
||||
bounce: true,
|
||||
attract: {
|
||||
enable: false,
|
||||
rotateX: 600,
|
||||
rotateY: 1200
|
||||
}
|
||||
}
|
||||
},
|
||||
interactivity: {
|
||||
detect_on: "canvas",
|
||||
events: {
|
||||
onhover: {
|
||||
enable: true,
|
||||
mode: "grab"
|
||||
},
|
||||
onclick: {
|
||||
enable: true,
|
||||
mode: "push"
|
||||
},
|
||||
resize: true
|
||||
},
|
||||
modes: {
|
||||
grab: {
|
||||
distance: 100,
|
||||
line_linked: {
|
||||
opacity: 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
retina_detect: true
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
#particles-oli-wrapper {
|
||||
height: 99vh;
|
||||
}
|
||||
</style>
|
||||
|
152
components/Common.vue
Normal file
152
components/Common.vue
Normal file
@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<div
|
||||
class="theme-container"
|
||||
:class="pageClasses"
|
||||
@touchstart="onTouchStart"
|
||||
@touchend="onTouchEnd">
|
||||
<Password v-if="!isHasKey"></Password>
|
||||
<div v-else>
|
||||
<Navbar
|
||||
v-if="shouldShowNavbar"
|
||||
@toggle-sidebar="toggleSidebar"/>
|
||||
|
||||
<div
|
||||
class="sidebar-mask"
|
||||
@click="toggleSidebar(false)"></div>
|
||||
|
||||
<Sidebar
|
||||
:items="sidebarItems"
|
||||
@toggle-sidebar="toggleSidebar">
|
||||
<slot
|
||||
name="sidebar-top"
|
||||
slot="top"/>
|
||||
<slot
|
||||
name="sidebar-bottom"
|
||||
slot="bottom"/>
|
||||
</Sidebar>
|
||||
<slot></slot>
|
||||
<Valine :isComment="isComment"></Valine>
|
||||
<BackToTop></BackToTop>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Navbar from '@theme/components/Navbar.vue'
|
||||
import Sidebar from '@theme/components/Sidebar.vue'
|
||||
import { resolveSidebarItems } from '../util'
|
||||
import Password from '@theme/components/Password'
|
||||
import Valine from '@theme/components/Valine/'
|
||||
import BackToTop from "@theme/components/BackToTop"
|
||||
|
||||
export default {
|
||||
components: { Sidebar, Navbar, Password, Valine, BackToTop },
|
||||
|
||||
props: ['sidebar', 'isComment'],
|
||||
|
||||
data () {
|
||||
return {
|
||||
isSidebarOpen: false,
|
||||
isHasKey: true,
|
||||
nightMode: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
shouldShowNavbar () {
|
||||
const { themeConfig } = this.$site
|
||||
const { frontmatter } = this.$page
|
||||
if (
|
||||
frontmatter.navbar === false
|
||||
|| themeConfig.navbar === false) {
|
||||
return false
|
||||
}
|
||||
return (
|
||||
this.$title
|
||||
|| themeConfig.logo
|
||||
|| themeConfig.repo
|
||||
|| themeConfig.nav
|
||||
|| this.$themeLocaleConfig.nav
|
||||
)
|
||||
},
|
||||
|
||||
shouldShowSidebar () {
|
||||
const { frontmatter } = this.$page
|
||||
return (
|
||||
this.sidebar !== false
|
||||
&& !frontmatter.home
|
||||
&& frontmatter.sidebar !== false
|
||||
&& this.sidebarItems.length
|
||||
)
|
||||
},
|
||||
|
||||
sidebarItems () {
|
||||
return resolveSidebarItems(
|
||||
this.$page,
|
||||
this.$page.regularPath,
|
||||
this.$site,
|
||||
this.$localePath
|
||||
)
|
||||
},
|
||||
|
||||
pageClasses () {
|
||||
const userPageClass = this.$page.frontmatter.pageClass
|
||||
return [
|
||||
{
|
||||
'no-navbar': !this.shouldShowNavbar,
|
||||
'sidebar-open': this.isSidebarOpen,
|
||||
'no-sidebar': !this.shouldShowSidebar,
|
||||
'night-mode': this.nightMode
|
||||
},
|
||||
userPageClass
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.$router.afterEach(() => {
|
||||
this.isSidebarOpen = false
|
||||
})
|
||||
|
||||
if (localStorage.getItem('nightMode')) {
|
||||
document.documentElement.style.background = "#000"
|
||||
this.nightMode = true
|
||||
}
|
||||
|
||||
const keyPage = this.$site.themeConfig.keyPage
|
||||
if (!keyPage) {
|
||||
this.isHasKey = true
|
||||
return
|
||||
}
|
||||
|
||||
const keys = keyPage.keys
|
||||
this.isHasKey = keys && keys.indexOf(sessionStorage.getItem('key')) > -1
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleSidebar (to) {
|
||||
this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
|
||||
},
|
||||
|
||||
// side swipe
|
||||
onTouchStart (e) {
|
||||
this.touchStart = {
|
||||
x: e.changedTouches[0].clientX,
|
||||
y: e.changedTouches[0].clientY
|
||||
}
|
||||
},
|
||||
|
||||
onTouchEnd (e) {
|
||||
const dx = e.changedTouches[0].clientX - this.touchStart.x
|
||||
const dy = e.changedTouches[0].clientY - this.touchStart.y
|
||||
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
|
||||
if (dx > 0 && this.touchStart.x <= 80) {
|
||||
this.toggleSidebar(true)
|
||||
} else {
|
||||
this.toggleSidebar(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
181
components/DropdownLink.vue
Normal file
181
components/DropdownLink.vue
Normal file
@ -0,0 +1,181 @@
|
||||
<template>
|
||||
<div
|
||||
class="dropdown-wrapper"
|
||||
:class="{ open }"
|
||||
>
|
||||
<a
|
||||
class="dropdown-title"
|
||||
@click="toggle"
|
||||
>
|
||||
<span class="title">
|
||||
<i :class="`iconfont ${item.icon}`"></i>
|
||||
{{ item.text }}
|
||||
</span>
|
||||
<span
|
||||
class="arrow"
|
||||
:class="open ? 'down' : 'right'"
|
||||
></span>
|
||||
</a>
|
||||
|
||||
<DropdownTransition>
|
||||
<ul
|
||||
class="nav-dropdown"
|
||||
v-show="open"
|
||||
>
|
||||
<li
|
||||
class="dropdown-item"
|
||||
:key="subItem.link || index"
|
||||
v-for="(subItem, index) in item.items"
|
||||
>
|
||||
<h4 v-if="subItem.type === 'links'">{{ subItem.text }}</h4>
|
||||
|
||||
<ul
|
||||
class="dropdown-subitem-wrapper"
|
||||
v-if="subItem.type === 'links'"
|
||||
>
|
||||
<li
|
||||
class="dropdown-subitem"
|
||||
:key="childSubItem.link"
|
||||
v-for="childSubItem in subItem.items"
|
||||
>
|
||||
<NavLink :item="childSubItem"/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<NavLink
|
||||
v-else
|
||||
:item="subItem"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</DropdownTransition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NavLink from '@theme/components/NavLink.vue'
|
||||
import DropdownTransition from '@theme/components/DropdownTransition.vue'
|
||||
|
||||
export default {
|
||||
components: { NavLink, DropdownTransition },
|
||||
|
||||
data () {
|
||||
return {
|
||||
open: false
|
||||
}
|
||||
},
|
||||
|
||||
props: {
|
||||
item: {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggle () {
|
||||
this.open = !this.open
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.dropdown-wrapper
|
||||
cursor pointer
|
||||
.dropdown-title
|
||||
display block
|
||||
&:hover
|
||||
border-color transparent
|
||||
.arrow
|
||||
vertical-align middle
|
||||
margin-top -1px
|
||||
margin-left 0.4rem
|
||||
.nav-dropdown
|
||||
.dropdown-item
|
||||
color inherit
|
||||
line-height 1.7rem
|
||||
h4
|
||||
margin 0.45rem 0 0
|
||||
border-top 1px solid #eee
|
||||
padding 0.45rem 1.5rem 0 1.25rem
|
||||
.dropdown-subitem-wrapper
|
||||
padding 0
|
||||
list-style none
|
||||
.dropdown-subitem
|
||||
font-size 0.9em
|
||||
a
|
||||
display block
|
||||
line-height 1.7rem
|
||||
position relative
|
||||
border-bottom none
|
||||
font-weight 400
|
||||
margin-bottom 0
|
||||
padding 0 1.5rem 0 1.25rem
|
||||
&:hover
|
||||
color $accentColor
|
||||
&.router-link-active
|
||||
color $accentColor
|
||||
&::after
|
||||
content ""
|
||||
width 0
|
||||
height 0
|
||||
border-left 5px solid $accentColor
|
||||
border-top 3px solid transparent
|
||||
border-bottom 3px solid transparent
|
||||
position absolute
|
||||
top calc(50% - 2px)
|
||||
left 9px
|
||||
&:first-child h4
|
||||
margin-top 0
|
||||
padding-top 0
|
||||
border-top 0
|
||||
|
||||
@media (max-width: $MQMobile)
|
||||
.dropdown-wrapper
|
||||
&.open .dropdown-title
|
||||
margin-bottom 0.5rem
|
||||
.nav-dropdown
|
||||
transition height .1s ease-out
|
||||
overflow hidden
|
||||
.dropdown-item
|
||||
h4
|
||||
border-top 0
|
||||
margin-top 0
|
||||
padding-top 0
|
||||
h4, & > a
|
||||
font-size 15px
|
||||
line-height 2rem
|
||||
.dropdown-subitem
|
||||
font-size 14px
|
||||
padding-left 1rem
|
||||
|
||||
@media (min-width: $MQMobile)
|
||||
.dropdown-wrapper
|
||||
height 1.8rem
|
||||
&:hover .nav-dropdown
|
||||
// override the inline style.
|
||||
display block !important
|
||||
.dropdown-title .arrow
|
||||
// make the arrow always down at desktop
|
||||
border-left 4px solid transparent
|
||||
border-right 4px solid transparent
|
||||
border-top 6px solid $arrowBgColor
|
||||
border-bottom 0
|
||||
.nav-dropdown
|
||||
display none
|
||||
// Avoid height shaked by clicking
|
||||
height auto !important
|
||||
box-sizing border-box;
|
||||
max-height calc(100vh - 2.7rem)
|
||||
overflow-y auto
|
||||
position absolute
|
||||
top 100%
|
||||
right 0
|
||||
background-color #fff
|
||||
padding 0.6rem 0
|
||||
box-shadow: 0 4px 20px 0 rgba(0,0,0,.2);
|
||||
text-align left
|
||||
border-radius 0.25rem
|
||||
white-space nowrap
|
||||
margin 0
|
||||
</style>
|
285
components/Home.vue
Normal file
285
components/Home.vue
Normal file
@ -0,0 +1,285 @@
|
||||
<template>
|
||||
<div class="home" :class="recoShow?'reco-show': 'reco-hide'">
|
||||
<div class="hero">
|
||||
<img v-if="data.heroImage" :style="heroImageStyle" :src="$withBase(data.heroImage)" alt="hero">
|
||||
|
||||
<h1 v-if="data.isShowTitleInHome !== false">{{ data.heroText || $title || '午后南杂' }}</h1>
|
||||
|
||||
<p class="description">{{ data.tagline || $description || 'Welcome to your vuePress-theme-reco site' }}</p>
|
||||
|
||||
<p class="action" v-if="data.actionText && data.actionLink">
|
||||
<NavLink class="action-button" :item="actionLink"/>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="features" v-if="data.features && data.features.length">
|
||||
<div v-for="(feature, index) in data.features" :key="index" class="feature">
|
||||
<h2>{{ feature.title }}</h2>
|
||||
<p>{{ feature.details }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Content class="home-center" custom/>
|
||||
|
||||
<div class="footer">
|
||||
<span>
|
||||
<i class="iconfont reco-theme"></i>
|
||||
<a target="blank" href="https://recoluan.gitlab.io/vuepress-theme-reco-doc/">VuePress-theme-reco</a>
|
||||
</span>
|
||||
<span>
|
||||
<i class="iconfont reco-other"></i>
|
||||
<a>{{ $site.themeConfig.author || $site.title }}</a>
|
||||
</span>
|
||||
<span>
|
||||
<i class="iconfont reco-copyright"></i>
|
||||
<a>{{ year }}</a>
|
||||
</span>
|
||||
<span>
|
||||
<AccessNumber idVal="/"></AccessNumber>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NavLink from "@theme/components/NavLink/";
|
||||
import AccessNumber from '@theme/components/Valine/AccessNumber'
|
||||
|
||||
export default {
|
||||
components: { NavLink, AccessNumber },
|
||||
data () {
|
||||
return {
|
||||
recoShow: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
year () {
|
||||
return new Date().getFullYear()
|
||||
},
|
||||
data() {
|
||||
return this.$page.frontmatter;
|
||||
},
|
||||
|
||||
actionLink() {
|
||||
return {
|
||||
link: this.data.actionLink,
|
||||
text: this.data.actionText
|
||||
};
|
||||
},
|
||||
|
||||
heroImageStyle () {
|
||||
return this.data.heroImageStyle || {
|
||||
maxHeight: '200px',
|
||||
margin: '6rem auto 1.5rem'
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.recoShow = true
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@require '../styles/loadMixin.styl'
|
||||
|
||||
.home {
|
||||
padding: $navbarHeight 2rem 0;
|
||||
max-width: 960px;
|
||||
margin: 0px auto;
|
||||
|
||||
.hero {
|
||||
text-align: center;
|
||||
img {
|
||||
background-color: $accentColor;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
h1, .description, .action {
|
||||
margin: 1.8rem auto;
|
||||
}
|
||||
|
||||
.description {
|
||||
max-width: 35rem;
|
||||
font-size: 1.6rem;
|
||||
line-height: 1.3;
|
||||
color: lighten($textColor, 20%);
|
||||
}
|
||||
|
||||
.action-button {
|
||||
display: inline-block;
|
||||
font-size: 1.2rem;
|
||||
color: #fff;
|
||||
background-color: $accentColor;
|
||||
padding: 0.6rem 1.2rem;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.1s ease;
|
||||
box-sizing: border-box;
|
||||
load-start()
|
||||
|
||||
&:hover {
|
||||
background-color: lighten($accentColor, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.features {
|
||||
border-top: 1px solid $borderColor;
|
||||
padding: 1.2rem 0;
|
||||
margin-top: 2.5rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: flex-start;
|
||||
align-content: stretch;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.feature {
|
||||
flex-grow: 1;
|
||||
flex-basis: 30%;
|
||||
max-width: 30%;
|
||||
transition: all .5s
|
||||
h2 {
|
||||
font-size: 1.6rem;
|
||||
font-weight: 500;
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
color: lighten($textColor, 10%);
|
||||
}
|
||||
|
||||
p {
|
||||
color: lighten($textColor, 20%);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform scale(1.05)
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
padding: 2.5rem;
|
||||
border-top: 1px solid $borderColor;
|
||||
text-align: center;
|
||||
color: lighten($textColor, 25%);
|
||||
load-start()
|
||||
> span {
|
||||
margin-left 1rem
|
||||
> i {
|
||||
margin-right .5rem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.reco-hide {
|
||||
.hero {
|
||||
img {
|
||||
load-start()
|
||||
}
|
||||
.h1 {
|
||||
load-start()
|
||||
}
|
||||
.description {
|
||||
load-start()
|
||||
}
|
||||
.action-button {
|
||||
load-start()
|
||||
}
|
||||
}
|
||||
.features {
|
||||
load-start()
|
||||
}
|
||||
.home-center {
|
||||
load-start()
|
||||
}
|
||||
.footer {
|
||||
load-start()
|
||||
}
|
||||
}
|
||||
|
||||
&.reco-show {
|
||||
.hero {
|
||||
img {
|
||||
load-end(0.08s)
|
||||
}
|
||||
.h1 {
|
||||
load-end(0.16s)
|
||||
}
|
||||
.description {
|
||||
load-end(0.24s)
|
||||
}
|
||||
.action-button {
|
||||
load-end(0.32s)
|
||||
}
|
||||
}
|
||||
.features {
|
||||
load-end(0.40s)
|
||||
}
|
||||
.home-center {
|
||||
load-end(0.48s)
|
||||
}
|
||||
.footer {
|
||||
load-end(0.56s)
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $MQMobile) {
|
||||
.home {
|
||||
.features {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.feature {
|
||||
max-width: 100%;
|
||||
padding: 0 2.5rem;
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
text-align: left!important;
|
||||
> span {
|
||||
display block
|
||||
margin-left 0
|
||||
line-height 2rem
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $MQMobileNarrow) {
|
||||
.home {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
|
||||
.hero {
|
||||
img {
|
||||
max-height: 210px;
|
||||
margin: 2rem auto 1.2rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
h1, .description, .action {
|
||||
margin: 1.2rem auto;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
font-size: 1rem;
|
||||
padding: 0.6rem 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.feature {
|
||||
h2 {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -12,7 +12,12 @@
|
||||
:href="link"
|
||||
class="nav-link external"
|
||||
:target="isMailto(link) || isTel(link) ? null : '_blank'"
|
||||
<<<<<<< HEAD:components/NavLink/index.vue
|
||||
:rel="isMailto(link) || isTel(link) ? null : 'noopener noreferrer'">
|
||||
=======
|
||||
:rel="isMailto(link) || isTel(link) ? null : 'noopener noreferrer'"
|
||||
>
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd:components/NavLink.vue
|
||||
<i :class="`iconfont ${item.icon}`"></i>
|
||||
{{ item.text }}
|
||||
<!-- <OutboundLink/> -->
|
||||
@ -20,7 +25,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isExternal, isMailto, isTel, ensureExt } from '../../util/'
|
||||
import { isExternal, isMailto, isTel, ensureExt } from '../util'
|
||||
|
||||
export default {
|
||||
props: {
|
@ -29,9 +29,15 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<<<<<<< HEAD:components/NavLinks/index.vue
|
||||
import DropdownLink from './components/DropdownLink/'
|
||||
import { resolveNavLinkItem } from '../../util/'
|
||||
import NavLink from '../NavLink/'
|
||||
=======
|
||||
import DropdownLink from '@theme/components/DropdownLink.vue'
|
||||
import { resolveNavLinkItem } from '../util'
|
||||
import NavLink from '@theme/components/NavLink.vue'
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd:components/NavLinks.vue
|
||||
|
||||
export default {
|
||||
components: { NavLink, DropdownLink },
|
||||
@ -69,6 +75,40 @@ export default {
|
||||
}
|
||||
return [...this.userNav, languageDropdown]
|
||||
}
|
||||
|
||||
// blogConfig 的处理,根绝配置自动添加分类和标签
|
||||
const blogConfig = this.$themeConfig.blogConfig || {},
|
||||
isHasCategory = this.userNav.some(item => {
|
||||
return item.text === 'Category'
|
||||
}),
|
||||
isHasTag = this.userNav.some(item => {
|
||||
return item.text === 'Tag'
|
||||
})
|
||||
|
||||
if (!isHasCategory && blogConfig.hasOwnProperty('category')) {
|
||||
const category = blogConfig.category
|
||||
const $categories = this.$categories
|
||||
this.userNav.splice( parseInt(category.location || 2) - 1, 0, {
|
||||
items: $categories.list.map(item => {
|
||||
item.link = item.path
|
||||
item.text = item.name
|
||||
return item
|
||||
}),
|
||||
text: category.text || '分类',
|
||||
type: "links",
|
||||
icon: "reco-category"
|
||||
})
|
||||
}
|
||||
if (!isHasTag && blogConfig.hasOwnProperty('tag')) {
|
||||
const tag = blogConfig.tag
|
||||
this.userNav.splice(parseInt(tag.location || 3) - 1, 0, {
|
||||
link: '/tag/',
|
||||
text: tag.text || '标签',
|
||||
type: "links",
|
||||
icon: "reco-tag"
|
||||
})
|
||||
}
|
||||
|
||||
return this.userNav
|
||||
},
|
||||
|
||||
@ -111,8 +151,6 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@import '../../styles/config.styl'
|
||||
|
||||
.nav-links
|
||||
display inline-block
|
||||
a
|
||||
@ -121,7 +159,11 @@ export default {
|
||||
&:hover, &.router-link-active
|
||||
color $accentColor
|
||||
.iconfont
|
||||
<<<<<<< HEAD:components/NavLinks/index.vue
|
||||
color $accentColor!important
|
||||
=======
|
||||
color $accentColor
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd:components/NavLinks.vue
|
||||
.nav-item
|
||||
position relative
|
||||
display inline-block
|
125
components/Navbar.vue
Normal file
125
components/Navbar.vue
Normal file
@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<header class="navbar">
|
||||
<SidebarButton @toggle-sidebar="$emit('toggle-sidebar')"/>
|
||||
|
||||
<router-link
|
||||
:to="$localePath"
|
||||
class="home-link">
|
||||
<img
|
||||
class="logo"
|
||||
v-if="$site.themeConfig.logo"
|
||||
:src="$withBase($site.themeConfig.logo)"
|
||||
:alt="$siteTitle">
|
||||
<span
|
||||
ref="siteName"
|
||||
class="site-name"
|
||||
v-if="$siteTitle">{{ $siteTitle }}</span>
|
||||
</router-link>
|
||||
|
||||
<div
|
||||
class="links"
|
||||
:style="linksWrapMaxWidth ? {
|
||||
'max-width': linksWrapMaxWidth + 'px'
|
||||
} : {}">
|
||||
<Theme />
|
||||
<AlgoliaSearchBox
|
||||
v-if="isAlgoliaSearch"
|
||||
:options="algolia"/>
|
||||
<SearchBox v-else-if="$site.themeConfig.search !== false && $page.frontmatter.search !== false"/>
|
||||
<NavLinks class="can-hide"/>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AlgoliaSearchBox from '@AlgoliaSearchBox'
|
||||
import SearchBox from '@SearchBox'
|
||||
import SidebarButton from '@theme/components/SidebarButton.vue'
|
||||
import NavLinks from '@theme/components/NavLinks.vue'
|
||||
import Theme from '@theme/components/Theme'
|
||||
|
||||
export default {
|
||||
components: { SidebarButton, NavLinks, SearchBox, AlgoliaSearchBox, Theme },
|
||||
|
||||
data () {
|
||||
return {
|
||||
linksWrapMaxWidth: null
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
|
||||
const NAVBAR_VERTICAL_PADDING = parseInt(css(this.$el, 'paddingLeft')) + parseInt(css(this.$el, 'paddingRight'))
|
||||
const handleLinksWrapWidth = () => {
|
||||
if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {
|
||||
this.linksWrapMaxWidth = null
|
||||
} else {
|
||||
this.linksWrapMaxWidth = this.$el.offsetWidth - NAVBAR_VERTICAL_PADDING
|
||||
- (this.$refs.siteName && this.$refs.siteName.offsetWidth || 0)
|
||||
}
|
||||
}
|
||||
handleLinksWrapWidth()
|
||||
window.addEventListener('resize', handleLinksWrapWidth, false)
|
||||
},
|
||||
|
||||
computed: {
|
||||
algolia () {
|
||||
return this.$themeLocaleConfig.algolia || this.$site.themeConfig.algolia || {}
|
||||
},
|
||||
|
||||
isAlgoliaSearch () {
|
||||
return this.algolia && this.algolia.apiKey && this.algolia.indexName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function css (el, property) {
|
||||
// NOTE: Known bug, will return 'auto' if style value is 'auto'
|
||||
const win = el.ownerDocument.defaultView
|
||||
// null means not to return pseudo styles
|
||||
return win.getComputedStyle(el, null)[property]
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
$navbar-vertical-padding = 0.7rem
|
||||
$navbar-horizontal-padding = 1.5rem
|
||||
|
||||
.navbar
|
||||
padding $navbar-vertical-padding $navbar-horizontal-padding
|
||||
line-height $navbarHeight - 1.4rem
|
||||
box-shadow 0 1px 6px 0 rgba(32,33,36,.28)
|
||||
a, span, img
|
||||
display inline-block
|
||||
.logo
|
||||
height $navbarHeight - 1.4rem
|
||||
min-width $navbarHeight - 1.4rem
|
||||
margin-right 0.8rem
|
||||
vertical-align top
|
||||
.site-name
|
||||
font-size 1.2rem
|
||||
font-weight 600
|
||||
color $textColor
|
||||
position relative
|
||||
.links
|
||||
padding-left 1.5rem
|
||||
box-sizing border-box
|
||||
background-color white
|
||||
white-space nowrap
|
||||
font-size 0.9rem
|
||||
position absolute
|
||||
right $navbar-horizontal-padding
|
||||
top $navbar-vertical-padding
|
||||
display flex
|
||||
.search-box
|
||||
flex: 0 0 auto
|
||||
vertical-align top
|
||||
|
||||
@media (max-width: $MQMobile)
|
||||
.navbar
|
||||
padding-left 4rem
|
||||
.can-hide
|
||||
display none
|
||||
.links
|
||||
padding-left 1.5rem
|
||||
</style>
|
@ -1,177 +0,0 @@
|
||||
<template>
|
||||
<header class="navbar" id="navbarWrapper">
|
||||
<SidebarButton @toggle-sidebar="$emit('toggle-sidebar')"/>
|
||||
|
||||
<router-link :to="$localePath" class="home-link">
|
||||
<img
|
||||
class="logo"
|
||||
v-if="$site.themeConfig.logo"
|
||||
:src="$withBase($site.themeConfig.logo)"
|
||||
:alt="$siteTitle">
|
||||
<span
|
||||
ref="siteName"
|
||||
class="site-name"
|
||||
v-if="$siteTitle">{{ $siteTitle }}</span>
|
||||
</router-link>
|
||||
|
||||
<div class="links" :style="{
|
||||
'max-width': linksWrapMaxWidth + 'px'
|
||||
}">
|
||||
<Search class="side-search-wrapper"></Search>
|
||||
<NavLinks class="can-hide"/>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SidebarButton from "./components/SidebarButton/";
|
||||
import Search from '../Search/'
|
||||
import NavLinks from "../NavLinks/";
|
||||
|
||||
export default {
|
||||
components: { SidebarButton, NavLinks, Search },
|
||||
|
||||
data() {
|
||||
return {
|
||||
linksWrapMaxWidth: null
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const MOBILE_DESKTOP_BREAKPOINT = 719; // refer to config.styl
|
||||
const NAVBAR_VERTICAL_PADDING =
|
||||
parseInt(css(this.$el, "paddingLeft")) +
|
||||
parseInt(css(this.$el, "paddingRight"));
|
||||
const handleLinksWrapWidth = () => {
|
||||
if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {
|
||||
this.linksWrapMaxWidth = null;
|
||||
} else {
|
||||
this.linksWrapMaxWidth =
|
||||
this.$el.offsetWidth -
|
||||
NAVBAR_VERTICAL_PADDING -
|
||||
((this.$refs.siteName && this.$refs.siteName.offsetWidth) || 0);
|
||||
}
|
||||
};
|
||||
handleLinksWrapWidth();
|
||||
window.addEventListener("resize", handleLinksWrapWidth, false);
|
||||
},
|
||||
|
||||
// 头部导航条的滚动
|
||||
|
||||
// updated () {
|
||||
// this.$nextTick(() => {
|
||||
// // 头部导航条的滚动
|
||||
// let oldScrollY = 0
|
||||
// let oldTransformHeight = 0
|
||||
// window.addEventListener('scroll', (e) => {
|
||||
// const newScrollY = window.scrollY
|
||||
// // 判断滚动方向
|
||||
// const scrollDirection = newScrollY - oldScrollY > 0 ? 'up' : 'down'
|
||||
|
||||
// // 使用ref会间断性获取不到dom
|
||||
// const navbarWrapper = document.querySelector('#navbarWrapper')
|
||||
// const height = navbarWrapper.offsetHeight == 58 ? 58 : 58
|
||||
// const transformHeight = scrollDirection == 'up' ? height : 0
|
||||
|
||||
// if (oldTransformHeight != transformHeight) {
|
||||
// navbarWrapper.style.top = `-${transformHeight}px`
|
||||
// }
|
||||
|
||||
// oldScrollY = newScrollY
|
||||
// oldTransformHeight = transformHeight
|
||||
// })
|
||||
// })
|
||||
// },
|
||||
|
||||
computed: {
|
||||
algolia() {
|
||||
return (
|
||||
this.$themeLocaleConfig.algolia || this.$site.themeConfig.algolia || {}
|
||||
);
|
||||
},
|
||||
|
||||
isAlgoliaSearch() {
|
||||
return this.algolia && this.algolia.apiKey && this.algolia.indexName;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function css(el, property) {
|
||||
// NOTE: Known bug, will return 'auto' if style value is 'auto'
|
||||
const win = el.ownerDocument.defaultView;
|
||||
// null means not to return pseudo styles
|
||||
return win.getComputedStyle(el, null)[property];
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@import '../../styles/config.styl';
|
||||
|
||||
$navbar-vertical-padding = 0.7rem;
|
||||
$navbar-horizontal-padding = 1.5rem;
|
||||
|
||||
.navbar {
|
||||
transition all .4s
|
||||
padding: $navbar-vertical-padding $navbar-horizontal-padding;
|
||||
position: relative;
|
||||
-moz-user-select:none;/*火狐*/
|
||||
-webkit-user-select:none;/*webkit浏览器*/
|
||||
-ms-user-select:none;/*IE10*/
|
||||
-khtml-user-select:none;/*早期浏览器*/
|
||||
user-select:none;
|
||||
|
||||
a, span, img {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.home-link {
|
||||
line-height $navbarHeight - 1.4rem
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: $navbarHeight - 1.4rem;
|
||||
min-width: $navbarHeight - 1.4rem;
|
||||
margin-right: 0.8rem;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.site-name {
|
||||
font-size: 1.2rem;
|
||||
color: $textColor;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.links {
|
||||
padding-left: 1.5rem;
|
||||
box-sizing: border-box;
|
||||
background-color: $bgColor;
|
||||
white-space: nowrap;
|
||||
font-size: 0.9rem;
|
||||
position: absolute;
|
||||
right: $navbar-horizontal-padding;
|
||||
top: $navbar-vertical-padding;
|
||||
display: flex;
|
||||
|
||||
.nav-links {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $MQMobile) {
|
||||
.navbar {
|
||||
transition all .5s
|
||||
|
||||
.can-hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.links {
|
||||
padding-left: 1.5rem;
|
||||
}
|
||||
.side-search-wrapper {
|
||||
display none
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -10,13 +10,21 @@
|
||||
</div>
|
||||
<div class="abstract" v-html="item.excerpt"></div>
|
||||
<hr>
|
||||
<<<<<<< HEAD:components/NoteAbstract/index.vue
|
||||
<PageInfo :pageInfo="item" :currentTag="currentTag" @currentTag="getCurrentTag"></PageInfo>
|
||||
=======
|
||||
<PageInfo :pageInfo="item" :currentTag="currentTag"></PageInfo>
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd:components/NoteAbstract.vue
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<<<<<<< HEAD:components/NoteAbstract/index.vue
|
||||
import PageInfo from '../PageInfo/'
|
||||
=======
|
||||
import PageInfo from './PageInfo'
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd:components/NoteAbstract.vue
|
||||
|
||||
export default {
|
||||
components: { PageInfo },
|
||||
@ -26,18 +34,24 @@ export default {
|
||||
const data = this.data
|
||||
const currentPage = this.currentPage
|
||||
return data.slice(currentPage * 10 - 10, currentPage * 10)
|
||||
<<<<<<< HEAD:components/NoteAbstract/index.vue
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getCurrentTag (tag) {
|
||||
this.$emit('currentTag', tag)
|
||||
=======
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd:components/NoteAbstract.vue
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
<<<<<<< HEAD:components/NoteAbstract/index.vue
|
||||
@import '../../styles/config.styl'
|
||||
=======
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd:components/NoteAbstract.vue
|
||||
|
||||
.abstract-wrapper
|
||||
width 100%
|
@ -107,7 +107,10 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
<<<<<<< HEAD:components/Pagation/index.vue
|
||||
@import '../../styles/config.styl'
|
||||
=======
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd:components/Pagation.vue
|
||||
|
||||
.pagation
|
||||
font-weight: 700;
|
284
components/Page.vue
Normal file
284
components/Page.vue
Normal file
@ -0,0 +1,284 @@
|
||||
<template>
|
||||
<main class="page" :class="recoShow?'reco-show': 'reco-hide'">
|
||||
<slot name="top"/>
|
||||
|
||||
<div class="page-title" v-if="!(isTimeLine)">
|
||||
<h1>{{$page.title}}</h1>
|
||||
<hr>
|
||||
<PageInfo :pageInfo="$page"></PageInfo>
|
||||
</div>
|
||||
|
||||
<Content/>
|
||||
|
||||
<TimeLine v-if="isTimeLine"></TimeLine>
|
||||
|
||||
<footer class="page-edit">
|
||||
<div
|
||||
class="edit-link"
|
||||
v-if="editLink"
|
||||
>
|
||||
<a
|
||||
:href="editLink"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>{{ editLinkText }}</a>
|
||||
<OutboundLink/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="last-updated"
|
||||
v-if="lastUpdated"
|
||||
>
|
||||
<span class="prefix">{{ lastUpdatedText }}: </span>
|
||||
<span class="time">{{ lastUpdated }}</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<div class="page-nav" v-if="prev || next">
|
||||
<p class="inner">
|
||||
<span
|
||||
v-if="prev"
|
||||
class="prev"
|
||||
>
|
||||
←
|
||||
<router-link
|
||||
v-if="prev"
|
||||
class="prev"
|
||||
:to="prev.path"
|
||||
>
|
||||
{{ prev.title || prev.path }}
|
||||
</router-link>
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-if="next"
|
||||
class="next"
|
||||
>
|
||||
<router-link
|
||||
v-if="next"
|
||||
:to="next.path"
|
||||
>
|
||||
{{ next.title || next.path }}
|
||||
</router-link>
|
||||
→
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<slot name="bottom"/>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PageInfo from '@theme/components/PageInfo'
|
||||
import { resolvePage, outboundRE, endingSlashRE } from '../util'
|
||||
import TimeLine from '@theme/components/TimeLine'
|
||||
|
||||
export default {
|
||||
components: { PageInfo, TimeLine},
|
||||
|
||||
props: ['sidebarItems'],
|
||||
|
||||
data () {
|
||||
return {
|
||||
recoShow: false
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
isTimeLine () {
|
||||
return this.$page.frontmatter.isTimeLine
|
||||
},
|
||||
lastUpdated () {
|
||||
return this.$page.lastUpdated
|
||||
},
|
||||
|
||||
lastUpdatedText () {
|
||||
if (typeof this.$themeLocaleConfig.lastUpdated === 'string') {
|
||||
return this.$themeLocaleConfig.lastUpdated
|
||||
}
|
||||
if (typeof this.$site.themeConfig.lastUpdated === 'string') {
|
||||
return this.$site.themeConfig.lastUpdated
|
||||
}
|
||||
return 'Last Updated'
|
||||
},
|
||||
|
||||
prev () {
|
||||
const prev = this.$page.frontmatter.prev
|
||||
if (prev === false) {
|
||||
return
|
||||
} else if (prev) {
|
||||
return resolvePage(this.$site.pages, prev, this.$route.path)
|
||||
} else {
|
||||
return resolvePrev(this.$page, this.sidebarItems)
|
||||
}
|
||||
},
|
||||
|
||||
next () {
|
||||
const next = this.$page.frontmatter.next
|
||||
if (next === false) {
|
||||
return
|
||||
} else if (next) {
|
||||
return resolvePage(this.$site.pages, next, this.$route.path)
|
||||
} else {
|
||||
return resolveNext(this.$page, this.sidebarItems)
|
||||
}
|
||||
},
|
||||
|
||||
editLink () {
|
||||
if (this.$page.frontmatter.editLink === false) {
|
||||
return
|
||||
}
|
||||
const {
|
||||
repo,
|
||||
editLinks,
|
||||
docsDir = '',
|
||||
docsBranch = 'master',
|
||||
docsRepo = repo
|
||||
} = this.$site.themeConfig
|
||||
|
||||
if (docsRepo && editLinks && this.$page.relativePath) {
|
||||
return this.createEditLink(repo, docsRepo, docsDir, docsBranch, this.$page.relativePath)
|
||||
}
|
||||
},
|
||||
|
||||
editLinkText () {
|
||||
return (
|
||||
this.$themeLocaleConfig.editLinkText
|
||||
|| this.$site.themeConfig.editLinkText
|
||||
|| `Edit this page`
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
this.recoShow = true
|
||||
},
|
||||
|
||||
methods: {
|
||||
createEditLink (repo, docsRepo, docsDir, docsBranch, path) {
|
||||
const bitbucket = /bitbucket.org/
|
||||
if (bitbucket.test(repo)) {
|
||||
const base = outboundRE.test(docsRepo)
|
||||
? docsRepo
|
||||
: repo
|
||||
return (
|
||||
base.replace(endingSlashRE, '')
|
||||
+ `/src`
|
||||
+ `/${docsBranch}/`
|
||||
+ (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '')
|
||||
+ path
|
||||
+ `?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`
|
||||
)
|
||||
}
|
||||
|
||||
const base = outboundRE.test(docsRepo)
|
||||
? docsRepo
|
||||
: `https://github.com/${docsRepo}`
|
||||
return (
|
||||
base.replace(endingSlashRE, '')
|
||||
+ `/edit`
|
||||
+ `/${docsBranch}/`
|
||||
+ (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '')
|
||||
+ path
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolvePrev (page, items) {
|
||||
return find(page, items, -1)
|
||||
}
|
||||
|
||||
function resolveNext (page, items) {
|
||||
return find(page, items, 1)
|
||||
}
|
||||
|
||||
function find (page, items, offset) {
|
||||
const res = []
|
||||
flatten(items, res)
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
const cur = res[i]
|
||||
if (cur.type === 'page' && cur.path === decodeURIComponent(page.path)) {
|
||||
return res[i + offset]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function flatten (items, res) {
|
||||
for (let i = 0, l = items.length; i < l; i++) {
|
||||
if (items[i].type === 'group') {
|
||||
flatten(items[i].children || [], res)
|
||||
} else {
|
||||
res.push(items[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@require '../styles/wrapper.styl'
|
||||
@require '../styles/loadMixin.styl'
|
||||
|
||||
.page
|
||||
padding-top 6rem
|
||||
padding-bottom 2rem
|
||||
display block
|
||||
.page-title
|
||||
max-width: 740px;
|
||||
margin: 0 auto;
|
||||
padding: 0rem 2.5rem;
|
||||
|
||||
.page-edit
|
||||
@extend $wrapper
|
||||
padding-top 1rem
|
||||
padding-bottom 1rem
|
||||
overflow auto
|
||||
.edit-link
|
||||
display inline-block
|
||||
a
|
||||
color lighten($textColor, 25%)
|
||||
margin-right 0.25rem
|
||||
.last-updated
|
||||
float right
|
||||
font-size 0.9em
|
||||
.prefix
|
||||
font-weight 500
|
||||
color lighten($textColor, 25%)
|
||||
.time
|
||||
font-weight 400
|
||||
color #aaa
|
||||
|
||||
.page-nav
|
||||
@extend $wrapper
|
||||
padding-top 1rem
|
||||
padding-bottom 0
|
||||
.inner
|
||||
min-height 2rem
|
||||
margin-top 0
|
||||
border-top 1px solid $borderColor
|
||||
padding-top 1rem
|
||||
overflow auto // clear float
|
||||
.next
|
||||
float right
|
||||
|
||||
.reco-hide.page {
|
||||
load-start()
|
||||
}
|
||||
.reco-show.page {
|
||||
load-end(0.08s)
|
||||
}
|
||||
|
||||
@media (max-width: $MQMobile)
|
||||
.page-title
|
||||
padding: 0 1rem;
|
||||
.page-edit
|
||||
.edit-link
|
||||
margin-bottom .5rem
|
||||
.last-updated
|
||||
font-size .8em
|
||||
float none
|
||||
text-align left
|
||||
|
||||
</style>
|
68
components/PageInfo.vue
Normal file
68
components/PageInfo.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div>
|
||||
<i
|
||||
class="iconfont reco-account"
|
||||
v-if="pageInfo.frontmatter.author || $site.themeConfig.author || $site.title">
|
||||
<span>{{ pageInfo.frontmatter.author || $site.themeConfig.author || $site.title }}</span>
|
||||
</i>
|
||||
<i class="iconfont reco-date" v-if="pageInfo.frontmatter.date"><span>{{ new Date(pageInfo.frontmatter.date).toLocaleDateString() }}</span></i>
|
||||
<AccessNumber :idVal="pageInfo.path" :numStyle="numStyle"></AccessNumber>
|
||||
<i class="iconfont reco-tag tags" v-if="pageInfo.frontmatter.tags">
|
||||
<span
|
||||
v-for="(subItem, subIndex) in pageInfo.frontmatter.tags"
|
||||
:key="subIndex"
|
||||
class="tag-item"
|
||||
:class="{ 'active': currentTag == subItem }"
|
||||
@click="goTags(subItem)">
|
||||
{{subItem}}
|
||||
</span>
|
||||
</i>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AccessNumber from './Valine/AccessNumber'
|
||||
|
||||
export default {
|
||||
components: { AccessNumber },
|
||||
props: ['pageInfo', 'currentTag'],
|
||||
data () {
|
||||
return {
|
||||
numStyle: {
|
||||
fontSize: '.9rem',
|
||||
fontWeight: 'normal',
|
||||
color: '#999'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
goTags (tag) {
|
||||
window.location.href = `/tag/?tag=${tag}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
.iconfont
|
||||
display inline-block
|
||||
line-height 1.5rem
|
||||
&:not(:last-child)
|
||||
margin-right 1rem
|
||||
span
|
||||
margin-left .5rem
|
||||
.tags
|
||||
.tag-item
|
||||
cursor: pointer;
|
||||
&.active
|
||||
color $accentColor
|
||||
&:hover
|
||||
color $accentColor
|
||||
|
||||
@media (max-width: $MQMobile)
|
||||
.tags
|
||||
display block
|
||||
margin-left: 0!important;
|
||||
</style>
|
283
components/Password.vue
Normal file
283
components/Password.vue
Normal file
@ -0,0 +1,283 @@
|
||||
<template>
|
||||
<div class="password-shadow">
|
||||
<Background></Background>
|
||||
<h3 class="title">{{$site.title}}</h3>
|
||||
<p class="description">{{$site.description}}</p>
|
||||
<label class="inputBox" id="box">
|
||||
<input
|
||||
v-model="key"
|
||||
type="password"
|
||||
@keyup.enter="inter"
|
||||
@focus="inputFocus"
|
||||
@blur="inputBlur">
|
||||
<span>{{warningText}}</span>
|
||||
<button ref="passwordBtn" @click="inter">OK</button>
|
||||
</label>
|
||||
|
||||
<div class="footer">
|
||||
<span>
|
||||
<i class="iconfont reco-theme"></i>
|
||||
<a target="blank" href="https://www.npmjs.com/package/vuepress-theme-reco">vuePress-theme-reco</a>
|
||||
</span>
|
||||
<span>
|
||||
<i class="iconfont reco-other"></i>
|
||||
<a>{{ $site.themeConfig.author || $site.title }}</a>
|
||||
</span>
|
||||
<span>
|
||||
<i class="iconfont reco-copyright"></i>
|
||||
<a>{{ year }}</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Background from '@theme/components/Background'
|
||||
|
||||
export default {
|
||||
components: {Background},
|
||||
name: 'Password',
|
||||
data() {
|
||||
return {
|
||||
warningText: 'Konck! Knock!',
|
||||
key: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
year () {
|
||||
return new Date().getFullYear()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
inter () {
|
||||
const keyVal = this.key.trim()
|
||||
sessionStorage.setItem('key', keyVal)
|
||||
if (!this.isHasKey()) {
|
||||
this.warningText = 'Key Error'
|
||||
return
|
||||
}
|
||||
const passwordBtn = this.$refs.passwordBtn
|
||||
const width = document.getElementById('box').getClientRects()[0].width
|
||||
|
||||
passwordBtn.style.width = `${width - 2}px`
|
||||
passwordBtn.style.opacity = 1
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 800)
|
||||
},
|
||||
isHasKey () {
|
||||
const keyPage = this.$site.themeConfig.keyPage
|
||||
const keys = keyPage.keys
|
||||
return keys && keys.indexOf(sessionStorage.getItem('key')) > -1
|
||||
},
|
||||
inputFocus () {
|
||||
this.warningText = 'Input Your Key'
|
||||
},
|
||||
inputBlur () {
|
||||
this.warningText = 'Konck! Knock!'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
.password-shadow {
|
||||
width 100vw;
|
||||
height 100vh;
|
||||
background #fff
|
||||
position relative
|
||||
.title {
|
||||
position: absolute;
|
||||
left 0
|
||||
right 0
|
||||
top 12%
|
||||
margin auto
|
||||
text-align center
|
||||
color #666
|
||||
font-size 30px
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.description {
|
||||
position: absolute;
|
||||
left 0
|
||||
right 0
|
||||
top 20%
|
||||
margin auto
|
||||
text-align center
|
||||
color #999
|
||||
font-size 22px
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.inputBox{
|
||||
max-width:700px;
|
||||
height: 100px;
|
||||
background: $accentColor;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
left 0
|
||||
right 0
|
||||
top 36%
|
||||
margin auto
|
||||
padding-left 20px
|
||||
box-sizing border-box
|
||||
opacity 0.9
|
||||
input{
|
||||
width:600px;
|
||||
height:100%;
|
||||
border:none;
|
||||
padding:0;
|
||||
padding-left:5px;
|
||||
color: #fff;
|
||||
background: none;
|
||||
outline: none;
|
||||
position: absolute;
|
||||
bottom:0;
|
||||
opacity 0
|
||||
font-size 50px
|
||||
&:focus {
|
||||
opacity 1
|
||||
}
|
||||
&:focus~span{
|
||||
transform: translateY(-80px);
|
||||
color $accentColor
|
||||
font-size 30px
|
||||
opacity:0.8;
|
||||
}
|
||||
&:focus~button{
|
||||
opacity:1;
|
||||
width:100px;
|
||||
}
|
||||
}
|
||||
span{
|
||||
width:200px;
|
||||
height: 100%;
|
||||
display: block;
|
||||
position: absolute;
|
||||
line-height:100px;
|
||||
top:0;
|
||||
left:20px;
|
||||
color: #fff;
|
||||
cursor: text;
|
||||
transition: 0.5s;
|
||||
transform-origin: left top;
|
||||
font-size 30px
|
||||
}
|
||||
button{
|
||||
width:0px;
|
||||
height:98px;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
border 1px solid $accentColor
|
||||
right:1px;
|
||||
top 1px
|
||||
border:0;
|
||||
padding:0;
|
||||
background: #fff;
|
||||
color: $accentColor;
|
||||
font-size:18px;
|
||||
outline:none;
|
||||
cursor: pointer;
|
||||
opacity:0;
|
||||
transition: 0.5s;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
.footer {
|
||||
position: absolute;
|
||||
left 0
|
||||
right 0
|
||||
bottom 10%
|
||||
margin auto
|
||||
padding: 2.5rem;
|
||||
text-align: center;
|
||||
color: lighten($textColor, 25%);
|
||||
> span {
|
||||
margin-left 1rem
|
||||
> i {
|
||||
margin-right .5rem
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: $MQMobile) {
|
||||
.inputBox{
|
||||
max-width:700px;
|
||||
height: 60px;
|
||||
background: $accentColor;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
left 0
|
||||
right 0
|
||||
top 43%
|
||||
margin auto
|
||||
padding-left 20px
|
||||
box-sizing border-box
|
||||
opacity 0.9
|
||||
input{
|
||||
width:600px;
|
||||
height:100%;
|
||||
border:none;
|
||||
padding:0;
|
||||
padding-left:5px;
|
||||
color: #fff;
|
||||
background: none;
|
||||
outline: none;
|
||||
position: absolute;
|
||||
bottom:0;
|
||||
opacity 0
|
||||
font-size 30px
|
||||
&:focus {
|
||||
opacity 1
|
||||
}
|
||||
&:focus~span{
|
||||
transform: translateY(-60px);
|
||||
color $accentColor
|
||||
font-size 20px
|
||||
opacity:0.8;
|
||||
}
|
||||
&:focus~button{
|
||||
opacity:1;
|
||||
width:60px;
|
||||
}
|
||||
}
|
||||
span{
|
||||
width:200px;
|
||||
height: 100%;
|
||||
display: block;
|
||||
position: absolute;
|
||||
line-height:60px;
|
||||
top:0;
|
||||
left:20px;
|
||||
color: #fff;
|
||||
cursor: text;
|
||||
transition: 0.5s;
|
||||
transform-origin: left top;
|
||||
font-size 20px
|
||||
}
|
||||
button{
|
||||
width:0px;
|
||||
height:58px;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
border 1px solid $accentColor
|
||||
right:1px;
|
||||
top 1px
|
||||
border:0;
|
||||
padding:0;
|
||||
background: #fff;
|
||||
color: $accentColor;
|
||||
font-size:18px;
|
||||
outline:none;
|
||||
cursor: pointer;
|
||||
opacity:0;
|
||||
transition: 0.5s;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</style>
|
@ -1,84 +0,0 @@
|
||||
<template>
|
||||
<transition name="sw-update-popup">
|
||||
<div
|
||||
v-if="enabled"
|
||||
class="sw-update-popup">
|
||||
{{message}}<br>
|
||||
<button @click="reload">{{buttonText}}</button>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
updateEvent: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
popupConfig () {
|
||||
for (const config of [this.$themeLocaleConfig, this.$site.themeConfig]) {
|
||||
const sw = config.serviceWorker
|
||||
if (sw && sw.updatePopup) {
|
||||
return typeof sw.updatePopup === 'object' ? sw.updatePopup : {}
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
|
||||
enabled () {
|
||||
return Boolean(this.popupConfig && this.updateEvent)
|
||||
},
|
||||
|
||||
message () {
|
||||
const c = this.popupConfig
|
||||
return (c && c.message) || 'New content is available.'
|
||||
},
|
||||
|
||||
buttonText () {
|
||||
const c = this.popupConfig
|
||||
return (c && c.buttonText) || 'Refresh'
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
reload () {
|
||||
if (this.updateEvent) {
|
||||
this.updateEvent.skipWaiting().then(() => {
|
||||
location.reload(true)
|
||||
})
|
||||
this.updateEvent = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@import '../../styles/config.styl'
|
||||
|
||||
.sw-update-popup
|
||||
position fixed
|
||||
right 1em
|
||||
bottom 1em
|
||||
padding 1em
|
||||
border 1px solid $accentColor
|
||||
border-radius 3px
|
||||
background-color: $bgColor;
|
||||
box-shadow 0 4px 16px rgba(0, 0, 0, 0.5)
|
||||
text-align center
|
||||
|
||||
button
|
||||
margin-top 0.5em
|
||||
padding 0.25em 2em
|
||||
|
||||
.sw-update-popup-enter-active, .sw-update-popup-leave-active
|
||||
transition opacity 0.3s, transform 0.3s
|
||||
|
||||
.sw-update-popup-enter, .sw-update-popup-leave-to
|
||||
opacity 0
|
||||
transform translate(0, 50%) scale(0.5)
|
||||
</style>
|
59
components/Sidebar.vue
Normal file
59
components/Sidebar.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<aside class="sidebar">
|
||||
<NavLinks/>
|
||||
<slot name="top"/>
|
||||
<SidebarLinks :depth="0" :items="items"/>
|
||||
<slot name="bottom"/>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SidebarLinks from '@theme/components/SidebarLinks.vue'
|
||||
import NavLinks from '@theme/components/NavLinks.vue'
|
||||
|
||||
export default {
|
||||
name: 'Sidebar',
|
||||
|
||||
components: { SidebarLinks, NavLinks },
|
||||
|
||||
props: ['items']
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.sidebar
|
||||
ul
|
||||
padding 0
|
||||
margin 0
|
||||
list-style-type none
|
||||
a
|
||||
display inline-block
|
||||
.nav-links
|
||||
display none
|
||||
border-bottom 1px solid $borderColor
|
||||
padding 0.5rem 0 0.75rem 0
|
||||
a
|
||||
font-weight 600
|
||||
.nav-item, .repo-link
|
||||
display block
|
||||
line-height 1.25rem
|
||||
font-size 1.1em
|
||||
padding 0.5rem 0 0.5rem 1.5rem
|
||||
& > .sidebar-links
|
||||
padding 1.5rem 0
|
||||
& > li > a.sidebar-link
|
||||
font-size 1.1em
|
||||
line-height 1.7
|
||||
font-weight bold
|
||||
& > li:not(:first-child)
|
||||
margin-top .75rem
|
||||
|
||||
@media (max-width: $MQMobile)
|
||||
.sidebar
|
||||
.nav-links
|
||||
display block
|
||||
.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after
|
||||
top calc(1rem - 2px)
|
||||
& > .sidebar-links
|
||||
padding 1rem 0
|
||||
</style>
|
@ -1,124 +0,0 @@
|
||||
<template>
|
||||
<div class="sidebar">
|
||||
<Search class="side-search-wrapper"></Search>
|
||||
<NavLinks/>
|
||||
<slot name="top"/>
|
||||
<ul class="sidebar-links" v-if="items.length">
|
||||
<li v-for="(item, i) in items" :key="i">
|
||||
<SidebarGroup
|
||||
v-if="item.type === 'group'"
|
||||
:item="item"
|
||||
:first="i === 0"
|
||||
:open="i === openGroupIndex"
|
||||
:collapsable="item.collapsable || item.collapsible"
|
||||
@toggle="toggleGroup(i)"/>
|
||||
<SidebarLink v-else :item="item"/>
|
||||
</li>
|
||||
</ul>
|
||||
<slot name="bottom"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SidebarGroup from '../SidebarGroup/'
|
||||
import SidebarLink from '../SidebarLink/'
|
||||
import NavLinks from '../NavLinks/'
|
||||
import Search from '../Search/'
|
||||
import { isActive } from '../../util/'
|
||||
|
||||
export default {
|
||||
components: { SidebarGroup, SidebarLink, NavLinks, Search },
|
||||
|
||||
props: ['items'],
|
||||
|
||||
data () {
|
||||
return {
|
||||
openGroupIndex: 0
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.refreshIndex()
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route' () {
|
||||
this.refreshIndex()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
refreshIndex () {
|
||||
const index = resolveOpenGroupIndex(
|
||||
this.$route,
|
||||
this.items
|
||||
)
|
||||
if (index > -1) {
|
||||
this.openGroupIndex = index
|
||||
}
|
||||
},
|
||||
|
||||
toggleGroup (index) {
|
||||
this.openGroupIndex = index === this.openGroupIndex ? -1 : index
|
||||
},
|
||||
|
||||
isActive (page) {
|
||||
return isActive(this.$route, page.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveOpenGroupIndex (route, items) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i]
|
||||
if (item.type === 'group' && item.children.some(c => isActive(route, c.path))) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@import '../../styles/config.styl'
|
||||
|
||||
.sidebar
|
||||
-moz-user-select:none;/*火狐*/
|
||||
-webkit-user-select:none;/*webkit浏览器*/
|
||||
-ms-user-select:none;/*IE10*/
|
||||
-khtml-user-select:none;/*早期浏览器*/
|
||||
user-select:none;
|
||||
ul
|
||||
padding 0
|
||||
margin 0
|
||||
list-style-type none
|
||||
a
|
||||
display inline-block
|
||||
.nav-links
|
||||
display none
|
||||
border-bottom 1px solid $borderColor
|
||||
padding 0.5rem 0 0.75rem 0
|
||||
a
|
||||
font-weight 600
|
||||
.nav-item, .repo-link
|
||||
display block
|
||||
line-height 1.25rem
|
||||
font-size 1.1em
|
||||
padding 0.5rem 0 0.5rem 1.5rem
|
||||
.sidebar-links
|
||||
padding 1.5rem 0
|
||||
.side-search-wrapper
|
||||
padding: 0.5rem 0 0.5rem 1.5rem;
|
||||
display none
|
||||
|
||||
@media (max-width: $MQMobile)
|
||||
.sidebar
|
||||
.nav-links
|
||||
display block
|
||||
.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after
|
||||
top calc(1rem - 2px)
|
||||
.sidebar-links
|
||||
padding 1rem 0
|
||||
.side-search-wrapper
|
||||
display block
|
||||
</style>
|
27
components/SidebarButton.vue
Normal file
27
components/SidebarButton.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div class="sidebar-button" @click="$emit('toggle-sidebar')">
|
||||
<svg class="icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512">
|
||||
<path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z" class=""></path>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="stylus">
|
||||
.sidebar-button
|
||||
cursor pointer
|
||||
display none
|
||||
width 1.25rem
|
||||
height 1.25rem
|
||||
position absolute
|
||||
padding 0.6rem
|
||||
top 0.6rem
|
||||
left 1rem
|
||||
.icon
|
||||
display block
|
||||
width 1.25rem
|
||||
height 1.25rem
|
||||
|
||||
@media (max-width: $MQMobile)
|
||||
.sidebar-button
|
||||
display block
|
||||
</style>
|
129
components/SidebarGroup.vue
Normal file
129
components/SidebarGroup.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<section
|
||||
class="sidebar-group"
|
||||
:class="[
|
||||
{
|
||||
collapsable,
|
||||
'is-sub-group': depth !== 0
|
||||
},
|
||||
`depth-${depth}`
|
||||
]"
|
||||
>
|
||||
<router-link
|
||||
v-if="item.path"
|
||||
class="sidebar-heading clickable"
|
||||
:class="{
|
||||
open,
|
||||
'active': isActive($route, item.path)
|
||||
}"
|
||||
:to="item.path"
|
||||
@click.native="$emit('toggle')"
|
||||
>
|
||||
<span>{{ item.title }}</span>
|
||||
<span
|
||||
class="arrow"
|
||||
v-if="collapsable"
|
||||
:class="open ? 'down' : 'right'">
|
||||
</span>
|
||||
</router-link>
|
||||
|
||||
<p
|
||||
v-else
|
||||
class="sidebar-heading"
|
||||
:class="{ open }"
|
||||
@click="$emit('toggle')"
|
||||
>
|
||||
<span>{{ item.title }}</span>
|
||||
<span
|
||||
class="arrow"
|
||||
v-if="collapsable"
|
||||
:class="open ? 'down' : 'right'">
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<DropdownTransition>
|
||||
<SidebarLinks
|
||||
class="sidebar-group-items"
|
||||
:items="item.children"
|
||||
v-if="open || !collapsable"
|
||||
:sidebarDepth="item.sidebarDepth"
|
||||
:depth="depth + 1"
|
||||
/>
|
||||
</DropdownTransition>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { isActive } from '../util'
|
||||
import DropdownTransition from '@theme/components/DropdownTransition.vue'
|
||||
|
||||
export default {
|
||||
name: 'SidebarGroup',
|
||||
props: ['item', 'open', 'collapsable', 'depth'],
|
||||
components: { DropdownTransition },
|
||||
// ref: https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
|
||||
beforeCreate () {
|
||||
this.$options.components.SidebarLinks = require('./SidebarLinks.vue').default
|
||||
},
|
||||
methods: { isActive }
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.sidebar-group
|
||||
.sidebar-group
|
||||
padding-left 0.5em
|
||||
&:not(.collapsable)
|
||||
.sidebar-heading:not(.clickable)
|
||||
cursor auto
|
||||
color inherit
|
||||
// refine styles of nested sidebar groups
|
||||
&.is-sub-group
|
||||
padding-left 0
|
||||
& > .sidebar-heading
|
||||
font-size 0.95em
|
||||
line-height 1.4
|
||||
font-weight normal
|
||||
padding-left 2rem
|
||||
&:not(.clickable)
|
||||
opacity 0.5
|
||||
& > .sidebar-group-items
|
||||
padding-left 1rem
|
||||
& > li > .sidebar-link
|
||||
font-size: 0.95em;
|
||||
border-left none
|
||||
&.depth-2
|
||||
& > .sidebar-heading
|
||||
border-left none
|
||||
|
||||
.sidebar-heading
|
||||
color $textColor
|
||||
transition color .15s ease
|
||||
cursor pointer
|
||||
font-size 1.1em
|
||||
font-weight bold
|
||||
// text-transform uppercase
|
||||
padding 0.35rem 1.5rem 0.35rem 1.25rem
|
||||
width 100%
|
||||
box-sizing border-box
|
||||
margin 0
|
||||
border-left 0.25rem solid transparent
|
||||
&.open, &:hover
|
||||
color inherit
|
||||
.arrow
|
||||
position relative
|
||||
top -0.12em
|
||||
left 0.5em
|
||||
&.clickable
|
||||
&.active
|
||||
font-weight 600
|
||||
color $accentColor
|
||||
border-left-color $accentColor
|
||||
&:hover
|
||||
color $accentColor
|
||||
|
||||
.sidebar-group-items
|
||||
transition height .1s ease-out
|
||||
font-size 0.95em
|
||||
overflow hidden
|
||||
</style>
|
@ -1,76 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="sidebar-group"
|
||||
:class="{ first, collapsable }">
|
||||
<p
|
||||
class="sidebar-heading"
|
||||
:class="{ open }"
|
||||
@click="$emit('toggle')">
|
||||
<span>{{ item.title }}</span>
|
||||
<span
|
||||
class="arrow"
|
||||
v-if="collapsable"
|
||||
:class="open ? 'down' : 'right'">
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<DropdownTransition>
|
||||
<ul
|
||||
ref="items"
|
||||
class="sidebar-group-items"
|
||||
v-if="open || !collapsable">
|
||||
<li
|
||||
v-for="(child, index) in item.children"
|
||||
:key="index">
|
||||
<SidebarLink :item="child"/>
|
||||
</li>
|
||||
</ul>
|
||||
</DropdownTransition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SidebarLink from '../SidebarLink/'
|
||||
import DropdownTransition from '../DropdownTransition/'
|
||||
|
||||
export default {
|
||||
name: 'SidebarGroup',
|
||||
props: ['item', 'first', 'open', 'collapsable'],
|
||||
components: { SidebarLink, DropdownTransition }
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
.sidebar-group
|
||||
&:not(.first)
|
||||
margin-top 1em
|
||||
.sidebar-group
|
||||
padding-left 0.5em
|
||||
&:not(.collapsable)
|
||||
.sidebar-heading
|
||||
cursor auto
|
||||
color inherit
|
||||
|
||||
.sidebar-heading
|
||||
color #999
|
||||
transition color .15s ease
|
||||
cursor pointer
|
||||
font-size 1.1em
|
||||
font-weight bold
|
||||
// text-transform uppercase
|
||||
padding 0 1.5rem
|
||||
margin-top 0
|
||||
margin-bottom 0.5rem
|
||||
&.open, &:hover
|
||||
color inherit
|
||||
.arrow
|
||||
position relative
|
||||
top -0.12em
|
||||
left 0.5em
|
||||
&:.open .arrow
|
||||
top -0.18em
|
||||
|
||||
.sidebar-group-items
|
||||
transition height .1s ease-out
|
||||
overflow hidden
|
||||
</style>
|
@ -1,12 +1,25 @@
|
||||
<script>
|
||||
import { isActive, hashRE, groupHeaders } from '../../util/'
|
||||
import { isActive, hashRE, groupHeaders } from '../util'
|
||||
|
||||
export default {
|
||||
functional: true,
|
||||
|
||||
props: ['item'],
|
||||
props: ['item', 'sidebarDepth'],
|
||||
|
||||
render (h, { parent: { $page, $site, $route }, props: { item }}) {
|
||||
render (h,
|
||||
{
|
||||
parent: {
|
||||
$page,
|
||||
$site,
|
||||
$route,
|
||||
$themeConfig,
|
||||
$themeLocaleConfig
|
||||
},
|
||||
props: {
|
||||
item,
|
||||
sidebarDepth
|
||||
}
|
||||
}) {
|
||||
// use custom active class matching logic
|
||||
// due to edge case of paths ending with / + hash
|
||||
const selfActive = isActive($route, item.path)
|
||||
@ -16,11 +29,17 @@ export default {
|
||||
? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
|
||||
: selfActive
|
||||
const link = renderLink(h, item.path, item.title || item.path, active)
|
||||
const configDepth = $page.frontmatter.sidebarDepth != null
|
||||
? $page.frontmatter.sidebarDepth
|
||||
: $site.themeConfig.sidebarDepth
|
||||
|
||||
const configDepth = $page.frontmatter.sidebarDepth
|
||||
|| sidebarDepth
|
||||
|| $themeLocaleConfig.sidebarDepth
|
||||
|| $themeConfig.sidebarDepth
|
||||
|
||||
const maxDepth = configDepth == null ? 1 : configDepth
|
||||
const displayAllHeaders = !!$site.themeConfig.displayAllHeaders
|
||||
|
||||
const displayAllHeaders = $themeLocaleConfig.displayAllHeaders
|
||||
|| $themeConfig.displayAllHeaders
|
||||
|
||||
if (item.type === 'auto') {
|
||||
return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
|
||||
} else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {
|
||||
@ -59,13 +78,12 @@ function renderChildren (h, children, path, route, maxDepth, depth = 1) {
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
@import '../../styles/config.styl'
|
||||
|
||||
.sidebar .sidebar-sub-headers
|
||||
padding-left 1rem
|
||||
font-size 0.95em
|
||||
|
||||
a.sidebar-link
|
||||
font-size 1em
|
||||
font-weight 400
|
||||
display inline-block
|
||||
color $textColor
|
86
components/SidebarLinks.vue
Normal file
86
components/SidebarLinks.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<ul
|
||||
class="sidebar-links"
|
||||
v-if="items.length"
|
||||
>
|
||||
<li v-for="(item, i) in items" :key="i">
|
||||
<SidebarGroup
|
||||
v-if="item.type === 'group'"
|
||||
:item="item"
|
||||
:open="i === openGroupIndex"
|
||||
:collapsable="item.collapsable || item.collapsible"
|
||||
:depth="depth"
|
||||
@toggle="toggleGroup(i)"
|
||||
/>
|
||||
<SidebarLink
|
||||
v-else
|
||||
:sidebarDepth="sidebarDepth"
|
||||
:item="item"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SidebarGroup from '@theme/components/SidebarGroup.vue'
|
||||
import SidebarLink from '@theme/components/SidebarLink.vue'
|
||||
import { isActive } from '../util'
|
||||
|
||||
export default {
|
||||
name: 'SidebarLinks',
|
||||
|
||||
components: { SidebarGroup, SidebarLink },
|
||||
|
||||
props: [
|
||||
'items',
|
||||
'depth', // depth of current sidebar links
|
||||
'sidebarDepth' // depth of headers to be extracted
|
||||
],
|
||||
|
||||
data () {
|
||||
return {
|
||||
openGroupIndex: 0
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.refreshIndex()
|
||||
},
|
||||
|
||||
watch: {
|
||||
'$route' () {
|
||||
this.refreshIndex()
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
refreshIndex () {
|
||||
const index = resolveOpenGroupIndex(
|
||||
this.$route,
|
||||
this.items
|
||||
)
|
||||
if (index > -1) {
|
||||
this.openGroupIndex = index
|
||||
}
|
||||
},
|
||||
|
||||
toggleGroup (index) {
|
||||
this.openGroupIndex = index === this.openGroupIndex ? -1 : index
|
||||
},
|
||||
|
||||
isActive (page) {
|
||||
return isActive(this.$route, page.regularPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveOpenGroupIndex (route, items) {
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i]
|
||||
if (item.type === 'group' && item.children.some(c => c.type === 'page' && isActive(route, c.path))) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
</script>
|
124
components/Theme/ThemeOptions.vue
Executable file
124
components/Theme/ThemeOptions.vue
Executable file
@ -0,0 +1,124 @@
|
||||
<template>
|
||||
<div class="theme-options">
|
||||
<ul v-if="reco.hasThemes" class="color-theme-options">
|
||||
<li>
|
||||
<a href="#" class="default-theme" @click.prevent="setTheme()"></a>
|
||||
</li>
|
||||
<li v-for="color in reco.themes" :key="color">
|
||||
<a href="#" :class="`${color}-theme`" :style="{background: colors[color]}" @click.prevent="setTheme(color)"></a>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-if="!reco.disableDarkTheme" class="dark-theme-options toggle-option">
|
||||
<label for="dark-theme-toggle">Enable Dark Theme?</label>
|
||||
<input id="dark-theme-toggle" v-model="darkTheme" type="checkbox" @change="toggleDarkTheme" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import recoConfig from './recoConfig.js';
|
||||
|
||||
export default {
|
||||
name: 'ThemeOptions',
|
||||
|
||||
mixins: [recoConfig],
|
||||
|
||||
data() {
|
||||
return {
|
||||
darkTheme: 'false'
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
const theme = localStorage.getItem('reco-theme')
|
||||
const night = localStorage.getItem('reco-night')
|
||||
const classes = document.body.classList;
|
||||
|
||||
this.darkTheme = night === 'true' ? true : false
|
||||
if (night === 'true') classes.add(`reco-theme-night`)
|
||||
if (theme) this.setTheme(theme)
|
||||
},
|
||||
|
||||
methods: {
|
||||
toggleDarkTheme() {
|
||||
console.log(123, this.darkTheme)
|
||||
localStorage.setItem('reco-night', this.darkTheme)
|
||||
console.log(456, localStorage.getItem('reco-night'))
|
||||
const classes = document.body.classList;
|
||||
if (this.darkTheme) {
|
||||
const oldColor = [...classes]
|
||||
classes.value = ''
|
||||
classes.add(`reco-theme-night`)
|
||||
oldColor.forEach(item => {
|
||||
classes.add(item)
|
||||
})
|
||||
}
|
||||
else {
|
||||
classes.remove(`reco-theme-night`)
|
||||
}
|
||||
},
|
||||
setTheme(theme, moveClass = true) {
|
||||
const colorThemes = this.reco.themes;
|
||||
|
||||
const classes = document.body.classList;
|
||||
const themes = colorThemes.map(colorTheme => `reco-theme-${colorTheme}`);
|
||||
|
||||
if (!theme) {
|
||||
if (moveClass) localStorage.removeItem('reco-theme');
|
||||
classes.remove(...themes);
|
||||
return
|
||||
}
|
||||
|
||||
classes.remove(...themes.filter(t => t !== `reco-theme-${theme}`));
|
||||
|
||||
if (moveClass) {
|
||||
classes.add(`reco-theme-${theme}`);
|
||||
localStorage.setItem('reco-theme', theme);
|
||||
} else {
|
||||
localStorage.removeItem('reco-theme')
|
||||
classes.remove(`reco-theme-${theme}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
|
||||
.color-theme-options {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
li {
|
||||
width: 33%;
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
border-radius: 2px;
|
||||
|
||||
&.default-theme {
|
||||
background-color: $accentColor;
|
||||
}
|
||||
|
||||
&.blue-theme {
|
||||
background-color: $blueAccentColor;
|
||||
}
|
||||
|
||||
&.red-theme {
|
||||
background-color: $redAccentColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toggle-option {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
label {
|
||||
padding-right: 0.25em;
|
||||
}
|
||||
}
|
||||
</style>
|
140
components/Theme/index.vue
Executable file
140
components/Theme/index.vue
Executable file
@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div v-if="showSettings" v-click-outside="hideMenu" class="color-picker">
|
||||
<a class="color-button" href="#" @click.prevent="showMenu = !showMenu">
|
||||
<i class="iconfont reco-color"></i>
|
||||
</a>
|
||||
<transition name="menu-transition" mode="out-in">
|
||||
<div v-show="showMenu" class="color-picker-menu">
|
||||
<ThemeOptions />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ClickOutside from 'vue-click-outside';
|
||||
import ThemeOptions from './ThemeOptions.vue';
|
||||
import recoConfig from './recoConfig.js';
|
||||
|
||||
export default {
|
||||
name: 'UserSettings',
|
||||
|
||||
directives: {
|
||||
'click-outside': ClickOutside,
|
||||
},
|
||||
|
||||
components: {
|
||||
ThemeOptions
|
||||
},
|
||||
|
||||
mixins: [recoConfig],
|
||||
|
||||
data() {
|
||||
return {
|
||||
showMenu: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
showSettings() {
|
||||
const { reco } = this;
|
||||
return reco.hasThemes || reco.disableDarkTheme !== true || reco.disableThemeIgnore !== true;
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
hideMenu() {
|
||||
this.showMenu = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="stylus">
|
||||
|
||||
.color-picker {
|
||||
position: relative;
|
||||
margin-right: 1em;
|
||||
|
||||
.color-button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
.iconfont {
|
||||
font-size 1.4rem
|
||||
color: $accentColor
|
||||
}
|
||||
.settings-icon {
|
||||
width: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.color-picker-menu {
|
||||
background-color: #fff;
|
||||
position: absolute;
|
||||
top: 40px;
|
||||
left: 50%;
|
||||
min-width: 100px;
|
||||
margin: 0;
|
||||
padding: 1em;
|
||||
border: 1px solid $borderColor;
|
||||
border-radius: 4px;
|
||||
transform: translateX(-50%);
|
||||
z-index: 150;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -7px;
|
||||
left: 50%;
|
||||
border-style: solid;
|
||||
border-color: transparent transparent $borderColor;
|
||||
border-width: 0 7px 7px;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
&.menu-transition-enter-active,
|
||||
&.menu-transition-leave-active {
|
||||
transition: all 0.25s ease-in-out;
|
||||
}
|
||||
|
||||
&.menu-transition-enter,
|
||||
&.menu-transition-leave-to {
|
||||
top: 50px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reco-theme-dark {
|
||||
.color-picker-menu {
|
||||
background-color: $darkPrimaryBg;
|
||||
border-color: $darkBorderColor;
|
||||
|
||||
&::before {
|
||||
border-bottom-color: $darkBorderColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $MQMobile) {
|
||||
.color-picker {
|
||||
margin-right: 0;
|
||||
|
||||
.color-picker-menu {
|
||||
left: calc(50% - 35px);
|
||||
|
||||
&::before {
|
||||
left: calc(50% + 35px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
22
components/Theme/recoConfig.js
Executable file
22
components/Theme/recoConfig.js
Executable file
@ -0,0 +1,22 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
reco: {},
|
||||
colors: {
|
||||
blue: '#2196f3',
|
||||
red: '#f26d6d',
|
||||
green: '#3eaf7c',
|
||||
orange: '#fb9b5f'
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.reco = {
|
||||
themes: ['blue', 'red', 'green', 'orange'],
|
||||
disableDarkTheme: false
|
||||
};
|
||||
|
||||
this.reco.hasThemes = this.$site.themeConfig.themePicker || true
|
||||
},
|
||||
};
|
189
components/TimeLine.vue
Normal file
189
components/TimeLine.vue
Normal file
@ -0,0 +1,189 @@
|
||||
<template>
|
||||
<div>
|
||||
<ul class="timeline-wrapper">
|
||||
<li class="desc">Yesterday Once More!</li>
|
||||
<li v-for="(item, index) in formatPagesArr" :key="index">
|
||||
<h3 class="year">{{item.year}}</h3>
|
||||
<ul class="year-wrapper">
|
||||
<li v-for="(subItem, subIndex) in item.data" :key="subIndex">
|
||||
<span class="date">{{dateFormat(new Date(subItem.frontmatter.date))}}</span>
|
||||
<span class="title" @click="go(subItem.path)">{{subItem.title}}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'TimeLine',
|
||||
data () {
|
||||
return {
|
||||
pages: [],
|
||||
tags: [],
|
||||
currentTag: '',
|
||||
currentPage: 1,
|
||||
formatPages: {},
|
||||
formatPagesArr: []
|
||||
}
|
||||
},
|
||||
props: {
|
||||
tag: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
trueCurrentTag () {
|
||||
return this.currentTag
|
||||
}
|
||||
},
|
||||
created () {
|
||||
this.getPages()
|
||||
},
|
||||
methods: {
|
||||
// 根据分类获取页面数据
|
||||
getPages (tag) {
|
||||
let pages = this.$site.pages
|
||||
pages = pages.filter(item => {
|
||||
const { home, isTimeLine, date } = item.frontmatter
|
||||
return !(home == true || isTimeLine == true || date === undefined)
|
||||
})
|
||||
// reverse()是为了按时间最近排序排序
|
||||
this.pages = pages.length == 0 ? [] : pages
|
||||
for (let i = 0, length = pages.length; i < length; i++) {
|
||||
const page = pages[i]
|
||||
const pageDateYear = this.dateFormat(page.frontmatter.date, 'year')
|
||||
if (this.formatPages[pageDateYear]) this.formatPages[pageDateYear].push(page)
|
||||
else {
|
||||
this.formatPages[pageDateYear] = [page]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for(let key in this.formatPages) {
|
||||
this.formatPagesArr.unshift({
|
||||
year: key,
|
||||
data: this.formatPages[key].sort((a, b) => {
|
||||
return this._getTimeNum(b) - this._getTimeNum(a)
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
// 时间格式化
|
||||
dateFormat (date, type) {
|
||||
const dateObj = new Date(date)
|
||||
const year = dateObj.getFullYear()
|
||||
const mon = dateObj.getMonth() + 1
|
||||
const day = dateObj.getDate()
|
||||
if (type == 'year') return year
|
||||
else return `${mon}-${day}`
|
||||
},
|
||||
// 跳转
|
||||
go (url) {
|
||||
this.$router.push({path: url})
|
||||
},
|
||||
// 获取时间的数字类型
|
||||
_getTimeNum (date) {
|
||||
return parseInt(new Date(date.frontmatter.date).getTime())
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@require '../styles/wrapper.styl'
|
||||
|
||||
.timeline-wrapper
|
||||
box-sizing border-box
|
||||
max-width: 740px;
|
||||
margin: 0 auto;
|
||||
position relative
|
||||
list-style none
|
||||
&::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
left: 0;
|
||||
margin-left: -2px;
|
||||
width: 4px;
|
||||
height: 100%;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
.desc, .year {
|
||||
position: relative;
|
||||
color #666
|
||||
font-size 16px
|
||||
&:before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
z-index 2;
|
||||
left: -19px;
|
||||
top: 50%;
|
||||
margin-left: -4px;
|
||||
margin-top: -4px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: #ddd;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
.year {
|
||||
margin: 80px 0 0px;
|
||||
color #555
|
||||
font-weight: 700;
|
||||
font-size 26px
|
||||
}
|
||||
.year-wrapper {
|
||||
padding-left 0!important
|
||||
li {
|
||||
display flex
|
||||
padding 30px 0 10px
|
||||
list-style none
|
||||
border-bottom: 1px dashed #ccc;
|
||||
position relative
|
||||
&:hover {
|
||||
.date {
|
||||
color $accentColor
|
||||
&::before {
|
||||
background $accentColor
|
||||
}
|
||||
}
|
||||
.title {
|
||||
color $accentColor
|
||||
}
|
||||
}
|
||||
.date {
|
||||
width 40px
|
||||
line-height 30px
|
||||
color: #555;
|
||||
font-size 12px
|
||||
&::before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
left: -19px;
|
||||
top: 41px;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
margin-left: -4px;
|
||||
background: #ddd;
|
||||
border-radius: 50%;
|
||||
border: 1px solid #fff;
|
||||
z-index 2
|
||||
}
|
||||
}
|
||||
.title {
|
||||
line-height 30px
|
||||
color: #555;
|
||||
font-size 16px
|
||||
cursor pointer
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: $MQMobile)
|
||||
.timeline-wrapper
|
||||
margin: 0 1.2rem;
|
||||
</style>
|
@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<<<<<<< HEAD
|
||||
<div class="valine-wrapper" v-show="isComment">
|
||||
=======
|
||||
<div class="valine-wrapper" v-show="isShowComment">
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
<div id="valine"></div>
|
||||
</div>
|
||||
</template>
|
||||
@ -8,12 +12,21 @@
|
||||
|
||||
|
||||
export default {
|
||||
<<<<<<< HEAD
|
||||
props: ['valineRefresh'],
|
||||
computed: {
|
||||
// 是否显示评论
|
||||
isComment () {
|
||||
const frontmatter = this.$page.frontmatter
|
||||
return frontmatter.isComment == false || frontmatter.home == true ? false : true
|
||||
=======
|
||||
props: ['isComment'],
|
||||
computed: {
|
||||
// 是否显示评论
|
||||
isShowComment () {
|
||||
const frontmatter = this.$page.frontmatter
|
||||
return this.isComment == false || frontmatter.isComment == false || frontmatter.home == true ? false : true
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
}
|
||||
},
|
||||
mounted: function(){
|
||||
@ -28,7 +41,10 @@ export default {
|
||||
if (typeof window !== 'undefined') {
|
||||
this.window = window
|
||||
window.AV = AV
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
}
|
||||
|
||||
new Valine({
|
||||
@ -41,7 +57,10 @@ export default {
|
||||
path: window.location.pathname,
|
||||
placeholder: 'just go go'
|
||||
});
|
||||
<<<<<<< HEAD
|
||||
this.valineRefresh = false
|
||||
=======
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -55,6 +74,7 @@ export default {
|
||||
}, 300)
|
||||
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
},
|
||||
'valineRefresh' (val) {
|
||||
if (val) {
|
||||
@ -62,12 +82,15 @@ export default {
|
||||
this.createValine()
|
||||
}, 300)
|
||||
}
|
||||
=======
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
<<<<<<< HEAD
|
||||
@import '../../styles/config.styl'
|
||||
|
||||
.valine-wrapper
|
||||
@ -78,4 +101,27 @@ export default {
|
||||
@media (max-width: $MQMobile)
|
||||
.valine-wrapper
|
||||
padding 1rem
|
||||
=======
|
||||
|
||||
.theme-container.no-sidebar
|
||||
.valine-wrapper
|
||||
padding-left 0
|
||||
|
||||
.valine-wrapper
|
||||
background-color $bgColor
|
||||
padding-left: 20rem;
|
||||
#valine
|
||||
padding 2rem
|
||||
max-width: 740px;
|
||||
margin: 0 auto;
|
||||
@media (max-width: $MQNarrow)
|
||||
.theme-container.no-sidebar
|
||||
.valine-wrapper
|
||||
padding-left 0
|
||||
.valine-wrapper
|
||||
padding-left: 16.4rem;
|
||||
@media (max-width: $MQMobile)
|
||||
.valine-wrapper
|
||||
padding-left: 0;
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
</style>
|
||||
|
@ -1,10 +1,19 @@
|
||||
@font-face {font-family: "iconfont";
|
||||
<<<<<<< HEAD
|
||||
src: url('iconfont.eot?t=1548606483811'); /* IE9 */
|
||||
src: url('iconfont.eot?t=1548606483811#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
|
||||
url('iconfont.woff?t=1548606483811') format('woff'),
|
||||
url('iconfont.ttf?t=1548606483811') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
|
||||
url('iconfont.svg?t=1548606483811#iconfont') format('svg'); /* iOS 4.1- */
|
||||
=======
|
||||
src: url('iconfont.eot?t=1555230336940'); /* IE9 */
|
||||
src: url('iconfont.eot?t=1555230336940#iefix') format('embedded-opentype'), /* IE6-IE8 */
|
||||
url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'),
|
||||
url('iconfont.woff?t=1555230336940') format('woff'),
|
||||
url('iconfont.ttf?t=1555230336940') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
|
||||
url('iconfont.svg?t=1555230336940#iconfont') format('svg'); /* iOS 4.1- */
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@ -15,6 +24,13 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
.reco-color:before {
|
||||
content: "\eae9";
|
||||
}
|
||||
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
.reco-message:before {
|
||||
content: "\e634";
|
||||
}
|
||||
|
@ -20,6 +20,12 @@ Created by iconfont
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
<glyph glyph-name="color" unicode="" d="M778.22179555 384q29.56401778 0 51.21517 20.48606777t21.60260778 52.33171001-21.60260778 52.33171001-51.21517 20.48606776-51.21516998-20.48606776-21.60260779-52.33171001 21.60260779-52.33171001 51.21516998-20.48606777zM632.58624 577.40401778q29.56401778 0 51.21516999 21.60260779t21.60260779 51.21516998-21.60260779 51.21517-51.21516999 21.60260778-51.21516999-21.60260778-21.60260779-51.21517 21.60260779-51.21516998 51.21516999-21.60260779zM391.41376 577.40401778q29.56401778 0 51.21516999 21.60260779t21.60260779 51.21516998-21.60260779 51.21517-51.21516999 21.60260778-51.21516999-21.60260778-21.60260779-51.21517 21.60260779-51.21516998 51.21516999-21.60260779zM245.77820445 384q29.56401778 0 51.21516998 20.48606777t21.60260779 52.33171001-21.60260779 52.33171001-51.21516998 20.48606776-51.21517-20.48606776-21.60260778-52.33171001 21.60260778-52.33171001 51.21517-20.48606777zM512 820.90666667q179.76282112 0 308.35901667-113.78991446t128.54765-275.34828999q0-100.14871666-71.7012389-170.68487111t-171.80140999-70.53615445l-84.17735111 0q-31.8456411 0-52.33171001-21.60260779t-20.48606777-51.21516999q0-25.04931555 18.20444444-47.76846222t18.20444445-50.05008555q0-31.8456411-20.48606777-52.33171001t-52.33171001-20.48606777q-182.04444445 0-309.47555555 127.43111112t-127.43111112 309.47555555 127.43111112 309.47555555 309.47555555 127.43111112z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
<glyph glyph-name="message" unicode="" d="M864.227 791.373h-702c-48.988 0-88.732-39.621-88.732-88.487v-519.688c0-48.866 42.607-84.866 91.616-84.866h218.638l122.113-106.65 122.134 106.65h233.366c48.988 0 91.596 36.021 91.596 84.866v519.688c0 48.866-39.763 88.487-88.732 88.487zM685.393 342.72299999999996h-309.702c-17.202 0-31.152 13.95-31.152 31.152s13.95 31.152 31.152 31.152h309.702c17.223 0 31.152-13.95 31.152-31.152s-13.95-31.152-31.152-31.152zM759.029 505.848h-484.343c-17.202 0-31.152 13.95-31.152 31.152 0 17.223 13.95 31.173 31.152 31.173h484.343c17.202 0 31.152-13.95 31.152-31.173 0.021-17.202-13.95-31.152-31.152-31.152z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
@ -80,7 +86,11 @@ Created by iconfont
|
||||
<glyph glyph-name="jianshu" unicode="" d="M0 384v-512h1024V896H0v-512z m356.864 331.776c-1.024-6.656-4.096-15.872-6.144-20.48-3.584-8.704 2.048-9.216 78.848-9.216H512v-51.2h-43.52c-24.064 0-43.52-0.512-43.52-1.024 0-1.024 4.608-16.384 10.24-34.816 5.632-18.432 10.24-33.792 10.24-34.304 0-1.024-18.432-1.536-40.448-1.536h-40.448l-3.584 16.896c-9.216 45.056-13.824 54.784-27.136 54.784-7.68 0-21.504-8.192-35.328-20.992-22.016-19.968-71.168-46.592-99.84-53.76-14.336-3.072-14.336-3.072-14.336 22.528 0 23.552 1.024 26.112 19.968 38.4 25.088 16.384 41.984 38.912 59.392 76.8l13.312 29.184h41.472c39.936 0 40.96-0.512 38.4-11.264z m306.688-6.656l-3.584-17.92h179.712v-56.32h-96.768l10.24-29.184c14.848-43.008 15.36-42.496-28.16-42.496h-37.888l-3.584 16.896c-2.048 8.704-6.144 25.088-8.704 35.84-5.12 17.92-7.168 18.944-25.6 18.944-16.384 0-23.552-3.584-41.472-20.992-19.456-18.944-76.288-50.176-104.448-58.368-10.752-3.072-11.776-1.536-11.776 18.944 0 20.992 2.048 24.576 27.648 46.592 25.6 22.016 49.152 59.392 61.44 97.28 2.048 7.168 9.216 8.704 44.544 8.704h41.472l-3.072-17.92z m-317.44-162.304c4.608-8.704 13.824-32.256 20.48-51.2 13.824-41.472 14.336-40.96-36.352-38.912l-34.816 1.536-11.264 35.84c-6.144 19.968-14.848 43.52-19.968 52.736L255.488 563.2h40.96c40.96 0 41.472 0 49.664-16.384z m462.848-225.792c0-200.192-0.512-217.6-9.216-233.984-15.872-28.672-40.448-37.888-103.424-38.4h-53.76l-1.536 29.696-1.536 29.184h33.792c29.184 0 35.328 1.536 46.08 12.8l12.8 12.288V476.16H384V537.6h424.96v-216.576zM291.84 243.2v-202.24h-76.8V445.44h76.8V243.2z m363.52 57.344c0-182.784 4.608-177.664-167.424-177.664H373.76V424.96h281.6v-124.416zM450.56 335.36v-33.28h128V368.64h-128v-33.28zM450.56 215.04v-35.84h55.808c65.024 0 69.12 2.56 69.632 43.008v26.112l-62.464 1.536-62.976 1.536v-36.352z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
<glyph glyph-name="theme" unicode="" d="M949.6 535.4s-0.1 0-0.1 0.1L755.1 729.4c-15.6 25.3-43.4 42.4-75.4 42.4h-55.5c-16.2 0-29.7-11.6-32.7-27l-0.6-0.9v1.2c-0.8-2-2-3.9-3.4-5.9-9.4-32.3-38.9-56-74.3-56-31 0-57.6 18.3-70.1 44.5l-0.4 0.3c-0.1 0.4-0.3 0.8-0.4 1.2-0.9 2-1.5 4.1-2.3 6.2-1.4 3.6-3 7.1-4.6 10.6v-5.3h-0.2c-0.2 3.6-1 7.1-2.2 10.3-0.7 1.5-1.5 3-2.3 4.5-5.8 9.8-16.3 16.4-28.5 16.4-2 0-3.9-0.3-5.9-0.7-1 0.5-2.1 0.7-3.2 0.7-0.7 0-1.4-0.2-2.1-0.4v0.4h-44.4c-28.9 0-54.3-14-70.6-35.3l-201.4-201s-0.1 0-0.1-0.1c-13-13-13-34 0-47l141.3-141c11.5-11.5 28.9-12.2 41.9-3.4v-325.6h2.2c4.6-12.9 16.6-22.2 31.1-22.2h444.2c14.5 0 26.5 9.3 31.1 22.2h2.2v324c12.7-7.2 28.9-5.9 39.7 4.9l141.3 141c13.1 13 13.1 34 0.1 47z" horiz-adv-x="1024" />
|
||||
=======
|
||||
<glyph glyph-name="theme" unicode="" d="M978.77333333 545.49333333s-0.10666667 0-0.10666666 0.10666667L771.30666667 752.42666667c-16.64 26.98666667-46.29333333 45.22666667-80.42666667 45.22666666h-59.2c-17.28 0-31.68-12.37333333-34.88-28.8l-0.64-0.96v1.28c-0.85333333-2.13333333-2.13333333-4.16-3.62666667-6.29333333-10.02666667-34.45333333-41.49333333-59.73333333-79.25333333-59.73333333-33.06666667 0-61.44 19.52-74.77333333 47.46666666l-0.42666667 0.32c-0.10666667 0.42666667-0.32 0.85333333-0.42666667 1.28-0.96 2.13333333-1.6 4.37333333-2.45333333 6.61333334-1.49333333 3.84-3.2 7.57333333-4.90666667 11.30666666v-5.65333333h-0.21333333c-0.21333333 3.84-1.06666667 7.57333333-2.34666667 10.98666667-0.74666667 1.6-1.6 3.2-2.45333333 4.8-6.18666667 10.45333333-17.38666667 17.49333333-30.4 17.49333333-2.13333333 0-4.16-0.32-6.29333333-0.74666667-1.06666667 0.53333333-2.24 0.74666667-3.41333334 0.74666667-0.74666667 0-1.49333333-0.21333333-2.24-0.42666667v0.42666667h-47.36c-30.82666667 0-57.92-14.93333333-75.30666666-37.65333333l-214.82666667-214.4s-0.10666667 0-0.10666667-0.10666667c-13.86666667-13.86666667-13.86666667-36.26666667 0-50.13333333l150.72-150.4c12.26666667-12.26666667 30.82666667-13.01333333 44.69333334-3.62666667v-347.30666667h2.34666666c4.90666667-13.76 17.70666667-23.68 33.17333334-23.68h473.81333333c15.46666667 0 28.26666667 9.92 33.17333333 23.68h2.34666667v345.6c13.54666667-7.68 30.82666667-6.29333333 42.34666667 5.22666667l150.72 150.4c13.97333333 13.86666667 13.97333333 36.26666667 0.10666666 50.13333333z" horiz-adv-x="1024" />
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
|
||||
|
||||
<glyph glyph-name="three" unicode="" d="M861.798876 266.798732C835.998959 320.998557 830.598976 331.29852400000004 806.999052 385.398351c-12.59996 28.799907-38.399877 46.79985-61.899801 52.69983l62.499799 294.499054c9.29997 43.899859-18.299941 86.99972-61.699801 96.39969-43.399861 9.39997-86.099723-18.59994-95.399694-62.499799l-58.099813-273.79912-3.699988 322.598963C587.999756 860.296825 551.599873 896.396709 507.200015 895.99671c-44.499857-0.299999-79.999743-36.999881-79.499744-81.799737l3.499989-304.299022-66.199788 248.999199c-11.499963 43.299861-55.599821 68.999778-98.499683 57.399816-42.899862-11.599963-68.299781-56.199819-56.799818-99.49968L295.000697 395.898317c-62.899798-21.69993-92.899702-43.899859-103.399668-72.899766l-37.999878-108.399652c-8.499973-23.399925 3.19999-75.299758 11.499964-98.799682 39.699872-112.799638 86.399722-187.699397 114.499632-226.699272 4.899984-6.799978 9.099971-12.29996 12.799959-16.899946H760.9992c1.699995 3.09999 3.19999 6.29998 4.499986 9.699969l94.999694 256.299177c22.099929 52.099833 10.799965 108.499651 1.299996 128.599587z" horiz-adv-x="1024" />
|
||||
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 26 KiB |
44
global-components/Badge.vue
Normal file
44
global-components/Badge.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<script>
|
||||
export default {
|
||||
functional: true,
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: 'tip'
|
||||
},
|
||||
text: String,
|
||||
vertical: {
|
||||
type: String,
|
||||
default: 'top'
|
||||
}
|
||||
},
|
||||
render (h, { props, slots }) {
|
||||
return h('span', {
|
||||
class: ['badge', props.type],
|
||||
style: {
|
||||
verticalAlign: props.vertical
|
||||
}
|
||||
}, props.text || slots().default)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.badge
|
||||
display inline-block
|
||||
font-size 14px
|
||||
height 18px
|
||||
line-height 18px
|
||||
border-radius 3px
|
||||
padding 0 6px
|
||||
color white
|
||||
background-color #42b983
|
||||
&.tip, &.green
|
||||
background-color #42b983
|
||||
&.error
|
||||
background-color #DA5961 //#f66
|
||||
&.warning, &.warn, &.yellow
|
||||
background-color darken(#ffe564, 35%)
|
||||
& + &
|
||||
margin-left 5px
|
||||
</style>
|
46
index.js
Normal file
46
index.js
Normal file
@ -0,0 +1,46 @@
|
||||
const path = require('path')
|
||||
|
||||
// Theme API.
|
||||
module.exports = (options, ctx) => ({
|
||||
alias () {
|
||||
const { themeConfig, siteConfig } = ctx
|
||||
// resolve algolia
|
||||
const isAlgoliaSearch = (
|
||||
themeConfig.algolia
|
||||
|| Object.keys(siteConfig.locales && themeConfig.locales || {})
|
||||
.some(base => themeConfig.locales[base].algolia)
|
||||
)
|
||||
return {
|
||||
'@AlgoliaSearchBox': isAlgoliaSearch
|
||||
? path.resolve(__dirname, 'components/AlgoliaSearchBox.vue')
|
||||
: path.resolve(__dirname, 'noopModule.js')
|
||||
}
|
||||
},
|
||||
|
||||
plugins: [
|
||||
'@vuepress/active-header-links',
|
||||
['@vuepress/plugin-blog', {
|
||||
permalink: '/:regular'
|
||||
}],
|
||||
'@vuepress/search',
|
||||
'@vuepress/plugin-nprogress',
|
||||
['container', {
|
||||
type: 'tip',
|
||||
defaultTitle: {
|
||||
'/zh/': '提示'
|
||||
}
|
||||
}],
|
||||
['container', {
|
||||
type: 'warning',
|
||||
defaultTitle: {
|
||||
'/zh/': '注意'
|
||||
}
|
||||
}],
|
||||
['container', {
|
||||
type: 'danger',
|
||||
defaultTitle: {
|
||||
'/zh/': '警告'
|
||||
}
|
||||
}]
|
||||
]
|
||||
})
|
@ -24,3 +24,5 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style src="../styles/theme.styl" lang="stylus"></style>
|
93
layouts/Category.vue
Normal file
93
layouts/Category.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="categories-wrapper">
|
||||
<!-- 公共布局 -->
|
||||
<Common :sidebar="false" :isComment="false">
|
||||
<!-- 页面标题 -->
|
||||
<h2 class="title">{{ title }}</h2>
|
||||
|
||||
<!-- 博客列表 -->
|
||||
<note-abstract
|
||||
:data="posts"
|
||||
:currentPage="currentPage"
|
||||
@currentTag="getCurrentTag"></note-abstract>
|
||||
|
||||
<!-- 分页 -->
|
||||
<pagation
|
||||
:data="posts"
|
||||
:currentPage="currentPage"
|
||||
@getCurrentPage="getCurrentPage"></pagation>
|
||||
</Common>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Common from '@theme/components/Common.vue'
|
||||
import NoteAbstract from '../components//NoteAbstract.vue'
|
||||
import Pagation from '../components//Pagation.vue'
|
||||
|
||||
export default {
|
||||
components: { Common, NoteAbstract, Pagation },
|
||||
|
||||
data () {
|
||||
return {
|
||||
// 当前页码
|
||||
currentPage: 1
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
// 时间降序后的博客列表
|
||||
posts () {
|
||||
let posts = this.$category.posts
|
||||
posts.sort((a, b) => {
|
||||
return this._getTimeNum(b) - this._getTimeNum(a)
|
||||
})
|
||||
return posts
|
||||
},
|
||||
// 标题只显示分类名称
|
||||
title () {
|
||||
return this.$page.frontmatter.title.split('|')[0]
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 获取当前tag
|
||||
getCurrentTag (tag) {
|
||||
this.$emit('currentTag', tag)
|
||||
},
|
||||
// 获取当前页码
|
||||
getCurrentPage (page) {
|
||||
this.currentPage = page
|
||||
this.$page.currentPage = page
|
||||
},
|
||||
// 获取时间的数字类型
|
||||
_getTimeNum (date) {
|
||||
return parseInt(new Date(date.frontmatter.date).getTime())
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style src="../styles/theme.styl" lang="stylus"></style>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.categories-wrapper
|
||||
max-width: 740px;
|
||||
margin: 0 auto;
|
||||
padding: 4.6rem 2.5rem 0;
|
||||
.title
|
||||
margin-bottom 3rem
|
||||
|
||||
@media (max-width: $MQMobile)
|
||||
.categories-wrapper
|
||||
padding: 4.6rem 1rem 0;
|
||||
.page-edit
|
||||
.edit-link
|
||||
margin-bottom .5rem
|
||||
.last-updated
|
||||
font-size .8em
|
||||
float none
|
||||
text-align left
|
||||
</style>
|
||||
|
||||
|
42
layouts/Layout.vue
Normal file
42
layouts/Layout.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<div>
|
||||
<Common>
|
||||
<Home v-if="$page.frontmatter.home"/>
|
||||
<Page
|
||||
v-else
|
||||
:sidebar-items="sidebarItems">
|
||||
<slot
|
||||
name="page-top"
|
||||
slot="top"/>
|
||||
<slot
|
||||
name="page-bottom"
|
||||
slot="bottom"/>
|
||||
</Page>
|
||||
</Common>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Home from '@theme/components/Home.vue'
|
||||
import Page from '@theme/components/Page.vue'
|
||||
import Common from '@theme/components/Common.vue'
|
||||
import { resolveSidebarItems } from '../util'
|
||||
|
||||
export default {
|
||||
components: { Home, Page, Common },
|
||||
|
||||
computed: {
|
||||
sidebarItems () {
|
||||
return resolveSidebarItems(
|
||||
this.$page,
|
||||
this.$page.regularPath,
|
||||
this.$site,
|
||||
this.$localePath
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style src="prismjs/themes/prism-tomorrow.css"></style>
|
||||
<style src="../styles/theme.styl" lang="stylus"></style>
|
129
layouts/Tags.vue
Normal file
129
layouts/Tags.vue
Normal file
@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div class="tags-wrapper">
|
||||
<Common :sidebar="false" :isComment="false"></Common>
|
||||
<div class="tags">
|
||||
<span
|
||||
v-for="(item, index) in tags"
|
||||
:key="index"
|
||||
:class="{'active': item.name == currentTag}"
|
||||
:style="{ 'backgroundColor': item.color }"
|
||||
@click="getPagesByTags(item.name)">{{item.name}}</span>
|
||||
</div>
|
||||
<note-abstract
|
||||
:data="posts"
|
||||
:currentPage="currentPage"
|
||||
:currentTag="currentTag"
|
||||
@currentTag="getCurrentTag"></note-abstract>
|
||||
|
||||
<pagation
|
||||
:data="posts"
|
||||
:currentPage="currentPage"
|
||||
@getCurrentPage="getCurrentPage"></pagation>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Common from '@theme/components/Common.vue'
|
||||
import NoteAbstract from '../components//NoteAbstract.vue'
|
||||
import Pagation from '../components//Pagation.vue'
|
||||
|
||||
export default {
|
||||
components: { Common, NoteAbstract, Pagation },
|
||||
|
||||
data () {
|
||||
return {
|
||||
posts: [],
|
||||
tags: [],
|
||||
currentTag: '',
|
||||
currentPage: 1
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
if (this.$tags.list.length > 0) {
|
||||
const currentTag = this.$route.query.tag ? this.$route.query.tag : this.$tags.list[0].name
|
||||
let tags = this.$tags.list
|
||||
tags.map(item => {
|
||||
const color = this._tagColor()
|
||||
item.color = color
|
||||
return tags
|
||||
})
|
||||
this.tags = tags
|
||||
|
||||
this.getPagesByTags(currentTag)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
// 根据分类获取页面数据
|
||||
getPagesByTags (currentTag) {
|
||||
|
||||
this.currentTag = currentTag
|
||||
|
||||
let posts = this.$tags.map[currentTag].posts
|
||||
posts.sort((a, b) => {
|
||||
return this._getTimeNum(b) - this._getTimeNum(a)
|
||||
})
|
||||
// reverse()是为了按时间最近排序排序
|
||||
this.posts = posts.length == 0 ? [] : posts
|
||||
|
||||
this.getCurrentPage(1);
|
||||
},
|
||||
|
||||
getCurrentTag (tag) {
|
||||
this.$emit('currentTag', tag)
|
||||
},
|
||||
|
||||
getCurrentPage (page) {
|
||||
this.currentPage = page
|
||||
this.$page.currentPage = page
|
||||
},
|
||||
|
||||
_tagColor () {
|
||||
// 红、蓝、绿、橙、灰
|
||||
const tagColorArr = ['#f26d6d', '#3498db', '#67cc86', '#fb9b5f', '#838282']
|
||||
const index = Math.floor(Math.random() * tagColorArr.length)
|
||||
return tagColorArr[index]
|
||||
},
|
||||
|
||||
// 获取时间的数字类型
|
||||
_getTimeNum (date) {
|
||||
return parseInt(new Date(date.frontmatter.date).getTime())
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style src="../styles/theme.styl" lang="stylus"></style>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.tags-wrapper
|
||||
max-width: 740px;
|
||||
margin: 0 auto;
|
||||
padding: 4.6rem 2.5rem 0;
|
||||
.tags
|
||||
margin-bottom 30px
|
||||
span
|
||||
vertical-align: middle;
|
||||
margin: 4px 4px 10px;
|
||||
padding: 4px 8px;
|
||||
display: inline-flex;
|
||||
cursor: pointer;
|
||||
border-radius: 2px;
|
||||
background: #fff;
|
||||
color: #fff;
|
||||
font-size: 13px;
|
||||
box-shadow 0 1px 4px 0 rgba(0,0,0,0.2)
|
||||
transition: all .5s
|
||||
&:hover
|
||||
transform scale(1.04)
|
||||
&.active
|
||||
transform scale(1.2)
|
||||
|
||||
@media (max-width: $MQMobile)
|
||||
.tags-wrapper
|
||||
padding: 0 0.6rem;
|
||||
</style>
|
||||
|
||||
|
1
noopModule.js
Normal file
1
noopModule.js
Normal file
@ -0,0 +1 @@
|
||||
export default {}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vuepress-theme-reco",
|
||||
"version": "0.3.11",
|
||||
"version": "1.0.0-alpha.11",
|
||||
"description": "this is a vuepress theme",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@ -24,7 +24,9 @@
|
||||
"_from": "vuepress-theme-reco@0.2.1",
|
||||
"_resolved": "http://registry.npm.taobao.org/vuepress-theme-reco/download/vuepress-theme-reco-0.2.1.tgz",
|
||||
"dependencies": {
|
||||
"leancloud-storage": "^3.12.0",
|
||||
"valine": "^1.3.6"
|
||||
"leancloud-storage": "^3.10.1",
|
||||
"valine": "^1.3.4",
|
||||
"@vuepress/plugin-blog": "^1.0.0-alpha.46",
|
||||
"vue-click-outside": "^1.0.7"
|
||||
}
|
||||
}
|
@ -1,5 +1,3 @@
|
||||
@require './config'
|
||||
|
||||
.content
|
||||
code
|
||||
color lighten($textColor, 20%)
|
||||
@ -8,6 +6,11 @@
|
||||
font-size 0.85em
|
||||
background-color rgba(27,31,35,0.05)
|
||||
border-radius 3px
|
||||
.token
|
||||
&.deleted
|
||||
color #EC5975
|
||||
&.inserted
|
||||
color $accentColor
|
||||
|
||||
.content
|
||||
pre, pre[class*="language-"]
|
||||
@ -127,3 +130,6 @@ div[class~="language-python"]:before
|
||||
|
||||
div[class~="language-bash"]:before
|
||||
content "sh"
|
||||
|
||||
div[class~="language-php"]:before
|
||||
content "php"
|
||||
|
55
styles/colorMode/colorMixin.styl
Normal file
55
styles/colorMode/colorMixin.styl
Normal file
@ -0,0 +1,55 @@
|
||||
color-mode(accountColor , colorName)
|
||||
.reco-theme-{colorName}
|
||||
input
|
||||
color accountColor!important;
|
||||
.search-box input
|
||||
border-color: accountColor!important;
|
||||
&:focus
|
||||
border-color: accountColor!important;
|
||||
.navbar
|
||||
box-shadow: 0 1px 6px 0 rgba(32,33,36,.28)
|
||||
.nav-links a:hover,
|
||||
.nav-links a.router-link-active,
|
||||
.nav-links a:hover .iconfont,
|
||||
.nav-links a.router-link-active .iconfont
|
||||
color accountColor!important;
|
||||
.home
|
||||
.hero
|
||||
.description
|
||||
color accountColor!important;
|
||||
.action-button, img
|
||||
background-color accountColor!important;
|
||||
color: #fff!important
|
||||
.features
|
||||
.feature
|
||||
h2, p
|
||||
color accountColor!important;
|
||||
.footer
|
||||
a
|
||||
color accountColor!important;
|
||||
.abstract-wrapper .abstract-item .title
|
||||
a
|
||||
color accountColor!important;
|
||||
a:after
|
||||
background-color accountColor!important;
|
||||
.back-to-ceiling i
|
||||
color accountColor!important;
|
||||
.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after
|
||||
border-left: 5px solid accountColor!important;
|
||||
.tags
|
||||
.tag-item.active, .tag-item:hover
|
||||
color accountColor!important;
|
||||
.timeline-wrapper .year-wrapper li:hover
|
||||
.title
|
||||
color accountColor!important;
|
||||
.date::before
|
||||
background: accountColor!important;
|
||||
.date
|
||||
color accountColor!important;
|
||||
@media (min-width: 765px)
|
||||
.nav-item > a:not(.external):hover,
|
||||
.nav-item > a:not(.external).router-link-active
|
||||
border-color: accountColor!important;
|
||||
@media (max-width: 959px)
|
||||
.search-box input
|
||||
border-color: transparent!important;
|
17
styles/colorMode/colorMode.styl
Normal file
17
styles/colorMode/colorMode.styl
Normal file
@ -0,0 +1,17 @@
|
||||
@require './colorMixin.styl'
|
||||
|
||||
$fc-red = #f26d6d
|
||||
$fc-red-name = 'red'
|
||||
color-mode($fc-red, $fc-red-name)
|
||||
|
||||
$fc-blue = #2196f3
|
||||
$fc-blue-name = 'blue'
|
||||
color-mode($fc-blue, $fc-blue-name)
|
||||
|
||||
$fc-green = #3eaf7c
|
||||
$fc-green-name = 'green'
|
||||
color-mode($fc-green, $fc-green-name)
|
||||
|
||||
$fc-orange = #fb9b5f
|
||||
$fc-orange-name = 'orange'
|
||||
color-mode($fc-orange, $fc-orange-name)
|
2
styles/colorMode/index.styl
Normal file
2
styles/colorMode/index.styl
Normal file
@ -0,0 +1,2 @@
|
||||
@require './nightMode.styl'
|
||||
@require './colorMode.styl'
|
114
styles/colorMode/nightMode.styl
Normal file
114
styles/colorMode/nightMode.styl
Normal file
@ -0,0 +1,114 @@
|
||||
$bc = #000
|
||||
$fc = #9e9e9e
|
||||
$bdc = #9e9e9e
|
||||
$fcActive = #fff
|
||||
|
||||
|
||||
bc() {
|
||||
background-color: $bc!important
|
||||
}
|
||||
fc() {
|
||||
color: $fc!important
|
||||
}
|
||||
bdc() {
|
||||
border-color: $bdc!important
|
||||
}
|
||||
fc-active() {
|
||||
color: $fcActive!important
|
||||
}
|
||||
|
||||
.reco-theme-night
|
||||
bc()
|
||||
fc()
|
||||
bdc()
|
||||
h1, h2, h3, h4, h5, h6, a, hr
|
||||
bdc()
|
||||
fc()
|
||||
input
|
||||
bc()
|
||||
fc()
|
||||
.search-box input
|
||||
bdc()
|
||||
&:focus
|
||||
bdc()
|
||||
.navbar
|
||||
bc()
|
||||
box-shadow: 0 2px 20px 0 rgba(255,255,255,0.4);
|
||||
border-bottom: 1px solid $bdc
|
||||
.site-name, .links
|
||||
bc()
|
||||
fc()
|
||||
.nav-links a:hover,
|
||||
.nav-links a.router-link-active,
|
||||
.nav-links a:hover .iconfont,
|
||||
.nav-links a.router-link-active .iconfont
|
||||
fc-active()
|
||||
.tags .tag-item:hover
|
||||
fc-active()
|
||||
@media (min-width: 765px)
|
||||
.nav-item > a:not(.external):hover,
|
||||
.nav-item > a:not(.external).router-link-active
|
||||
border-color: $fcActive;
|
||||
.dropdown-wrapper .nav-dropdown
|
||||
bc()
|
||||
box-shadow: 0 2px 20px 0 rgba(255,255,255,0.4);
|
||||
border: 1px solid $bdc
|
||||
@media (min-width: 719px)
|
||||
.nav-item > a:not(.external):hover,
|
||||
.nav-item > a:not(.external).router-link-active
|
||||
border-bottom: 2px solid $fcActive!important;
|
||||
@media (max-width: 959px)
|
||||
.search-box input
|
||||
border-color: transparent!important;
|
||||
.home
|
||||
.hero
|
||||
.description
|
||||
fc()
|
||||
.features
|
||||
bdc()
|
||||
.feature
|
||||
h2, p
|
||||
fc()
|
||||
.footer
|
||||
bdc()
|
||||
a
|
||||
fc()
|
||||
.abstract-wrapper .abstract-item
|
||||
background-color: lighten($bc, 20%)
|
||||
.custom-block.tip, .custom-block.warning, .custom-block.danger
|
||||
background-color: lighten($bc, 15%)
|
||||
.pagation .pagation-list
|
||||
bc()
|
||||
.sidebar
|
||||
bc()
|
||||
bdc()
|
||||
.valine-wrapper
|
||||
bc()
|
||||
|
||||
.v .vbtn, .v .vwrap
|
||||
bc()
|
||||
bdc()
|
||||
.v .vlist .vcard
|
||||
.vhead .vsys, .vh
|
||||
bdc()
|
||||
bc()
|
||||
.timeline-wrapper
|
||||
&::after
|
||||
background: $fc
|
||||
.year-wrapper li
|
||||
bdc()
|
||||
.back-to-ceiling
|
||||
background-color: lighten($bc, 15%)!important
|
||||
i
|
||||
fc()
|
||||
.color-picker .color-button .iconfont
|
||||
fc()
|
||||
.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after
|
||||
border-left: 5px solid $fcActive
|
||||
.timeline-wrapper .year-wrapper li:hover
|
||||
.title
|
||||
fc()
|
||||
.date::before
|
||||
background: $fcActive
|
||||
.date
|
||||
fc()
|
@ -1,23 +0,0 @@
|
||||
// colors
|
||||
$accentColor = #424242
|
||||
$textColor = #232321
|
||||
$borderColor = #eaecef
|
||||
$codeBgColor = #282c34
|
||||
$arrowBgColor = #ccc
|
||||
$bgColor = #fff
|
||||
|
||||
// layout
|
||||
$navbarHeight = 3.4rem
|
||||
$sidebarWidth = 20rem
|
||||
$contentWidth = 740px
|
||||
|
||||
// // responsive breakpoints
|
||||
$MQNarrow = 1024px
|
||||
$MQMobile = 765px
|
||||
$MQMobileNarrow = 419px
|
||||
|
||||
// code
|
||||
$lineNumbersWrapperWidth = 3.5rem
|
||||
$codeLang = js ts html md vue css sass scss less stylus go java c sh yaml py
|
||||
|
||||
@import '~@temp/override.styl'
|
@ -10,7 +10,10 @@
|
||||
&.tip
|
||||
background-color #f3f5f7
|
||||
border-color #67cc86
|
||||
<<<<<<< HEAD
|
||||
// color darken(#67cc86, 70%)
|
||||
=======
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
&.warning
|
||||
background-color #fbf0ea
|
||||
border-color #fb9b5f
|
||||
@ -27,3 +30,5 @@
|
||||
color darken(red, 40%)
|
||||
a
|
||||
color $textColor
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
@require './config'
|
||||
// @require './config'
|
||||
|
||||
$mobileSidebarWidth = $sidebarWidth * 0.82
|
||||
|
||||
|
@ -1,48 +0,0 @@
|
||||
#nprogress
|
||||
pointer-events none
|
||||
.bar
|
||||
background $accentColor
|
||||
position fixed
|
||||
z-index 1031
|
||||
top 0
|
||||
left 0
|
||||
width 100%
|
||||
height 2px
|
||||
.peg
|
||||
display block
|
||||
position absolute
|
||||
right 0px
|
||||
width 100px
|
||||
height 100%
|
||||
box-shadow 0 0 10px $accentColor, 0 0 5px $accentColor
|
||||
opacity 1.0
|
||||
transform rotate(3deg) translate(0px, -4px)
|
||||
.spinner
|
||||
display block
|
||||
position fixed
|
||||
z-index 1031
|
||||
top 15px
|
||||
right 15px
|
||||
.spinner-icon
|
||||
width 18px
|
||||
height 18px
|
||||
box-sizing border-box
|
||||
border solid 2px transparent
|
||||
border-top-color $accentColor
|
||||
border-left-color $accentColor
|
||||
border-radius 50%
|
||||
animation nprogress-spinner 400ms linear infinite
|
||||
|
||||
.nprogress-custom-parent
|
||||
overflow hidden
|
||||
position relative
|
||||
|
||||
.nprogress-custom-parent #nprogress .spinner,
|
||||
.nprogress-custom-parent #nprogress .bar
|
||||
position absolute
|
||||
|
||||
@keyframes nprogress-spinner
|
||||
0%
|
||||
transform rotate(0deg)
|
||||
100%
|
||||
transform rotate(360deg)
|
3
styles/recoConfig.styl
Normal file
3
styles/recoConfig.styl
Normal file
@ -0,0 +1,3 @@
|
||||
// colors
|
||||
$accentColor = #424242
|
||||
$textColor = #232321
|
@ -1,29 +1,40 @@
|
||||
@require './config'
|
||||
@require './nprogress'
|
||||
@require './recoConfig'
|
||||
@require './code'
|
||||
@require './custom-blocks'
|
||||
@require './arrow'
|
||||
@require './wrapper'
|
||||
@require './toc'
|
||||
<<<<<<< HEAD
|
||||
// @require './common'
|
||||
=======
|
||||
@require './colorMode/index'
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
@require '../fonts/iconfont.css'
|
||||
|
||||
html, body
|
||||
padding 0
|
||||
margin 0
|
||||
<<<<<<< HEAD
|
||||
background-color: $bgColor
|
||||
overflow-x: hidden
|
||||
|
||||
=======
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
body
|
||||
font-family -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif
|
||||
-webkit-font-smoothing antialiased
|
||||
-moz-osx-font-smoothing grayscale
|
||||
font-size 16px
|
||||
<<<<<<< HEAD
|
||||
color $textColor
|
||||
|
||||
input
|
||||
background-color: $bgColor
|
||||
-webkit-appearance: none;
|
||||
=======
|
||||
color $textColor
|
||||
background-color #fff
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
|
||||
.page
|
||||
padding-left $sidebarWidth
|
||||
@ -37,7 +48,6 @@ input
|
||||
height $navbarHeight
|
||||
background-color $bgColor
|
||||
box-sizing border-box
|
||||
box-shadow: 0 1px 6px 0 rgba(32,33,36,0.28)
|
||||
|
||||
.sidebar-mask
|
||||
position fixed
|
||||
@ -47,11 +57,19 @@ input
|
||||
width 100vw
|
||||
height 100vh
|
||||
display none
|
||||
<<<<<<< HEAD
|
||||
background-color: rgba(0, 0, 0, .65)
|
||||
|
||||
.sidebar
|
||||
font-size 15px
|
||||
background-color $bgColor
|
||||
=======
|
||||
background-color: rgba(0,0,0,.65);
|
||||
|
||||
.sidebar
|
||||
font-size 16px
|
||||
background-color #fff
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
width $sidebarWidth
|
||||
position fixed
|
||||
z-index 10
|
||||
@ -80,7 +98,7 @@ input
|
||||
padding 0
|
||||
margin 0
|
||||
img
|
||||
max-width 100%
|
||||
max-width 100%
|
||||
|
||||
a
|
||||
font-weight 500
|
||||
@ -99,11 +117,13 @@ kbd
|
||||
padding 0 0.15em
|
||||
|
||||
blockquote
|
||||
font-size 1rem
|
||||
font-size .9rem
|
||||
color #999
|
||||
border-left .25rem solid #dfe2e5
|
||||
margin-left 0
|
||||
padding-left 1rem
|
||||
margin 0.5rem 0
|
||||
padding .25rem 0 .25rem 1rem
|
||||
& > p
|
||||
margin 0
|
||||
|
||||
ul, ol
|
||||
padding-left 1.2em
|
||||
@ -172,9 +192,6 @@ th, td
|
||||
border 1px solid #dfe2e5
|
||||
padding .6em 1em
|
||||
|
||||
.custom-layout
|
||||
padding-top $navbarHeight
|
||||
|
||||
.theme-container
|
||||
&.sidebar-open
|
||||
.sidebar-mask
|
||||
@ -185,6 +202,7 @@ th, td
|
||||
padding-top 0
|
||||
.sidebar
|
||||
top 0
|
||||
<<<<<<< HEAD
|
||||
.custom-layout
|
||||
padding-top 0
|
||||
|
||||
@ -214,6 +232,8 @@ th, td
|
||||
width: 5px;
|
||||
background-color: rgba(125, 125, 125, 0.7);
|
||||
-webkit-border-radius: 6px;
|
||||
=======
|
||||
>>>>>>> 24c38eb010e47bfb4c4532c15a8d35e38c27adfd
|
||||
|
||||
@media (min-width: ($MQMobile + 1px))
|
||||
.theme-container.no-sidebar
|
||||
@ -222,4 +242,32 @@ th, td
|
||||
.page
|
||||
padding-left 0
|
||||
|
||||
@require './mobile.styl'
|
||||
@require 'mobile.styl'
|
||||
|
||||
.iconfont
|
||||
font-size: 0.9rem;
|
||||
color: #999;
|
||||
// &:not(:first-child)
|
||||
// margin-left: 1rem
|
||||
// span
|
||||
// margin-left: .5rem
|
||||
|
||||
/************** 滚动条 **************/
|
||||
::-webkit-scrollbar
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
|
||||
::-webkit-scrollbar-track-piece
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
-webkit-border-radius: 6px;
|
||||
|
||||
::-webkit-scrollbar-thumb:vertical
|
||||
height: 5px;
|
||||
background-color: rgba(125, 125, 125, 0.7);
|
||||
-webkit-border-radius: 6px;
|
||||
|
||||
::-webkit-scrollbar-thumb:horizontal
|
||||
width: 5px;
|
||||
background-color: rgba(125, 125, 125, 0.7);
|
||||
-webkit-border-radius: 6px;
|
||||
|
||||
|
@ -58,10 +58,10 @@ export function resolvePage (pages, rawPath, base) {
|
||||
}
|
||||
const path = normalize(rawPath)
|
||||
for (let i = 0; i < pages.length; i++) {
|
||||
if (normalize(pages[i].path) === path) {
|
||||
if (normalize(pages[i].regularPath) === path) {
|
||||
return Object.assign({}, pages[i], {
|
||||
type: 'page',
|
||||
path: ensureExt(rawPath)
|
||||
path: ensureExt(pages[i].path)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -107,7 +107,14 @@ function resolvePath (relative, base, append) {
|
||||
return stack.join('/')
|
||||
}
|
||||
|
||||
export function resolveSidebarItems (page, route, site, localePath) {
|
||||
/**
|
||||
* @param { Page } page
|
||||
* @param { string } regularPath
|
||||
* @param { SiteData } site
|
||||
* @param { string } localePath
|
||||
* @returns { SidebarGroup }
|
||||
*/
|
||||
export function resolveSidebarItems (page, regularPath, site, localePath) {
|
||||
const { pages, themeConfig } = site
|
||||
|
||||
const localeConfig = localePath && themeConfig.locales
|
||||
@ -123,19 +130,24 @@ export function resolveSidebarItems (page, route, site, localePath) {
|
||||
if (!sidebarConfig) {
|
||||
return []
|
||||
} else {
|
||||
const { base, config } = resolveMatchingConfig(route, sidebarConfig)
|
||||
const { base, config } = resolveMatchingConfig(regularPath, sidebarConfig)
|
||||
return config
|
||||
? config.map(item => resolveItem(item, pages, base))
|
||||
: []
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param { Page } page
|
||||
* @returns { SidebarGroup }
|
||||
*/
|
||||
function resolveHeaders (page) {
|
||||
const headers = groupHeaders(page.headers || [])
|
||||
return [{
|
||||
type: 'group',
|
||||
collapsable: false,
|
||||
title: page.title,
|
||||
path: null,
|
||||
children: headers.map(h => ({
|
||||
type: 'auto',
|
||||
title: h.title,
|
||||
@ -166,7 +178,12 @@ export function resolveNavLinkItem (linkItem) {
|
||||
})
|
||||
}
|
||||
|
||||
export function resolveMatchingConfig (route, config) {
|
||||
/**
|
||||
* @param { Route } route
|
||||
* @param { Array<string|string[]> | Array<SidebarGroup> | [link: string]: SidebarConfig } config
|
||||
* @returns { base: string, config: SidebarConfig }
|
||||
*/
|
||||
export function resolveMatchingConfig (regularPath, config) {
|
||||
if (Array.isArray(config)) {
|
||||
return {
|
||||
base: '/',
|
||||
@ -174,7 +191,7 @@ export function resolveMatchingConfig (route, config) {
|
||||
}
|
||||
}
|
||||
for (const base in config) {
|
||||
if (ensureEndingSlash(route.path).indexOf(base) === 0) {
|
||||
if (ensureEndingSlash(regularPath).indexOf(encodeURI(base)) === 0) {
|
||||
return {
|
||||
base,
|
||||
config: config[base]
|
||||
@ -190,7 +207,7 @@ function ensureEndingSlash (path) {
|
||||
: path + '/'
|
||||
}
|
||||
|
||||
function resolveItem (item, pages, base, isNested) {
|
||||
function resolveItem (item, pages, base, groupDepth = 1) {
|
||||
if (typeof item === 'string') {
|
||||
return resolvePage(pages, item, base)
|
||||
} else if (Array.isArray(item)) {
|
||||
@ -198,17 +215,23 @@ function resolveItem (item, pages, base, isNested) {
|
||||
title: item[1]
|
||||
})
|
||||
} else {
|
||||
if (isNested) {
|
||||
if (groupDepth > 3) {
|
||||
console.error(
|
||||
'[vuepress] Nested sidebar groups are not supported. ' +
|
||||
'Consider using navbar + categories instead.'
|
||||
'[vuepress] detected a too deep nested sidebar group.'
|
||||
)
|
||||
}
|
||||
const children = item.children || []
|
||||
if (children.length === 0 && item.path) {
|
||||
return Object.assign(resolvePage(pages, item.path, base), {
|
||||
title: item.title
|
||||
})
|
||||
}
|
||||
return {
|
||||
type: 'group',
|
||||
path: item.path,
|
||||
title: item.title,
|
||||
children: children.map(child => resolveItem(child, pages, base, true)),
|
||||
sidebarDepth: item.sidebarDepth,
|
||||
children: children.map(child => resolveItem(child, pages, base, groupDepth + 1)),
|
||||
collapsable: item.collapsable !== false
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user