Compare commits

..

No commits in common. "fb1cbbada498ec1493ee2502074785b6f8f58207" and "183aa7627b3bbd67e4cb3b4ad663f100e93289ff" have entirely different histories.

8 changed files with 8062 additions and 2548 deletions

View File

@ -1,9 +1,6 @@
{ {
"presets": [ "presets": [
["@babel/preset-env", { "@babel/preset-env"
"useBuiltIns": "usage",
"corejs": 3
}]
], ],
"plugins": [ "plugins": [
"@babel/transform-runtime" "@babel/transform-runtime"

View File

@ -60,7 +60,7 @@
</div> </div>
<ul class="search-ul"> <ul class="search-ul">
<li class="search-li" v-for="(item,index) in items" :key="index" v-show="!item.isHide"> <li class="search-li" v-for="(item,index) in items" :key="index" v-show="!item.isHide">
<a :href="urlformat(item.path)" class="search-title"><i class="icon icon-quote-left"></i> <a :href="item.path|urlformat" class="search-title"><i class="icon icon-quote-left"></i>
<span v-text="item.title"></span> <span v-text="item.title"></span>
</a> </a>
<p class="search-time" v-if="item.date"> <p class="search-time" v-if="item.date">

File diff suppressed because it is too large Load Diff

View File

@ -18,36 +18,39 @@
"author": "litten", "author": "litten",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.26.0", "babel-polyfill": "^6.23.0",
"core-js": "^3.40.0", "leancloud-storage": "^3.7.3",
"photoswipe": "^4.1.3", "photoswipe": "^4.1.3",
"qrious": "^4.0.2", "qrious": "^4.0.2",
"scrollreveal": "^4.0.9", "scrollreveal": "^4.0.5",
"vue": "^3.5.14" "vue": "^2.6.14"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.26.0", "@babel/core": "^7.17.5",
"@babel/plugin-transform-runtime": "^7.25.9", "@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.26.0", "@babel/preset-env": "^7.16.11",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.2",
"babel-loader": "^9.2.1", "axios": "^1.13.6",
"babel-loader": "8.3.0",
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"css-loader": "^7.1.2", "css-loader": "^5.2.7",
"html-webpack-plugin": "^5.6.3", "file-loader": "^6.2.0",
"less": "^4.2.2", "html-webpack-plugin": "^5.5.0",
"less-loader": "^12.2.0", "less": "^4.1.3",
"mini-css-extract-plugin": "^2.9.2", "less-loader": "^11.1.0",
"postcss": "^8.5.3", "mini-css-extract-plugin": "^2.6.0",
"postcss-loader": "^8.1.1", "postcss-loader": "^6.2.1",
"terser-webpack-plugin": "^5.3.11", "terser-webpack-plugin": "^5.3.1",
"webpack": "^5.97.1", "url-loader": "^4.1.1",
"webpack-cli": "^5.1.4" "webpack": "^5.70.0",
"webpack-cli": "^4.9.2"
}, },
"browserslist": [ "browserslist": [
"> 1%", "> 1%",
"last 2 versions", "last 2 versions",
"not dead", "not dead",
"iOS >= 10", "iOS >= 7",
"Android >= 5" "Android >= 4",
"not ie <= 8"
] ]
} }

View File

@ -1,5 +1,6 @@
module.exports = { module.exports = {
plugins: [ plugins: [
"autoprefixer" "autoprefixer",
"postcss-preset-env"
] ]
} }

View File

@ -1,19 +1,14 @@
const DEFAULT_TIMEOUT = 10000 import axios from 'axios'
function serializeParams(params) { const http = axios.create({
if (!params) return '' timeout: 10000,
const query = Object.entries(params) paramsSerializer: {
.filter(([, v]) => v !== undefined && v !== null) indexes: null
.flatMap(([k, v]) => Array.isArray(v) ? v.map(item => `${encodeURIComponent(k)}=${encodeURIComponent(item)}`) : [`${encodeURIComponent(k)}=${encodeURIComponent(v)}`])
.join('&')
return query ? '?' + query : ''
} }
})
function handleResponse(res) { http.interceptors.response.use(res => {
if (!res.ok) { const responseBody = res.data
return Promise.reject(new Error(`HTTP ${res.status}`))
}
return res.json().then(responseBody => {
// 统一响应格式处理 // 统一响应格式处理
switch (responseBody.code) { switch (responseBody.code) {
case 0: case 0:
@ -23,30 +18,8 @@ function handleResponse(res) {
return Promise.reject(new Error(responseBody.message || '请求失败')) return Promise.reject(new Error(responseBody.message || '请求失败'))
default: default:
// 其他情况,兼容没有包装格式的响应 // 其他情况,兼容没有包装格式的响应
return responseBody return res.data
}
})
}
async function request(url, options = {}) {
const controller = new AbortController()
const timer = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT)
return fetch(url, { ...options, signal: controller.signal })
.then(res => { clearTimeout(timer); return handleResponse(res) })
.catch(err => { clearTimeout(timer); return Promise.reject(err) })
}
const http = {
get(url, { params } = {}) {
return request(url + serializeParams(params))
},
post(url, data) {
return request(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
})
}
} }
}, err => Promise.reject(err))
export default http export default http

