feat: 设置及盒子页面构建

This commit is contained in:
imsyy 2023-08-07 18:09:18 +08:00
parent 1b016cb037
commit c184efb8ce
24 changed files with 451 additions and 87 deletions

View File

@ -1,26 +1,30 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Snavigation</title>
<!-- HarmonyOS Sans -->
<link rel="stylesheet" href="https://s1.hdslb.com/bfs/static/jinkela/long/font/regular.css" />
<!-- IE Out -->
<script>
if (
/*@cc_on!@*/
false ||
(!!window.MSInputMethodContext && !!document.documentMode)
)
window.location.href =
"https://support.dmeng.net/upgrade-your-browser.html?referrer=" +
encodeURIComponent(window.location.href);
</script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Snavigation</title>
<!-- HarmonyOS Sans -->
<link rel="stylesheet" href="https://s1.hdslb.com/bfs/static/jinkela/long/font/regular.css" />
<!-- IE Out -->
<script>
if (
/*@cc_on!@*/
false ||
(!!window.MSInputMethodContext && !!document.documentMode)
)
window.location.href =
"https://support.dmeng.net/upgrade-your-browser.html?referrer=" +
encodeURIComponent(window.location.href);
</script>
</head>
<body>
<div id="app"></div>
<script src="/lib/iconfont.js" async></script>
<script type="module" src="/src/main.js"></script>
</body>
</html>

View File

@ -1,7 +1,7 @@
{
"name": "snavigation",
"private": true,
"version": "2.0.0 beta 2",
"version": "2.0.0 beta 3",
"type": "module",
"scripts": {
"dev": "vite --host",
@ -21,6 +21,7 @@
"@vitejs/plugin-vue": "^4.2.3",
"naive-ui": "^2.34.4",
"terser": "^5.19.2",
"vite": "^4.4.5"
"vite": "^4.4.5",
"vite-plugin-compression": "^0.5.1"
}
}

View File

@ -40,6 +40,9 @@ devDependencies:
vite:
specifier: ^4.4.5
version: 4.4.6(sass@1.64.1)(terser@5.19.2)
vite-plugin-compression:
specifier: ^0.5.1
version: 0.5.1(vite@4.4.6)
packages:
@ -1691,7 +1694,6 @@ packages:
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
dev: false
/anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
@ -1859,7 +1861,6 @@ packages:
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
dev: false
/chokidar@3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
@ -1886,7 +1887,6 @@ packages:
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: false
/color-name@1.1.3:
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
@ -1894,7 +1894,6 @@ packages:
/color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: false
/combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
@ -1969,7 +1968,6 @@ packages:
optional: true
dependencies:
ms: 2.1.2
dev: false
/deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
@ -2185,6 +2183,15 @@ packages:
mime-types: 2.1.35
dev: false
/fs-extra@10.1.0:
resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==}
engines: {node: '>=12'}
dependencies:
graceful-fs: 4.2.11
jsonfile: 6.1.0
universalify: 2.0.0
dev: true
/fs-extra@9.1.0:
resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
engines: {node: '>=10'}
@ -2287,7 +2294,6 @@ packages:
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
dev: false
/has-bigints@1.0.2:
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
@ -2301,7 +2307,6 @@ packages:
/has-flag@4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
dev: false
/has-property-descriptors@1.0.0:
resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
@ -2556,7 +2561,6 @@ packages:
universalify: 2.0.0
optionalDependencies:
graceful-fs: 4.2.11
dev: false
/jsonpointer@5.0.1:
resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==}
@ -2645,7 +2649,6 @@ packages:
/ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: false
/naive-ui@2.34.4(vue@3.3.4):
resolution: {integrity: sha512-aPG8PDfhSzIzn/jSC9y3Jb3Pe2wHJ7F0cFV1EWlbImSrZECeUmoc+fIcOSWbizoztkKfaUAeKwYdMl09MKkj1g==}
@ -3040,7 +3043,6 @@ packages:
engines: {node: '>=8'}
dependencies:
has-flag: 4.0.0
dev: false
/supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
@ -3177,7 +3179,6 @@ packages:
/universalify@2.0.0:
resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
engines: {node: '>= 10.0.0'}
dev: false
/upath@1.2.0:
resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==}
@ -3210,6 +3211,19 @@ packages:
vue: 3.3.4
dev: true
/vite-plugin-compression@0.5.1(vite@4.4.6):
resolution: {integrity: sha512-5QJKBDc+gNYVqL/skgFAP81Yuzo9R+EAf19d+EtsMF/i8kFUpNi3J/H01QD3Oo8zBQn+NzoCIFkpPLynoOzaJg==}
peerDependencies:
vite: '>=2.0.0'
dependencies:
chalk: 4.1.2
debug: 4.3.4
fs-extra: 10.1.0
vite: 4.4.6(sass@1.64.1)(terser@5.19.2)
transitivePeerDependencies:
- supports-color
dev: true
/vite-plugin-pwa@0.16.4(vite@4.4.6)(workbox-build@7.0.0)(workbox-window@7.0.0):
resolution: {integrity: sha512-lmwHFIs9zI2H9bXJld/zVTbCqCQHZ9WrpyDMqosICDV0FVnCJwniX1NMDB79HGTIZzOQkY4gSZaVTJTw6maz/Q==}
engines: {node: '>=16.0.0'}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

