Skip to content

Commit

Permalink
Build & Deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] committed Feb 11, 2024
0 parents commit 70df7d0
Show file tree
Hide file tree
Showing 70 changed files with 13,073 additions and 0 deletions.
304 changes: 304 additions & 0 deletions about/index.html

Large diffs are not rendered by default.

273 changes: 273 additions & 0 deletions archives/2023/05/index.html

Large diffs are not rendered by default.

273 changes: 273 additions & 0 deletions archives/2023/index.html

Large diffs are not rendered by default.

273 changes: 273 additions & 0 deletions archives/index.html

Large diffs are not rendered by default.

273 changes: 273 additions & 0 deletions categories/Android/VPN/index.html

Large diffs are not rendered by default.

273 changes: 273 additions & 0 deletions categories/Android/index.html

Large diffs are not rendered by default.

275 changes: 275 additions & 0 deletions categories/index.html

Large diffs are not rendered by default.

6,289 changes: 6,289 additions & 0 deletions css/index.css

Large diffs are not rendered by default.

Empty file added css/var.css
Empty file.
Binary file added img/404.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/friend_404.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
321 changes: 321 additions & 0 deletions index.html

Large diffs are not rendered by default.

827 changes: 827 additions & 0 deletions js/main.js

Large diffs are not rendered by default.