View File

@ -1,22 +1,17 @@
import http from './request' import http from './request'
import { createApp } from 'vue' import Vue from 'vue/dist/vue.esm'
import waifuTips from '../config/waifu-tip.json' import waifuTips from '../config/waifu-tip.json'
function setScrollZero() { function setScrollZero() {
document.querySelectorAll('.tools-section').forEach(em => { let $sct = document.querySelectorAll('.tools-section')
Array.prototype.forEach.call($sct, (em) => {
em.scrollTop = 0 em.scrollTop = 0
}) })
} }
function urlformat(str) {
return (window.themeConfig && window.themeConfig.root) ? window.themeConfig.root + str : '/' + str
}
var waifuTipTimer = null, fullTextSearchTimer = null var waifuTipTimer = null, fullTextSearchTimer = null
const vm = new Vue({
const vm = createApp({ el: '#container',
data() { data: {
return {
isCtnShow: false, isCtnShow: false,
isShow: undefined, isShow: undefined,
items: [], items: [],
@ -42,10 +37,8 @@ const vm = createApp({
showTools: false // 显示工具栏 showTools: false // 显示工具栏
}, },
themeConfig: window.themeConfig themeConfig: window.themeConfig
}
}, },
methods: { methods: {
urlformat,
stop (event) { stop (event) {
event.stopPropagation() event.stopPropagation()
}, },
@ -84,7 +77,7 @@ const vm = createApp({
query = query.trim() query = query.trim()
} }
// 如果已存在相同的查询条件, 则不加入 // 如果已存在相同的查询条件, 则不加入
const isExist = this.searchItems.some(searchItem => { var isExist = Array.prototype.some.call(this.searchItems, searchItem => {
return searchItem.query === query && searchItem.type === type return searchItem.query === query && searchItem.type === type
}) })
if(!isExist && query) { if(!isExist && query) {
@ -101,7 +94,7 @@ const vm = createApp({
this.fullTextSearch.pageNum ++ this.fullTextSearch.pageNum ++
this.fullTextSearch.isLoading = true this.fullTextSearch.isLoading = true
this.fullTextSearch.tip = undefined this.fullTextSearch.tip = undefined
const params = { let params = {
pageNum: this.fullTextSearch.pageNum, pageNum: this.fullTextSearch.pageNum,
limit: this.fullTextSearch.limit, limit: this.fullTextSearch.limit,
words: this.fullTextSearchWords words: this.fullTextSearchWords
@ -143,15 +136,22 @@ const vm = createApp({
}, time || 5000) }, time || 5000)
} }
}, },
filters: {
urlformat (str) {
return (window.themeConfig && window.themeConfig.root) ? window.themeConfig.root + str : '/' + str
}
},
watch: { watch: {
searchItems(newVal) { searchItems (newVal, oldVal) {
if(newVal && newVal.length) { if(newVal && newVal.length) {
handleSearch.call(this, newVal) handleSearch.call(this, newVal)
} else { } else {
this.items.forEach(item => { item.isHide = false }) this.items.forEach(function(item){
item.isHide = false
})
} }
}, },
fullTextSearchWords(newVal) { fullTextSearchWords (newVal, oldVal) {
this.fullTextSearch.hasMore = false this.fullTextSearch.hasMore = false
this.fullTextSearchItems.isLoading = false this.fullTextSearchItems.isLoading = false
this.fullTextSearch.tip = undefined this.fullTextSearch.tip = undefined
@ -160,7 +160,9 @@ const vm = createApp({
clearTimeout(fullTextSearchTimer) clearTimeout(fullTextSearchTimer)
fullTextSearchTimer = null fullTextSearchTimer = null
} }
if (!newVal) return if(!newVal) {
return
}
this.fullTextSearch.pageNum = 0 this.fullTextSearch.pageNum = 0
fullTextSearchTimer = setTimeout(this.loadSearchResult.bind(this), 500) fullTextSearchTimer = setTimeout(this.loadSearchResult.bind(this), 500)
} }
@ -168,7 +170,7 @@ const vm = createApp({
mounted () { mounted () {
fetch(window.themeConfig.root + 'content.json').then(res => res.json()).then(resJson=>{ fetch(window.themeConfig.root + 'content.json').then(res => res.json()).then(resJson=>{
this.items = resJson this.items = resJson
}).catch(() => { }).catch(err => {
console.warn('加载文章列表失败') console.warn('加载文章列表失败')
}) })
welcomeMessage().then(msg => { welcomeMessage().then(msg => {
@ -177,37 +179,42 @@ const vm = createApp({
document.addEventListener('copy', () => { document.addEventListener('copy', () => {
this.showMessage('你都复制了些什么呀,转载要记得加上出处哦') this.showMessage('你都复制了些什么呀,转载要记得加上出处哦')
}) })
const hideModal = () => { // 隐藏模态框
document.querySelectorAll('.page-modal').forEach(modal => { let hideModal = (function() {
let modals = document.querySelectorAll('.page-modal')
Array.prototype.forEach.call(modals, modal => {
modal.classList.remove('in') modal.classList.remove('in')
}) })
this.$refs.mask.classList.remove('in') this.$refs.mask.classList.remove('in')
} }).bind(this)
// 隐藏模态框
this.$refs.mask.addEventListener('click', hideModal) this.$refs.mask.addEventListener('click', hideModal)
document.querySelectorAll('.js-modal-close').forEach(modalClose => { Array.prototype.forEach.call(document.querySelectorAll('.js-modal-close'), modalClose => {
modalClose.addEventListener('click', hideModal) modalClose.addEventListener('click', hideModal)
}) })
}, },
created() { created() {
// 夜间模式 // 夜间模式
const night = localStorage.getItem('night') let night = localStorage.getItem('night')
if (night === 'true') { try {
document.querySelector('body').classList.add('night') if(night && eval(night)) document.querySelector('body').classList.add('night')
} catch (e){}
} }
} })
}).mount('#container')
function handleSearch(searchItems) { function handleSearch(searchItems) {
this.items.forEach(articleItem => { this.items.forEach(articleItem => {
articleItem.isHide = !searchItems.every(searchItem => { articleItem.isHide = !Array.prototype.every.call(searchItems, searchItem => {
switch(searchItem.type) { switch(searchItem.type) {
case 'title': case 'title':
return articleItem.title.toLowerCase().indexOf(searchItem.query.toLowerCase()) !== -1 return articleItem.title.toLowerCase().indexOf(searchItem.query.toLowerCase()) !== -1
case 'tag' : case 'tag' :
return articleItem.tags.some(tag => tag.name === searchItem.query) return Array.prototype.some.call(articleItem.tags, tag => {
return tag.name === searchItem.query
})
case 'category' : case 'category' :
return articleItem.categories.some(category => category.name === searchItem.query) return Array.prototype.some.call(articleItem.categories, category => {
return category.name === searchItem.query
})
case 'date' : case 'date' :
return articleItem.date && ( articleItem.date.substr(0,7) === searchItem.query ) return articleItem.date && ( articleItem.date.substr(0,7) === searchItem.query )
} }
@ -219,8 +226,16 @@ async function welcomeMessage() {
let now = new Date().getHours() let now = new Date().getHours()
return http.get('/api/v2/common/config/waifu_tip').then(textTimes => { return http.get('/api/v2/common/config/waifu_tip').then(textTimes => {
let text = null let text = null
textTimes.sort((a, b) => a.start - b.start) Array.prototype.sort.call(textTimes, (item1, item2) => {
textTimes.forEach(textTime => { if(item1.start>item2.start) {
return 1
} else if(item1.start<item2.start) {
return -1
} else {
return 0
}
})
Array.prototype.forEach.call(textTimes, textTime => {
if(now > textTime.start && now <= textTime.end) { if(now > textTime.start && now <= textTime.end) {
text = textTime.text text = textTime.text
} }

View File

@ -24,7 +24,7 @@ module.exports = function(env, argv) {
})] })]
}, },
entry: { entry: {
main: './source-src/js/main.js', main: ['babel-polyfill', './source-src/js/main.js'],
slider: './source-src/js/slider.js', slider: './source-src/js/slider.js',
mobile: './source-src/js/mobile.js', mobile: './source-src/js/mobile.js',
viewer: './source-src/js/viewer.js' viewer: './source-src/js/viewer.js'
@ -37,25 +37,39 @@ module.exports = function(env, argv) {
module: { module: {
rules: [{ rules: [{
test: /\.js$/, test: /\.js$/,
use: 'babel-loader', use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-class-properties'],
},
},
exclude: /node_modules/ exclude: /node_modules/
},{ },{
test: /\.less$/, test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader'] use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
},{ },{
test: /\.css$/, test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'] use: [MiniCssExtractPlugin.loader, 'css-loader']
},{ },{
test: /\.(png|jpe?g|gif|ico)$/, test: /\.(png|jpe?g|gif|ico)$/,
type: 'asset/resource', use: {
generator: { loader: 'file-loader',
filename: 'images/[name].[contenthash:6][ext]' options: {
name: '[name].[contenthash:6].[ext]',
outputPath: 'images',
esModule: false // 不使用es6的模块语法
}
} }
},{ },{
test: /\.(svg|eot|ttf|woff2?|otf)$/, test: /\.(svg|eot|ttf|woff2?|otf)$/,
type: 'asset/resource', use: {
generator: { loader: 'file-loader',
filename: 'fonts/[name].[contenthash:6][ext]' options: {
name: '[name].[contenthash:6].[ext]',
outputPath: 'fonts',
esModule: false // 不使用es6的模块语法
}
} }
} }
] ]