1
public/lib/iconfont.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -4,10 +4,43 @@
<Cover @loadComplete="loadComplete" />
<!-- 主界面 -->
<Transition name="fade" mode="out-in">
<main v-if="status.imgLoadStatus" id="main" @click="mainClick">
<main
v-if="status.imgLoadStatus"
tabindex="0"
id="main"
:class="`main-${status.siteStatus}`"
@click="status.setSiteStatus('normal')"
@contextmenu="mainContextmenu"
@keydown="mainPressKeyboard"
>
<WeatherTime />
<SearchInp />
<SearchInp @contextmenu.stop />
<AllFunc @contextmenu.stop />
<Footer />
<!-- 状态切换 -->
<Transition name="fade">
<div
v-show="
status.siteStatus !== 'focus' && status.siteStatus !== 'normal'
"
class="change-status"
:title="status.siteStatus !== 'set' ? '设置' : '首页'"
@click.stop="
status.setSiteStatus(
status.siteStatus !== 'set' ? 'set' : 'normal'
)
"
>
<Transition name="fade" mode="out-in">
<SvgIcon
:iconName="`icon-${
status.siteStatus !== 'set' ? 'setting' : 'home'
}`"
:key="status.siteStatus !== 'set' ? 'setting' : 'home'"
/>
</Transition>
</div>
</Transition>
<!-- Notification -->
<Notification />
</main>
@ -26,7 +59,8 @@ import { getGreeting } from "@/utils/timeTools";
import Provider from "@/components/Provider.vue";
import Cover from "@/components/Cover.vue";
import WeatherTime from "@/components/WeatherTime.vue";
import SearchInp from "@/components/SearchInp.vue";
import SearchInp from "@/components/SearchInput/SearchInp.vue";
import AllFunc from "@/components/AllFunc/AllFunc.vue";
import Footer from "@/components/Footer.vue";
const status = statusStore();
@ -34,9 +68,10 @@ const status = statusStore();
//
const welcomeText = import.meta.env.VITE_WELCOME_TEXT ?? "欢迎访问本站";
//
const mainClick = () => {
status.setSiteStatus("normal");
//
const mainContextmenu = (event) => {
event.preventDefault();
status.setSiteStatus("box");
};
//
@ -48,6 +83,18 @@ const loadComplete = () => {
});
});
};
//
const mainPressKeyboard = (event) => {
const keyCode = event.keyCode;
//
if (keyCode === 13) {
// focus
const mainInput = document.getElementById("main-input");
status.setSiteStatus("focus");
mainInput?.focus();
}
};
</script>
<style lang="scss" scoped>
@ -62,6 +109,53 @@ const loadComplete = () => {
flex-direction: column;
justify-content: center;
align-items: center;
&.main-normal,
&.main-focus {
.main-box {
opacity: 0;
margin-top: 0;
transform: scale(0.35);
pointer-events: none;
}
}
&.main-box,
&.main-set {
.main-box {
opacity: 1;
margin-top: 200px;
transform: scale(1);
visibility: visible;
}
.search-input {
:deep(.all) {
opacity: 0;
width: 0;
visibility: hidden;
}
}
}
.change-status {
cursor: pointer;
position: fixed;
top: 10px;
right: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 28px;
padding: 8px;
border-radius: 8px;
color: var(--main-text-color);
z-index: 1;
transition: opacity 0.3s, background-color 0.3s, transform 0.3s;
&:hover {
backdrop-filter: blur(20px);
background-color: var(--main-background-light-color);
}
&:active {
transform: scale(0.95);
}
}
}
#loading {
color: var(--main-text-color);

View File

@ -0,0 +1,12 @@
<!-- 全局设置 -->
<template>
<n-tabs class="func" size="large" justify-content="space-evenly" animated>
<n-tab-pane name="link" tab="捷径"> 即将完善 </n-tab-pane>
<n-tab-pane name="note" tab="便签"> 即将完善 </n-tab-pane>
<n-tab-pane name="more" tab="还能有啥"> 还能有啥呢 😢 </n-tab-pane>
</n-tabs>
</template>
<script setup>
import { NTabs, NTabPane } from "naive-ui";
</script>

View File

@ -0,0 +1,67 @@
<template>
<div class="main-box" @click.stop>
<Transition name="fade" mode="out-in">
<AllBox v-if="status.siteStatus === 'box'" />
<AllSet v-else-if="status.siteStatus === 'set'" />
</Transition>
</div>
</template>
<script setup>
import { statusStore } from "@/stores";
import AllBox from "@/components/AllFunc/AllBox.vue";
import AllSet from "@/components/AllFunc/AllSet.vue";
const status = statusStore();
</script>
<style lang="scss" scoped>
.main-box {
position: absolute;
width: 80%;
height: 400px;
max-height: 400px;
max-width: 1200px;
background-color: var(--main-background-light-color);
backdrop-filter: blur(20px);
color: var(--main-text-color);
border-radius: 8px;
transition: opacity 0.3s, transform 0.3s, margin-top 0.3s;
z-index: 2;
:deep(.set-item) {
width: 100%;
border-radius: 8px;
margin-bottom: 12px;
border: none;
box-shadow: var(--main-box-shadow);
--n-color: var(--main-background-light-color);
.n-card__content {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
.name {
display: flex;
flex-direction: column;
.title {
font-size: 16px;
}
.tip {
font-size: 13px;
opacity: 0.8;
}
}
.set {
width: 200px;
@media (max-width: 768px) {
width: 140px;
min-width: 140px;
}
}
}
&:last-child {
margin-bottom: 0;
}
}
}
</style>

View File

@ -0,0 +1,104 @@
<!-- 全局设置 -->
<template>
<n-tabs class="set" size="large" justify-content="space-evenly" animated>
<n-tab-pane name="main" tab="基础设置">
<n-scrollbar style="max-height: 316px">
<n-card class="set-item">
<div class="name">
<span class="title">壁纸偏好</span>
<span class="tip">设置站点背景图片</span>
</div>
</n-card>
<n-card class="set-item">
<div class="name">
<span class="title">壁纸遮罩</span>
<span class="tip">壁纸周围是否显示暗色遮罩</span>
</div>
<n-switch v-model:value="showBackgroundGray" :round="false" />
</n-card>
<n-card class="set-item">
<div class="name">
<span class="title">搜索引擎</span>
<span class="tip">切换搜索引擎</span>
</div>
</n-card>
<n-card class="set-item">
<div class="name">
<span class="title">搜索建议</span>
<span class="tip">是否显示搜索建议</span>
</div>
<n-switch v-model:value="showSuggestions" :round="false" />
</n-card>
<n-card class="set-item">
<div class="name">
<span class="title">跳转方式</span>
<span class="tip">全站链接跳转方式</span>
</div>
<n-select
class="set"
v-model:value="urlJumpType"
:options="urlJumpTypeOptions"
/>
</n-card>
</n-scrollbar>
</n-tab-pane>
<n-tab-pane name="personalization" tab="个性调整">
<n-card class="set-item">
<div class="name">
<span class="title">时间显秒</span>
<span class="tip">是否在分钟后面显示秒数</span>
</div>
<n-switch v-model:value="showSeconds" :round="false" />
</n-card>
<n-card class="set-item">
<div class="name">
<span class="title">自动聚焦</span>
<span class="tip">打开网站时自动聚焦搜索框</span>
</div>
<n-switch v-model:value="autoFocus" :round="false" />
</n-card>
<n-card class="set-item">
<div class="name">
<span class="title">自动失焦</span>
<span class="tip">跳转搜索后搜索框自动失焦</span>
</div>
<n-switch v-model:value="autoInputBlur" :round="false" />
</n-card>
</n-tab-pane>
<n-tab-pane name="other" tab="其他设置"> 其他设置 </n-tab-pane>
</n-tabs>
</template>
<script setup>
import { NTabs, NTabPane, NCard, NSwitch, NSelect, NScrollbar } from "naive-ui";
import { storeToRefs } from "pinia";
import { setStore } from "@/stores";
const set = setStore();
const {
backgroundType,
showBackgroundGray,
searchEngine,
lastSearchEngine,
customEngine,
showCleanInput,
autoFocus,
autoInputBlur,
timeStyle,
showSeconds,
showSuggestions,
urlJumpType,
} = storeToRefs(set);
//
const urlJumpTypeOptions = [
{
label: "新页面打开",
value: "open",
},
{
label: "当前页打开",
value: "href",
},
];
</script>

View File

@ -67,8 +67,9 @@ const imgAnimationEnd = () => {
//
const imgLoadError = () => {
console.error("图片加载失败:", bgUrl.value);
bgUrl.value = `/background/bg${bgRandom}.jpg`;
console.error("图片加载失败:", bgUrl.value);
$message.error("壁纸加载失败,已临时切换回默认");
};
onMounted(() => {

View File

@ -13,5 +13,6 @@
width: 100%;
font-size: 14px;
color: var(--main-text-color);
z-index: 1;
}
</style>

View File

@ -3,6 +3,7 @@
<n-config-provider
:locale="zhCN"
:date-locale="dateZhCN"
:theme="darkTheme"
:theme-overrides="themeOverrides"
abstract
inline-theme-disabled
@ -23,6 +24,7 @@ import { defineComponent } from "vue";
import {
zhCN,
dateZhCN,
darkTheme,
NConfigProvider,
NDialogProvider,
NNotificationProvider,
@ -36,6 +38,10 @@ import {
const themeOverrides = {
common: {
fontFamily: "'HarmonyOS_Regular', sans-serif",
primaryColor: "#ffffff",
primaryColorHover: "#ffffff70",
primaryColorSuppl: "#ffffff30",
primaryColorPressed: "#ffffff30",
},
};

View File

@ -3,7 +3,7 @@
<div
v-if="status.siteStatus === 'focus'"
class="mask"
@click="closeSearchInput"
@click="closeSearchInput(false)"
/>
<div
ref="searchAllRef"
@ -29,12 +29,12 @@
title="请输入搜索内容"
autocomplete="false"
:placeholder="inputTip"
v-model="inputValue"
v-model="status.searchInputValue"
@focus="status.setSiteStatus('focus')"
@click.stop="status.setEngineChangeStatus(false)"
@keydown.stop="pressKeyboard"
/>
<div class="go" title="搜索" @click="toSearch(inputValue)">
<div class="go" title="搜索" @click="toSearch(status.searchInputValue)">
<SvgIcon iconName="icon-search" className="search" />
</div>
</div>
@ -43,7 +43,7 @@
<!-- 搜索建议 -->
<Suggestions
ref="suggestionsRef"
:keyWord="inputValue"
:keyWord="status.searchInputValue"
@toSearch="toSearch"
/>
</div>
@ -52,8 +52,8 @@
<script setup>
import { ref } from "vue";
import { statusStore, setStore } from "@/stores";
import SearchEngine from "@/components/SearchEngine.vue";
import Suggestions from "@/components/Suggestions.vue";
import SearchEngine from "@/components/SearchInput/SearchEngine.vue";
import Suggestions from "@/components/SearchInput/Suggestions.vue";
import defaultEngine from "@/assets/defaultEngine.json";
const set = setStore();
@ -66,17 +66,20 @@ const inputTip = import.meta.env.VITE_INPUT_TIP ?? "想要搜点什么";
const searchAllRef = ref(null);
const searchInputRef = ref(null);
const inputClickable = ref(true);
const inputValue = ref("");
//
const suggestionsRef = ref(null);
//
const closeSearchInput = () => {
status.setSiteStatus("normal");
const closeSearchInput = (check = false) => {
if (check && !set.autoInputBlur) {
status.setSiteStatus("focus");
} else {
status.setSearchInputValue("");
status.setSiteStatus("normal");
searchInputRef.value?.blur();
}
status.setEngineChangeStatus(false);
searchInputRef.value?.blur();
inputValue.value = "";
};
//
@ -84,9 +87,9 @@ const toSearch = (val, type = 1) => {
const searchValue = val?.trim();
//
const jumpLink = (url) => {
if (set.urlJumpType === "open") {
if (set.urlJumpType === "href") {
window.location.href = url;
} else if (set.urlJumpType === "href") {
} else if (set.urlJumpType === "open") {
window.open(url, "_blank");
}
};
@ -124,8 +127,11 @@ const toSearch = (val, type = 1) => {
default:
break;
}
closeSearchInput();
closeSearchInput(true);
} else {
if (status.siteStatus === "focus") {
$message.info("请输入搜索内容", { duration: 1500 });
}
status.setSiteStatus("focus");
searchInputRef.value?.focus();
}
@ -159,12 +165,13 @@ const changeEngine = () => {
<style lang="scss" scoped>
.search-input {
position: relative;
position: absolute;
display: flex;
flex-direction: row;
align-items: center;
max-width: 680px;
width: calc(100% - 60px);
transition: width 0.3s;
.mask {
position: fixed;
top: 0;
@ -186,7 +193,7 @@ const changeEngine = () => {
backdrop-filter: blur(10px);
opacity: 1;
animation: fade-up-in 0.7s cubic-bezier(0.37, 0.99, 0.36, 1);
transition: transform 0.3s, background-color 0.3s;
transition: transform 0.3s, background-color 0.3s, opacity 0.5s;
z-index: 1;
&.focus {
transform: translateY(-60px);

View File

@ -27,7 +27,7 @@
<div
v-if="searchKeywordType === 'text'"
class="s-result"
@click="toSearch(keyWord, 2)"
@click.stop="toSearch(keyWord, 2)"
>
<SvgIcon iconName="icon-translation-two" />
<span class="text">快捷翻译{{ keyWord }}</span>
@ -36,7 +36,7 @@
<div
v-if="searchKeywordType !== 'text'"
class="s-result"
@click="
@click.stop="
toSearch(searchKeyword, searchKeywordType === 'email' ? 3 : 4)
"
>
@ -69,7 +69,7 @@
v-for="item in searchSuggestionsData"
class="s-result"
:key="item"
@click="toSearch(item, 1)"
@click.stop="toSearch(item, 1)"
>
<SvgIcon iconName="icon-search" className="search" />
<span class="text">{{ item }}</span>
@ -214,12 +214,14 @@ const toSearch = (val, type = 1) => {
watch(
() => props.keyWord,
(val) => {
//
searchSuggestionsData.value = [];
//
searchKeywordType.value = identifyInput(val);
//
keywordsSearch(val);
if (set.showSuggestions) {
//
searchSuggestionsData.value = [];
//
searchKeywordType.value = identifyInput(val);
//
keywordsSearch(val);
}
}
);

View File

@ -1,13 +1,17 @@
<template>
<div
:class="
status.siteStatus !== 'normal' ? 'weather-time focus' : 'weather-time'
"
@click.stop
>
<div :class="['time', set.timeStyle]">
<div :class="`weather-time ${status.siteStatus}`" @click.stop>
<div
:class="['time', set.timeStyle]"
@click.stop="
status.setSiteStatus(
status.siteStatus !== 'normal' && status.siteStatus !== 'focus'
? 'normal'
: 'box'
)
"
>
<span class="hour">{{ timeData.hour ?? "00" }}</span>
<span class="separator">:</span>
<span class="separator" :key="set.showSeconds">:</span>
<span class="minute">{{ timeData.minute ?? "00" }}</span>
<template v-if="set.showSeconds">
<span class="separator">:</span>
@ -120,6 +124,10 @@ onBeforeUnmount(() => {
&.focus {
transform: translateY(-180px);
}
&.box,
&.set {
transform: translateY(-220px);
}
.time {
cursor: pointer;
font-size: 3rem;
@ -160,8 +168,7 @@ onBeforeUnmount(() => {
}
}
.weather {
margin-top: 6px;
opacity: 0.8;
opacity: 0.7;
font-size: 1rem;
text-shadow: var(--main-text-shadow);
.temperature {

View File

@ -4,16 +4,14 @@ import { createPinia } from "pinia";
import piniaPluginPersistedstate from "pinia-plugin-persistedstate";
// IconFont
import SvgIcon from "@/components/SvgIcon.vue";
import "@/utils/iconfont.js";
// Notification
import Notification from "@/components/Notification.vue";
// 主组件
import App from "@/App.vue";
// 全局样式
import "@/style/global.scss";
// 根组件
const app = createApp(App);
// Pinia

View File

@ -16,6 +16,8 @@ const useSetDataStore = defineStore("setData", {
showCleanInput: true,
// 搜索框自动 focus
autoFocus: false,
// 搜索后搜索框自动失焦
autoInputBlur: true,
// 时间样式
timeStyle: "one",
// 是否显秒
@ -23,8 +25,8 @@ const useSetDataStore = defineStore("setData", {
// 是否显示搜索建议
showSuggestions: true,
// 跳转方式
// open 当前页面 / href 新标签页
urlJumpType: "href",
// open 新标签页 / href 当前页面
urlJumpType: "open",
};
},
actions: {

View File

@ -10,6 +10,8 @@ const useStatusDataStore = defineStore("statusData", {
siteStatus: "normal",
// 切换搜索引擎
engineChangeStatus: false,
// 搜索框文本
searchInputValue: "",
};
},
getters: {},
@ -19,10 +21,14 @@ const useStatusDataStore = defineStore("statusData", {
},
setSiteStatus(value) {
this.siteStatus = value;
this.searchInputValue = "";
},
setEngineChangeStatus(value) {
this.engineChangeStatus = value;
},
setSearchInputValue(value) {
this.searchInputValue = value;
},
},
});

View File

@ -8,6 +8,7 @@
--main-background-hover-color: #ffffff70;
--main-input-hover-color: #ffffff;
--main-notification-background-color: #00000030;
--main-box-shadow: 0px 0px 10px 0px #00000020;
--main-text-shadow: 0px 0px 8px #00000066;
}
@ -49,10 +50,42 @@ body {
}
}
// NTabs
.n-tabs {
height: 100%;
--n-bar-color: var(--main-text-color) !important;
--n-tab-text-color-active: var(--main-text-color) !important;
--n-tab-text-color-hover: var(--main-text-color) !important;
.n-tabs-nav {
height: 44px;
}
.n-tabs-pane-wrapper {
height: 100%;
.n-tab-pane {
padding: 20px;
box-sizing: border-box;
}
}
}
// NSwitch
.n-switch {
--n-rail-color: var(--main-background-light-color) !important;
--n-rail-color-active: var(--main-background-hover-color) !important;
--n-box-shadow-focus: var(--main-box-shadow) !important;
}
// NScrollbar
.n-scrollbar {
.n-scrollbar-rail {
right: 0 !important;
}
}
// Transition 动画
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
transition: opacity 0.25s ease-in-out;
}
.fade-enter-from,

File diff suppressed because one or more lines are too long

View File

@ -11,6 +11,8 @@ const identifyInput = (input) => {
*/
const urlRegex =
/^(?:(?:(?:https?|ftp):\/\/)?(?:www\.)?)?([a-zA-Z0-9.-]+(?:\.[a-zA-Z]{2,})+)(?:\/[^\s]*)?(?:\?[^#\s]*)?(?:#[^\s]*)?$/;
const ipv4Regex =
/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
/**
* 邮箱正则
@ -19,7 +21,7 @@ const identifyInput = (input) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
// 判断是否为网址
if (urlRegex.test(input)) return "url";
if (urlRegex.test(input) || ipv4Regex.test(input)) return "url";
// 判断是否为邮件地址
if (emailRegex.test(input)) return "email";

View File

@ -2,6 +2,7 @@ import { defineConfig } from "vite";
import { VitePWA } from "vite-plugin-pwa";
import vue from "@vitejs/plugin-vue";
import path from "path";
import viteCompression from "vite-plugin-compression";
// https://vitejs.dev/config/
export default defineConfig({
@ -48,6 +49,8 @@ export default defineConfig({
],
},
}),
// viteCompression
viteCompression(),
],
server: {
host: "0.0.0.0",