feat: 完善捷径

This commit is contained in:
imsyy 2023-08-18 18:25:48 +08:00
parent 8b338d8e14
commit dc17328a8f
10 changed files with 236 additions and 105 deletions

View File

@ -1,5 +1,5 @@
<!doctype html>
<html lang="zh-CN">
<html lang="zh-CN" theme="light">
<head>
<meta charset="UTF-8" />

File diff suppressed because one or more lines are too long

View File

@ -9,6 +9,7 @@
tabindex="0"
id="main"
:class="`main-${status.siteStatus}`"
:style="{ pointerEvents: mainClickable ? 'auto' : 'none' }"
@click="status.setSiteStatus('normal')"
@contextmenu="mainContextmenu"
@keydown="mainPressKeyboard"
@ -67,8 +68,8 @@
</template>
<script setup>
import { nextTick } from "vue";
import { statusStore } from "@/stores";
import { onMounted, nextTick, watch, ref } from "vue";
import { statusStore, setStore } from "@/stores";
import { getGreeting } from "@/utils/timeTools";
import Provider from "@/components/Provider.vue";
import Cover from "@/components/Cover.vue";
@ -77,7 +78,9 @@ import SearchInp from "@/components/SearchInput/SearchInp.vue";
import AllFunc from "@/components/AllFunc/AllFunc.vue";
import Footer from "@/components/Footer.vue";
const set = setStore();
const status = statusStore();
const mainClickable = ref(false);
//
const welcomeText = import.meta.env.VITE_WELCOME_TEXT ?? "欢迎访问本站";
@ -91,6 +94,7 @@ const mainContextmenu = (event) => {
//
const loadComplete = () => {
nextTick().then(() => {
mainClickable.value = true;
$message.info(getGreeting() + "" + welcomeText, {
showIcon: false,
duration: 3000,
@ -109,6 +113,23 @@ const mainPressKeyboard = (event) => {
mainInput?.focus();
}
};
//
const changeThemeType = (val) => {
const htmlElement = document.querySelector("html");
const themeType = val === "light" ? "light" : "dark";
htmlElement.setAttribute("theme", themeType);
};
//
watch(
() => set.themeType,
(val) => changeThemeType(val)
);
onMounted(() => {
changeThemeType(set.themeType);
});
</script>
<style lang="scss" scoped>

View File

@ -1,34 +1,42 @@
[
{
"id": 0,
"name": "翻译",
"url": "@translation"
"url": "https://www.deepl.com/zh/translator"
},
{
"id": 1,
"name": "地图",
"url": "@map"
"url": "https://ditu.amap.com/"
},
{
"id": 2,
"name": "图片",
"url": "@picture"
"url": "https://www.pexels.com/zh-cn/"
},
{
"id": 3,
"name": "云盘",
"url": "@cloud"
"url": "https://www.aliyundrive.com/drive/"
},
{
"name": "设置",
"url": "@setting"
"id": 4,
"name": "Cloudflare",
"url": "https://dash.cloudflare.com/"
},
{
"id": 5,
"name": "邮箱",
"url": "https://mail.qq.com/"
},
{
"name": "哔哩哔哩",
"url": "https://mail.qq.com/"
"id": 6,
"name": "GitHub",
"url": "https://github.com/"
},
{
"name": "GitHub",
"url": "https://mail.qq.com/"
"id": 7,
"name": "哔哩哔哩",
"url": "https://www.bilibili.com/"
}
]

View File

@ -3,7 +3,18 @@
<n-tabs class="set" size="large" justify-content="space-evenly" animated>
<n-tab-pane name="main" tab="基础设置">
<n-scrollbar class="scrollbar">
<n-h6 prefix="bar"> 壁纸 </n-h6>
<n-h6 prefix="bar"> 主题与壁纸 </n-h6>
<n-card class="set-item">
<div class="name">
<span class="title">主题类别</span>
<span class="tip">切换全站主题类别</span>
</div>
<n-select
class="set"
v-model:value="themeType"
:options="themeTypeOptions"
/>
</n-card>
<n-card
class="set-item cover"
:content-style="{
@ -280,6 +291,7 @@ import identifyInput from "@/utils/identifyInput";
const set = setStore();
const status = statusStore();
const {
themeType,
backgroundType,
backgroundCustom,
showBackgroundGray,
@ -308,6 +320,18 @@ const backgroundTypeArr = [
{ name: "随机动漫", tip: "随机二次元图,随机更换" },
];
//
const themeTypeOptions = [
{
label: "浅色模式",
value: "light",
},
{
label: "深色模式",
value: "dark",
},
];
//
const changeBackground = (type, reset = false) => {
if (reset) {
@ -321,7 +345,7 @@ const changeBackground = (type, reset = false) => {
$message.info("已恢复为默认壁纸,刷新后生效");
},
});
return;
return true;
}
backgroundType.value = type;
$message.success(`已切换为${backgroundTypeArr[type].name},刷新后生效`);

View File

@ -15,7 +15,7 @@
:key="item"
class="shortcut-item"
@contextmenu="shortCutContextmenu($event, item)"
@click="shortCutJump"
@click="shortCutJump(item.url)"
>
<span class="name">{{ item.name }}</span>
</n-grid-item>
@ -47,7 +47,7 @@
<!-- 添加捷径 -->
<n-modal
preset="card"
v-model:show="addShortcutModal"
v-model:show="addShortcutModalShow"
:title="`${addShortcutModalType ? '编辑' : '添加'}捷径`"
:bordered="false"
@mask-click="addShortcutClose"
@ -58,6 +58,15 @@
:model="addShortcutValue"
:label-width="80"
>
<n-form-item label="ID" path="id">
<n-input-number
disabled
placeholder="请输入ID"
v-model:value="addShortcutValue.id"
style="width: 100%"
:show-button="false"
/>
</n-form-item>
<n-form-item label="捷径名称" path="name">
<n-input
clearable
@ -78,7 +87,7 @@
<template #footer>
<n-space justify="end">
<n-button strong secondary @click="addShortcutClose"> 取消 </n-button>
<n-button strong secondary @click="addShortcutBtn">
<n-button strong secondary @click="addOrEditShortcuts">
{{ addShortcutModalType ? "编辑" : "添加" }}
</n-button>
</n-space>
@ -88,6 +97,7 @@
<n-dropdown
placement="bottom-start"
trigger="manual"
size="large"
:x="shortCutDropdownX"
:y="shortCutDropdownY"
:options="shortCutDropdownOptions"
@ -102,7 +112,7 @@
</template>
<script setup>
import { ref, nextTick } from "vue";
import { ref, nextTick, h } from "vue";
import {
NButton,
NScrollbar,
@ -113,24 +123,41 @@ import {
NForm,
NFormItem,
NInput,
NInputNumber,
NDropdown,
} from "naive-ui";
import { storeToRefs } from "pinia";
import { siteStore } from "@/stores";
import { siteStore, setStore } from "@/stores";
import SvgIcon from "@/components/SvgIcon.vue";
import identifyInput from "@/utils/identifyInput";
const set = setStore();
const site = siteStore();
const { shortcutData } = storeToRefs(site);
//
const renderIcon = (icon) => {
return () => {
return h(SvgIcon, { iconName: `icon-${icon}` }, null);
};
};
//
const addShortcutRef = ref(null);
const addShortcutModal = ref(false);
const addShortcutModalShow = ref(false);
const addShortcutModalType = ref(false); // false / true
const addShortcutValue = ref({
id: null,
name: "",
url: "",
});
const addShortcutRules = {
id: {
required: true,
type: "number",
message: "请输入合法 ID",
trigger: ["input", "blur"],
},
name: {
required: true,
message: "请输入名称",
@ -150,61 +177,6 @@ const addShortcutRules = {
},
};
//
const addShortcutClose = () => {
addShortcutModal.value = false;
addShortcutValue.value = {
name: "",
url: "",
};
};
//
const addShortcutModalOpen = () => {
addShortcutValue.value = {
name: "",
url: "",
};
addShortcutModalType.value = false;
addShortcutModal.value = true;
};
//
const addShortcutBtn = () => {
addShortcutRef.value?.validate((errors) => {
if (!errors) {
//
if (!addShortcutModalType.value) {
//
const isDuplicate = shortcutData.value[0]
? shortcutData.value?.some((item) => {
return (
item.name === addShortcutValue.value.name ||
item.url === addShortcutValue.value.url
);
})
: false;
if (isDuplicate) {
$message.error("新增名称或链接与已有捷径重复");
} else {
shortcutData.value.push({
name: addShortcutValue.value.name,
url: addShortcutValue.value.url,
});
$message.success("添加成功");
addShortcutClose();
}
}
//
else {
$message.info("即将支持");
}
} else {
$message.error("请检查您的输入");
}
});
};
//
const shortCutDropdownX = ref(0);
const shortCutDropdownY = ref(0);
@ -213,20 +185,115 @@ const shortCutDropdownOptions = [
{
label: "编辑",
key: "edit",
icon: renderIcon("edit"),
},
{
label: "删除",
key: "delete",
icon: renderIcon("delete-1"),
},
];
//
const addShortcutClose = () => {
addShortcutModalShow.value = false;
addShortcutValue.value = {
id: null,
name: "",
url: "",
};
};
//
const addShortcutModalOpen = () => {
// ID
const shortcutMaxID = shortcutData.value.reduce((max, item) => {
return item.id > max ? item.id : max;
}, -1);
//
addShortcutValue.value = {
id: shortcutMaxID + 1,
name: "",
url: "",
};
addShortcutModalType.value = false;
addShortcutModalShow.value = true;
};
//
const addOrEditShortcuts = () => {
addShortcutRef.value?.validate((errors) => {
if (errors) {
$message.error("请检查您的输入");
return false;
}
//
if (!addShortcutModalType.value) {
//
const isDuplicate = shortcutData.value?.some(
(item) =>
item.name === addShortcutValue.value.name ||
item.url === addShortcutValue.value.url
);
if (isDuplicate) {
$message.error("新增名称或链接与已有捷径重复");
return false;
}
shortcutData.value.push({
id: addShortcutValue.value.id,
name: addShortcutValue.value.name,
url: addShortcutValue.value.url,
});
$message.success("捷径添加成功");
addShortcutClose();
return true;
} else {
//
const index = shortcutData.value.findIndex(
(item) => item.id === addShortcutValue.value.id
);
if (index === -1) {
$message.error("捷径中不存在该项,请重试");
return false;
}
shortcutData.value[index].name = addShortcutValue.value.name;
shortcutData.value[index].url = addShortcutValue.value.url;
$message.success("捷径编辑成功");
addShortcutClose();
return true;
}
});
};
//
const delShortcuts = () => {
const deleteId = addShortcutValue.value.id;
if (typeof deleteId === "number") {
const indexToRemove = shortcutData.value.findIndex(
(item) => item.id === deleteId
);
if (indexToRemove !== -1) {
shortcutData.value.splice(indexToRemove, 1);
// id
for (let i = indexToRemove; i < shortcutData.value.length; i++) {
shortcutData.value[i].id = i;
}
$message.success("捷径删除成功");
return true;
}
$message.error("捷径删除失败,请重试");
} else {
$message.error("捷径删除失败,请重试");
}
};
//
const shortCutContextmenu = (e, data) => {
e.preventDefault();
shortCutDropdownShow.value = false;
//
const { name, url } = data;
addShortcutValue.value = { name, url };
const { id, name, url } = data;
addShortcutValue.value = { id, name, url };
nextTick().then(() => {
shortCutDropdownShow.value = true;
shortCutDropdownX.value = e.clientX;
@ -241,10 +308,18 @@ const shortCutDropdownSelect = (key) => {
switch (key) {
case "edit":
addShortcutModalType.value = true;
addShortcutModal.value = true;
addShortcutModalShow.value = true;
break;
case "delete":
$message.info("即将支持");
$dialog.warning({
title: "删除捷径",
content: `确认删除 ${addShortcutValue.value.name} 捷径?此操作将无法恢复!`,
positiveText: "删除",
negativeText: "取消",
onPositiveClick: () => {
delShortcuts();
},
});
break;
default:
break;
@ -252,8 +327,14 @@ const shortCutDropdownSelect = (key) => {
};
//
const shortCutJump = () => {
$message.info("即将支持");
const shortCutJump = (url) => {
const urlRegex = /^(https?:\/\/)/i;
const urlFormat = urlRegex.test(url) ? url : `//${url}`;
if (set.urlJumpType === "href") {
window.location.href = urlFormat;
} else if (set.urlJumpType === "open") {
window.open(urlFormat, "_blank");
}
};
</script>
@ -276,10 +357,10 @@ const shortCutJump = () => {
font-size: 16px;
transition: background-color 0.3s, box-shadow 0.3s;
.i-icon {
width: 0rem;
opacity: 0;
font-size: 0px;
transition: width 0.3s, opacity 0.3s, font-size 0.3s, margin-right 0.3s;
width: 1rem;
margin-right: 6px;
font-size: 20px;
opacity: 1;
}
.name {
overflow: hidden;
@ -289,12 +370,6 @@ const shortCutJump = () => {
&:hover {
background-color: var(--main-background-hover-color);
box-shadow: 0 0 0px 2px var(--main-background-hover-color);
.i-icon {
width: 1rem;
margin-right: 6px;
font-size: 20px;
opacity: 1;
}
}
&:active {
box-shadow: none;

View File

@ -20,13 +20,7 @@
"
/>
<!-- 主搜索框 -->
<div
class="all"
ref="searchAllRef"
:style="{ pointerEvents: inputClickable ? 'none' : 'auto' }"
@animationstart="inputClickable = true"
@animationend="inputAnimationEnd"
>
<div class="all" ref="searchAllRef" @animationend="inputAnimationEnd">
<div class="engine" title="切换搜索引擎" @click="changeEngine">
<Transition name="fade" mode="out-in">
<SvgIcon
@ -84,7 +78,6 @@ const inputTip = import.meta.env.VITE_INPUT_TIP ?? "想要搜点什么";
//
const searchAllRef = ref(null);
const searchInputRef = ref(null);
const inputClickable = ref(true);
//
const suggestionsRef = ref(null);
@ -163,7 +156,6 @@ const toSearch = (val, type = 1) => {
//
const inputAnimationEnd = () => {
console.log("搜索框动画结束");
inputClickable.value = false;
// focus
if (set.autoFocus) {
status.setSiteStatus("focus");

View File

@ -3,6 +3,8 @@ import { defineStore } from "pinia";
const useSetDataStore = defineStore("setData", {
state: () => {
return {
// 主题类别
themeType: "light",
// 壁纸类别
// 0 本地 / 1 必应 / 2 随机风景 / 3 随机动漫 / 4 自定义
backgroundType: 2,

View File

@ -12,6 +12,12 @@
--main-text-shadow: 0px 0px 8px #00000066;
}
[theme="dark"] {
--main-text-color: #efefef;
--main-background-light-color: #00000030;
--main-background-hover-color: #00000040;
}
* {
margin: 0;
padding: 0;
@ -145,6 +151,7 @@ body {
.n-dropdown {
--n-border-radius: 8px !important;
--n-color: var(--main-background-light-color) !important;
--n-option-color-hover: var(--main-background-hover-color) !important;
backdrop-filter: blur(10px);
}

View File

@ -68,15 +68,17 @@ export const getGreeting = () => {
const currentTime = new Date();
const currentHour = currentTime.getHours();
let greeting = "";
if (currentHour >= 5 && currentHour < 9) {
if (currentHour >= 6 && currentHour < 9) {
greeting = "早上好";
} else if (currentHour >= 9 && currentHour < 12) {
greeting = "上午好";
} else if (currentHour >= 12 && currentHour < 18) {
greeting = "下午好";
} else if (currentHour >= 18 && currentHour < 24) {
} else if (currentHour >= 18 && currentHour < 20) {
greeting = "傍晚好";
} else if (currentHour >= 20 && currentHour < 24) {
greeting = "晚上好";
} else if (currentHour >= 0 && currentHour < 5) {
} else if (currentHour >= 4 && currentHour < 6) {
greeting = "凌晨好";
} else {
greeting = "夜深了";