163 changes: 163 additions & 0 deletions js/search/algolia.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
window.addEventListener('load', () => {
const openSearch = () => {
const bodyStyle = document.body.style
bodyStyle.width = '100%'
bodyStyle.overflow = 'hidden'
btf.animateIn(document.getElementById('search-mask'), 'to_show 0.5s')
btf.animateIn(document.querySelector('#algolia-search .search-dialog'), 'titleScale 0.5s')
setTimeout(() => { document.querySelector('#algolia-search .ais-SearchBox-input').focus() }, 100)

// shortcut: ESC
document.addEventListener('keydown', function f (event) {
if (event.code === 'Escape') {
closeSearch()
document.removeEventListener('keydown', f)
}
})
}

const closeSearch = () => {
const bodyStyle = document.body.style
bodyStyle.width = ''
bodyStyle.overflow = ''
btf.animateOut(document.querySelector('#algolia-search .search-dialog'), 'search_close .5s')
btf.animateOut(document.getElementById('search-mask'), 'to_hide 0.5s')
}

const searchClickFn = () => {
document.querySelector('#search-button > .search').addEventListener('click', openSearch)
}

const searchClickFnOnce = () => {
document.getElementById('search-mask').addEventListener('click', closeSearch)
document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch)
}

const cutContent = content => {
if (content === '') return ''

const firstOccur = content.indexOf('<mark>')

let start = firstOccur - 30
let end = firstOccur + 120
let pre = ''
let post = ''

if (start <= 0) {
start = 0
end = 140
} else {
pre = '...'
}

if (end > content.length) {
end = content.length
} else {
post = '...'
}

const matchContent = pre + content.substring(start, end) + post
return matchContent
}

const algolia = GLOBAL_CONFIG.algolia
const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName
if (!isAlgoliaValid) {
return console.error('Algolia setting is invalid!')
}

const search = instantsearch({
indexName: algolia.indexName,
/* global algoliasearch */
searchClient: algoliasearch(algolia.appId, algolia.apiKey),
searchFunction (helper) {
helper.state.query && helper.search()
}
})

const configure = instantsearch.widgets.configure({
hitsPerPage: 5
})

const searchBox = instantsearch.widgets.searchBox({
container: '#algolia-search-input',
showReset: false,
showSubmit: false,
placeholder: GLOBAL_CONFIG.algolia.languages.input_placeholder,
showLoadingIndicator: true
})

const hits = instantsearch.widgets.hits({
container: '#algolia-hits',
templates: {
item (data) {
const link = data.permalink ? data.permalink : (GLOBAL_CONFIG.root + data.path)
const result = data._highlightResult
const content = result.contentStripTruncate
? cutContent(result.contentStripTruncate.value)
: result.contentStrip
? cutContent(result.contentStrip.value)
: result.content
? cutContent(result.content.value)
: ''
return `
<a href="${link}" class="algolia-hit-item-link">
${result.title.value || 'no-title'}
</a>
<p class="algolia-hit-item-content">${content}</p>`
},
empty: function (data) {
return (
'<div id="algolia-hits-empty">' +
GLOBAL_CONFIG.algolia.languages.hits_empty.replace(/\$\{query}/, data.query) +
'</div>'
)
}
}
})

const stats = instantsearch.widgets.stats({
container: '#algolia-info > .algolia-stats',
templates: {
text: function (data) {
const stats = GLOBAL_CONFIG.algolia.languages.hits_stats
.replace(/\$\{hits}/, data.nbHits)
.replace(/\$\{time}/, data.processingTimeMS)
return (
`<hr>${stats}`
)
}
}
})

const powerBy = instantsearch.widgets.poweredBy({
container: '#algolia-info > .algolia-poweredBy'
})

const pagination = instantsearch.widgets.pagination({
container: '#algolia-pagination',
totalPages: 5,
templates: {
first: '<i class="fas fa-angle-double-left"></i>',
last: '<i class="fas fa-angle-double-right"></i>',
previous: '<i class="fas fa-angle-left"></i>',
next: '<i class="fas fa-angle-right"></i>'
}
})

search.addWidgets([configure, searchBox, hits, stats, powerBy, pagination]) // add the widgets to the instantsearch instance

search.start()

searchClickFn()
searchClickFnOnce()

window.addEventListener('pjax:complete', () => {
getComputedStyle(document.querySelector('#algolia-search .search-dialog')).display === 'block' && closeSearch()
searchClickFn()
})

window.pjax && search.on('render', () => {
window.pjax.refresh(document.getElementById('algolia-hits'))
})
})
190 changes: 190 additions & 0 deletions js/search/local-search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
window.addEventListener('load', () => {
let loadFlag = false
let dataObj = []
const $searchMask = document.getElementById('search-mask')

const openSearch = () => {
const bodyStyle = document.body.style
bodyStyle.width = '100%'
bodyStyle.overflow = 'hidden'
btf.animateIn($searchMask, 'to_show 0.5s')
btf.animateIn(document.querySelector('#local-search .search-dialog'), 'titleScale 0.5s')
setTimeout(() => { document.querySelector('#local-search-input input').focus() }, 100)
if (!loadFlag) {
search()
loadFlag = true
}
// shortcut: ESC
document.addEventListener('keydown', function f (event) {
if (event.code === 'Escape') {
closeSearch()
document.removeEventListener('keydown', f)
}
})
}

const closeSearch = () => {
const bodyStyle = document.body.style
bodyStyle.width = ''
bodyStyle.overflow = ''
btf.animateOut(document.querySelector('#local-search .search-dialog'), 'search_close .5s')
btf.animateOut($searchMask, 'to_hide 0.5s')
}

const searchClickFn = () => {
document.querySelector('#search-button > .search').addEventListener('click', openSearch)
}

const searchClickFnOnce = () => {
document.querySelector('#local-search .search-close-button').addEventListener('click', closeSearch)
$searchMask.addEventListener('click', closeSearch)
if (GLOBAL_CONFIG.localSearch.preload) dataObj = fetchData(GLOBAL_CONFIG.localSearch.path)
}

// check url is json or not
const isJson = url => {
const reg = /\.json$/
return reg.test(url)
}

const fetchData = async (path) => {
let data = []
const response = await fetch(path)
if (isJson(path)) {
data = await response.json()
} else {
const res = await response.text()
const t = await new window.DOMParser().parseFromString(res, 'text/xml')
const a = await t
data = [...a.querySelectorAll('entry')].map(item => {
return {
title: item.querySelector('title').textContent,
content: item.querySelector('content') && item.querySelector('content').textContent,
url: item.querySelector('url').textContent
}
})
}
if (response.ok) {
const $loadDataItem = document.getElementById('loading-database')
$loadDataItem.nextElementSibling.style.display = 'block'
$loadDataItem.remove()
}
return data
}

const search = () => {
if (!GLOBAL_CONFIG.localSearch.preload) {
dataObj = fetchData(GLOBAL_CONFIG.localSearch.path)
}

const $input = document.querySelector('#local-search-input input')
const $resultContent = document.getElementById('local-search-results')
const $loadingStatus = document.getElementById('loading-status')

$input.addEventListener('input', function () {
const keywords = this.value.trim().toLowerCase().split(/[\s]+/)
if (keywords[0] !== '') $loadingStatus.innerHTML = '<i class="fas fa-spinner fa-pulse"></i>'
else {
$resultContent.innerHTML = ''
return
}

let str = '<div class="search-result-list">'
if (keywords.length <= 0) return
let count = 0
// perform local searching
dataObj.then(data => {
data.forEach(data => {
let isMatch = true
let dataTitle = data.title ? data.title.trim().toLowerCase() : ''
const dataContent = data.content ? data.content.trim().replace(/<[^>]+>/g, '').toLowerCase() : ''
const dataUrl = data.url.startsWith('/') ? data.url : GLOBAL_CONFIG.root + data.url
let indexTitle = -1
let indexContent = -1
let firstOccur = -1
// only match articles with not empty titles and contents
if (dataTitle !== '' || dataContent !== '') {
keywords.forEach((keyword, i) => {
indexTitle = dataTitle.indexOf(keyword)
indexContent = dataContent.indexOf(keyword)
if (indexTitle < 0 && indexContent < 0) {
isMatch = false
} else {
if (indexContent < 0) {
indexContent = 0
}
if (i === 0) {
firstOccur = indexContent
}
}
})
} else {
isMatch = false
}

// show search results
if (isMatch) {
if (firstOccur >= 0) {
// cut out 130 characters
// let start = firstOccur - 30 < 0 ? 0 : firstOccur - 30
// let end = firstOccur + 50 > dataContent.length ? dataContent.length : firstOccur + 50
let start = firstOccur - 30
let end = firstOccur + 100
let pre = ''
let post = ''

if (start < 0) {
start = 0
}

if (start === 0) {
end = 100
} else {
pre = '...'
}

if (end > dataContent.length) {
end = dataContent.length
} else {
post = '...'
}

let matchContent = dataContent.substring(start, end)

// highlight all keywords
keywords.forEach(keyword => {
matchContent = matchContent.replaceAll(keyword, '<span class="search-keyword">' + keyword + '</span>')
dataTitle = dataTitle.replaceAll(keyword, '<span class="search-keyword">' + keyword + '</span>')
})

str += '<div class="local-search__hit-item"><a href="' + dataUrl + '"><span class="search-result-title">' + dataTitle + '</span>'
count += 1

if (dataContent !== '') {
str += '<p class="search-result">' + pre + matchContent + post + '</p>'
}
}
str += '</a></div>'
}
})
if (count === 0) {
str += '<div id="local-search__hits-empty">' + GLOBAL_CONFIG.localSearch.languages.hits_empty.replace(/\$\{query}/, this.value.trim()) +
'</div>'
}
str += '</div>'
$resultContent.innerHTML = str
if (keywords[0] !== '') $loadingStatus.innerHTML = ''
window.pjax && window.pjax.refresh($resultContent)
})
})
}

searchClickFn()
searchClickFnOnce()

// pjax
window.addEventListener('pjax:complete', () => {
!btf.isHidden($searchMask) && closeSearch()
searchClickFn()
})
})
Loading

0 comments on commit 70df7d0

Please sign in to comment.