diff --git a/blog.config.js b/blog.config.js index f19261e9..c0fcca5e 100644 --- a/blog.config.js +++ b/blog.config.js @@ -70,6 +70,14 @@ const BLOG = { // 樱花飘落特效 SAKURA: process.env.NEXT_PUBLIC_SAKURA || false, // 开关 + // 漂浮线段特效 + NEST: process.env.NEXT_PUBLIC_NEST || false, // 开关 + + // 动态彩带特效 + FLUTTERINGRIBBON: process.env.NEXT_PUBLIC_FLUTTERINGRIBBON || false, // 开关 + // 静态彩带特效 + RIBBON: process.env.NEXT_PUBLIC_RIBBON || false, // 开关 + // 星空雨特效 黑夜模式才会生效 STARRY_SKY: process.env.NEXT_PUBLIC_STARRY_SKY || false, // 开关 diff --git a/components/FlutteringRibbon.js b/components/FlutteringRibbon.js new file mode 100644 index 00000000..2eb817e4 --- /dev/null +++ b/components/FlutteringRibbon.js @@ -0,0 +1,307 @@ +/* eslint-disable */ +import React from 'react' + +export const FlutteringRibbon = () => { + React.useEffect(() => { + createFlutteringRibbon() + }, []) +} + +/** + * 创建连接点 + * @param config + */ +function createFlutteringRibbon() { + 'object' == typeof window && + (window.Ribbons = (function () { + const t = window, + i = document.body, + n = document.documentElement + var o = function () { + if (1 === arguments.length) { + if (Array.isArray(arguments[0])) { + const t = Math.round(o(0, arguments[0].length - 1)) + return arguments[0][t] + } + return o(0, arguments[0]) + } + return 2 === arguments.length + ? Math.random() * (arguments[1] - arguments[0]) + arguments[0] + : 0 + } + const s = function (o) { + const s = Math.max( + 0, + t.innerWidth || n.clientWidth || i.clientWidth || 0 + ), + e = Math.max( + 0, + t.innerHeight || n.clientHeight || i.clientHeight || 0 + ) + return { + width: s, + height: e, + ratio: s / e, + centerx: s / 2, + centery: e / 2, + scrollx: + Math.max(0, t.pageXOffset || n.scrollLeft || i.scrollLeft || 0) - + (n.clientLeft || 0), + scrolly: + Math.max(0, t.pageYOffset || n.scrollTop || i.scrollTop || 0) - + (n.clientTop || 0) + } + }, + e = function (t, i) { + ;(this.x = 0), (this.y = 0), this.set(t, i) + } + e.prototype = { + constructor: e, + set: function (t, i) { + ;(this.x = t || 0), (this.y = i || 0) + }, + copy: function (t) { + return (this.x = t.x || 0), (this.y = t.y || 0), this + }, + multiply: function (t, i) { + return (this.x *= t || 1), (this.y *= i || 1), this + }, + divide: function (t, i) { + return (this.x /= t || 1), (this.y /= i || 1), this + }, + add: function (t, i) { + return (this.x += t || 0), (this.y += i || 0), this + }, + subtract: function (t, i) { + return (this.x -= t || 0), (this.y -= i || 0), this + }, + clampX: function (t, i) { + return (this.x = Math.max(t, Math.min(this.x, i))), this + }, + clampY: function (t, i) { + return (this.y = Math.max(t, Math.min(this.y, i))), this + }, + flipX: function () { + return (this.x *= -1), this + }, + flipY: function () { + return (this.y *= -1), this + } + } + const h = function (t) { + ;(this._canvas = null), + (this._context = null), + (this._sto = null), + (this._width = 0), + (this._height = 0), + (this._scroll = 0), + (this._ribbons = []), + (this._options = { + colorSaturation: '80%', + colorBrightness: '60%', + colorAlpha: 0.65, + colorCycleSpeed: 6, + verticalPosition: 'center', + horizontalSpeed: 150, + ribbonCount: 5, + strokeSize: 5, + parallaxAmount: -0.5, + animateSections: !0 + }), + (this._onDraw = this._onDraw.bind(this)), + (this._onResize = this._onResize.bind(this)), + (this._onScroll = this._onScroll.bind(this)), + this.setOptions(t), + this.init() + } + return ( + (h.prototype = { + constructor: h, + setOptions: function (t) { + if ('object' == typeof t) + for (const i in t) + t.hasOwnProperty(i) && (this._options[i] = t[i]) + }, + init: function () { + try { + ;(this._canvas = document.createElement('canvas')), + (this._canvas.style.display = 'block'), + (this._canvas.style.position = 'fixed'), + (this._canvas.style.margin = '0'), + (this._canvas.style.padding = '0'), + (this._canvas.style.border = '0'), + (this._canvas.style.outline = '0'), + (this._canvas.style.left = '0'), + (this._canvas.style.top = '0'), + (this._canvas.style.width = '100%'), + (this._canvas.style.height = '100%'), + (this._canvas.style['z-index'] = '0'), + this._onResize(), + (this._context = this._canvas.getContext('2d')), + this._context.clearRect(0, 0, this._width, this._height), + (this._context.globalAlpha = this._options.colorAlpha), + window.addEventListener('resize', this._onResize), + window.addEventListener('scroll', this._onScroll), + document.body.appendChild(this._canvas) + } catch (t) { + return void console.warn('Canvas Context Error: ' + t.toString()) + } + this._onDraw() + }, + addRibbon: function () { + const t = Math.round(o(1, 9)) > 5 ? 'right' : 'left' + let i = 1e3 + const n = 200, + s = 0 - n, + h = this._width + n + let a = 0, + r = 0 + const l = 'right' === t ? s : h + let c = Math.round(o(0, this._height)) + ;/^(top|min)$/i.test(this._options.verticalPosition) + ? (c = 0 + n) + : /^(middle|center)$/i.test(this._options.verticalPosition) + ? (c = this._height / 2) + : /^(bottom|max)$/i.test(this._options.verticalPosition) && + (c = this._height - n) + const p = [], + _ = new e(l, c), + d = new e(l, c) + let u = null, + b = Math.round(o(0, 360)), + f = 0 + for (; !(i <= 0); ) { + if ( + (i--, + (a = Math.round( + (1 * Math.random() - 0.2) * this._options.horizontalSpeed + )), + (r = Math.round( + (1 * Math.random() - 0.5) * (0.25 * this._height) + )), + (u = new e()), + u.copy(d), + 'right' === t) + ) { + if ((u.add(a, r), d.x >= h)) break + } else if ('left' === t && (u.subtract(a, r), d.x <= s)) break + p.push({ + point1: new e(_.x, _.y), + point2: new e(d.x, d.y), + point3: u, + color: b, + delay: f, + dir: t, + alpha: 0, + phase: 0 + }), + _.copy(d), + d.copy(u), + (f += 4), + (b += this._options.colorCycleSpeed) + } + this._ribbons.push(p) + }, + _drawRibbonSection: function (t) { + if (t) { + if (t.phase >= 1 && t.alpha <= 0) return !0 + if (t.delay <= 0) { + if ( + ((t.phase += 0.02), + (t.alpha = 1 * Math.sin(t.phase)), + (t.alpha = t.alpha <= 0 ? 0 : t.alpha), + (t.alpha = t.alpha >= 1 ? 1 : t.alpha), + this._options.animateSections) + ) { + const i = 0.1 * Math.sin(1 + (t.phase * Math.PI) / 2) + 'right' === t.dir + ? (t.point1.add(i, 0), + t.point2.add(i, 0), + t.point3.add(i, 0)) + : (t.point1.subtract(i, 0), + t.point2.subtract(i, 0), + t.point3.subtract(i, 0)), + t.point1.add(0, i), + t.point2.add(0, i), + t.point3.add(0, i) + } + } else t.delay -= 0.5 + const i = this._options.colorSaturation, + n = this._options.colorBrightness, + o = + 'hsla(' + + t.color + + ', ' + + i + + ', ' + + n + + ', ' + + t.alpha + + ' )' + this._context.save(), + 0 !== this._options.parallaxAmount && + this._context.translate( + 0, + this._scroll * this._options.parallaxAmount + ), + this._context.beginPath(), + this._context.moveTo(t.point1.x, t.point1.y), + this._context.lineTo(t.point2.x, t.point2.y), + this._context.lineTo(t.point3.x, t.point3.y), + (this._context.fillStyle = o), + this._context.fill(), + this._options.strokeSize > 0 && + ((this._context.lineWidth = this._options.strokeSize), + (this._context.strokeStyle = o), + (this._context.lineCap = 'round'), + this._context.stroke()), + this._context.restore() + } + return !1 + }, + _onDraw: function () { + for (let t = 0, i = this._ribbons.length; t < i; ++t) + this._ribbons[t] || this._ribbons.splice(t, 1) + this._context.clearRect(0, 0, this._width, this._height) + for (let t = 0; t < this._ribbons.length; ++t) { + const i = this._ribbons[t], + n = i.length + let o = 0 + for (let t = 0; t < n; ++t) this._drawRibbonSection(i[t]) && o++ + o >= n && (this._ribbons[t] = null) + } + this._ribbons.length < this._options.ribbonCount && + this.addRibbon(), + requestAnimationFrame(this._onDraw) + }, + _onResize: function (t) { + const i = s(t) + ;(this._width = i.width), + (this._height = i.height), + this._canvas && + ((this._canvas.width = this._width), + (this._canvas.height = this._height), + this._context && + (this._context.globalAlpha = this._options.colorAlpha)) + }, + _onScroll: function (t) { + const i = s(t) + this._scroll = i.scrolly + } + }), + h + ) + })()) + new Ribbons({ + colorSaturation: '60%', + colorBrightness: '50%', + colorAlpha: 0.5, + colorCycleSpeed: 5, + verticalPosition: 'random', + horizontalSpeed: 200, + ribbonCount: 3, + strokeSize: 0, + parallaxAmount: -0.2, + animateSections: !0 + }) +} diff --git a/components/Nest.js b/components/Nest.js new file mode 100644 index 00000000..61f0ce30 --- /dev/null +++ b/components/Nest.js @@ -0,0 +1,113 @@ +/* eslint-disable */ +import React from 'react' + +export const Nest = () => { + React.useEffect(() => { + createNest() + }, []) +} + +/** + * 创建连接点 + * @param config + */ +function createNest() { + const e = document.getElementById('__next') + if(!e) return + function n(e, n, t) { + return e.getAttribute(n) || t + } + function t() { + ;(u = i.width = + window.innerWidth || + document.documentElement.clientWidth || + document.body.clientWidth), + (d = i.height = + window.innerHeight || + document.documentElement.clientHeight || + document.body.clientHeight) + } + function o() { + c.clearRect(0, 0, u, d) + const e = [s].concat(x) + let n, t, i, l, r, w + x.forEach(function (o) { + for ( + o.x += o.xa, + o.y += o.ya, + o.xa *= o.x > u || o.x < 0 ? -1 : 1, + o.ya *= o.y > d || o.y < 0 ? -1 : 1, + c.fillRect(o.x - 0.5, o.y - 0.5, 1, 1), + t = 0; + t < e.length; + t++ + ) + (n = e[t]), + o !== n && + null !== n.x && + null !== n.y && + ((l = o.x - n.x), + (r = o.y - n.y), + (w = l * l + r * r), + w < n.max && + (n === s && + w >= n.max / 2 && + ((o.x -= 0.03 * l), (o.y -= 0.03 * r)), + (i = (n.max - w) / n.max), + c.beginPath(), + (c.lineWidth = i / 2), + (c.strokeStyle = 'rgba(' + a.c + ',' + (i + 0.2) + ')'), + c.moveTo(o.x, o.y), + c.lineTo(n.x, n.y), + c.stroke())) + e.splice(e.indexOf(o), 1) + }), + m(o) + } + var i = document.createElement('canvas') + i.id = 'canvasNestCreated' + var a = (function () { + const t = e + return { + z: n(t, 'zIndex', 0), + o: n(t, 'opacity', 0.7), + c: n(t, 'color', '0,0,0'), + n: n(t, 'count', 99) + } + })(), + c = i.getContext('2d') + let u, d + var m = + window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (e) { + window.setTimeout(e, 1e3 / 45) + } + const l = Math.random + var r, + s = { x: null, y: null, max: 2e4 } + ;(i.style.cssText = + 'position:fixed;top:0;left:0;z-index:' + a.z + ';opacity:' + a.o), + (r = 'body'), e.appendChild(i), + t(), + (window.onresize = t), + (window.onmousemove = function (e) { + ;(e = e || window.event), (s.x = e.clientX), (s.y = e.clientY) + }), + (window.onmouseout = function () { + ;(s.x = null), (s.y = null) + }) + for (var x = [], w = 0; a.n > w; w++) { + const e = l() * u, + n = l() * d, + t = 2 * l() - 1, + o = 2 * l() - 1 + x.push({ x: e, y: n, xa: t, ya: o, max: 6e3 }) + } + setTimeout(function () { + o() + }, 100) +} diff --git a/components/Ribbon.js b/components/Ribbon.js new file mode 100644 index 00000000..d96e3591 --- /dev/null +++ b/components/Ribbon.js @@ -0,0 +1,85 @@ +/* eslint-disable */ +import React from 'react' + +export const Ribbon = () => { + React.useEffect(() => { + createRibbon() + }, []) +} + +/** + * 创建连接点 + * @param config + */ +function createRibbon() { + !(function () { + const t = document.getElementById('__next') + const e = { + z: n(t, 'zIndex', 0), + a: n(t, 'alpha', 0.6), + s: n(t, 'size', 90), + c: t.getAttribute('data-click') + } + function n(t, e, n) { + return Number(t.getAttribute(e)) || n + } + const i = document.createElement('canvas'), + o = i.getContext('2d'), + c = window.devicePixelRatio || 1, + a = window.innerWidth, + l = window.innerHeight, + d = e.s + let r, s + const u = Math + let h = 0 + const g = 2 * u.PI, + f = u.cos, + m = u.random + function x() { + for ( + o.clearRect(0, 0, a, l), + r = [ + { x: 0, y: 0.7 * l + d }, + { x: 0, y: 0.7 * l - d } + ]; + r[1].x < a + d; + + ) + y(r[0], r[1]) + } + function y(t, e) { + o.beginPath(), o.moveTo(t.x, t.y), o.lineTo(e.x, e.y) + const n = e.x + (2 * m() - 0.25) * d, + i = b(e.y) + o.lineTo(n, i), + o.closePath(), + (h -= g / -50), + (o.fillStyle = + '#' + + ( + ((127 * f(h) + 128) << 16) | + ((127 * f(h + g / 3) + 128) << 8) | + (127 * f(h + (g / 3) * 2) + 128) + ).toString(16)), + o.fill(), + (r[0] = r[1]), + (r[1] = { x: n, y: i }) + } + function b(t) { + return (s = t + (2 * m() - 1.1) * d), s > l || s < 0 ? b(t) : s + } + ;(i.width = a * c), + (i.height = l * c), + o.scale(c, c), + (o.globalAlpha = e.a), + (i.style.cssText = + 'opacity: ' + + e.a + + ';position:fixed;top:0;left:0;z-index: ' + + e.z + + ';width:100%;height:100%;pointer-events:none;'), + document.getElementsByTagName('body')[0].appendChild(i), + 'false' !== e.c && ((document.onclick = x), (document.ontouchstart = x)), + x() + })() +} diff --git a/components/Sakura.js b/components/Sakura.js index 24c55244..3f69cc25 100644 --- a/components/Sakura.js +++ b/components/Sakura.js @@ -1,15 +1,10 @@ /* eslint-disable */ -/** - * https://codepen.io/juliangarnier/pen/gmOwJX - * custom by hexo-theme-yun @YunYouJun - */ import React from 'react' export const Sakura = () => { React.useEffect(() => { createSakura({}) }, []) - // return } /** diff --git a/components/StarrySky.js b/components/StarrySky.js index 045dd533..3a3a77d6 100644 --- a/components/StarrySky.js +++ b/components/StarrySky.js @@ -1,8 +1,4 @@ /* eslint-disable */ -/** - * https://codepen.io/juliangarnier/pen/gmOwJX - * custom by hexo-theme-yun @YunYouJun - */ import React from 'react' export const StarrySky = () => { diff --git a/pages/_app.js b/pages/_app.js index 099b8514..f0eedb2c 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -25,6 +25,9 @@ import { GlobalContextProvider } from '@/lib/global' import { DebugPanel } from '@/components/DebugPanel' import { ThemeSwitch } from '@/components/ThemeSwitch' import { Fireworks } from '@/components/Fireworks' +import { Nest } from '@/components/Nest' +import { FlutteringRibbon } from '@/components/FlutteringRibbon' +import { Ribbon } from '@/components/Ribbon' import { Sakura } from '@/components/Sakura' import { StarrySky } from '@/components/StarrySky' import MusicPlayer from '@/components/MusicPlayer' @@ -53,6 +56,9 @@ const MyApp = ({ Component, pageProps }) => { {JSON.parse(BLOG.SAKURA) && } {JSON.parse(BLOG.STARRY_SKY) && } {JSON.parse(BLOG.MUSIC_PLAYER) && } + {JSON.parse(BLOG.NEST) && } + {JSON.parse(BLOG.FLUTTERINGRIBBON) && } + {JSON.parse(BLOG.RIBBON) && } // 默认Webfont: 请在font.js文件中检查font-family 新版改从npm本地导入; diff --git a/themes/example/LayoutBase.js b/themes/example/LayoutBase.js index dca7d326..695562a9 100644 --- a/themes/example/LayoutBase.js +++ b/themes/example/LayoutBase.js @@ -25,7 +25,7 @@ const LayoutBase = props => {