Skip to content

Commit

Permalink
feat: 侧边栏记录
Browse files Browse the repository at this point in the history
  • Loading branch information
Chanzhaoyu committed Feb 14, 2023
1 parent b6e5c59 commit b03f804
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 36 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
"@commitlint/cli": "^17.4.3",
"@commitlint/config-conventional": "^17.4.3",
"@iconify/vue": "^4.1.0",
"@types/crypto-js": "^4.1.1",
"@types/node": "^18.13.0",
"@vitejs/plugin-vue": "^4.0.0",
"autoprefixer": "^10.4.13",
"axios": "^1.3.2",
"crypto-js": "^4.1.1",
"eslint": "^8.34.0",
"husky": "^8.0.3",
"lint-staged": "^13.1.1",
Expand Down
12 changes: 12 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions src/components/business/Chat/layout/sider/Footer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import { HoverButton, SvgIcon, UserAvatar } from '@/components/common'
</script>

<template>
<footer class="flex items-center justify-between p-4 overflow-hidden border-t">
<UserAvatar />

<footer class="flex items-center justify-between min-w-0 p-4 overflow-hidden border-t h-[70px]">
<UserAvatar class="flex-1" />
<HoverButton tooltip="Setting">
<span class="text-xl text-[#4f555e]">
<SvgIcon icon="ri:settings-4-line" />
Expand Down
30 changes: 5 additions & 25 deletions src/components/business/Chat/layout/sider/index.vue
Original file line number Diff line number Diff line change
@@ -1,42 +1,22 @@
<script setup lang='ts'>
import { ref, watch } from 'vue'
import { ref } from 'vue'
import { NButton, NLayoutSider, useMessage } from 'naive-ui'
import List from './List.vue'
import Footer from './Footer.vue'
import { useAppStore } from '@/store'
interface Props {
collapsed?: boolean
}
interface Emit {
(e: 'update:collapsed', value: boolean): void
}
const props = withDefaults(defineProps<Props>(), {
collapsed: false,
})
const emit = defineEmits<Emit>()
const appStore = useAppStore()
const ms = useMessage()
const collapsed = ref(props.collapsed)
watch(
() => props.collapsed,
(value: boolean) => {
collapsed.value = value
},
{ immediate: true },
)
const collapsed = ref(appStore.siderCollapsed ?? false)
function handleAdd() {
ms.info('Coming soon...')
}
function handleCollapsed() {
collapsed.value = !collapsed.value
emit('update:collapsed', collapsed.value)
appStore.setSiderCollapsed(collapsed.value)
}
</script>

Expand Down
18 changes: 18 additions & 0 deletions src/store/modules/app/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { ls } from '@/utils/storage'

export interface AppState {
siderCollapsed: boolean
}

export function defaultSetting() {
return { siderCollapsed: false }
}

export function getAppSetting() {
const localSetting: AppState = ls.get('appSetting')
return localSetting ?? defaultSetting()
}

export function setAppSetting(setting: AppState) {
ls.set('appSetting', setting)
}
13 changes: 5 additions & 8 deletions src/store/modules/app/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import { defineStore } from 'pinia'

interface AppState {
siderCollapsed: boolean
}
import type { AppState } from './helper'
import { getAppSetting, setAppSetting } from './helper'

export const useAppStore = defineStore('app-store', {
state: (): AppState => ({
siderCollapsed: false,
}),
state: (): AppState => getAppSetting(),
actions: {
setSiderCollapsed(collapsed: boolean) {
this.siderCollapsed = collapsed
setAppSetting(this.$state)
},
toggleSiderCollapse() {
this.siderCollapsed = !this.siderCollapsed
this.setSiderCollapsed(!this.siderCollapsed)
},
},
})
18 changes: 18 additions & 0 deletions src/utils/crypto/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import CryptoJS from 'crypto-js'

const CryptoSecret = '__CRYPTO_SECRET__'

export function enCrypto(data: any) {
const str = JSON.stringify(data)
return CryptoJS.AES.encrypt(str, CryptoSecret).toString()
}

export function deCrypto(data: string) {
const bytes = CryptoJS.AES.decrypt(data, CryptoSecret)
const str = bytes.toString(CryptoJS.enc.Utf8)

if (str)
return JSON.parse(str)

return null
}
55 changes: 55 additions & 0 deletions src/utils/is/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
export function isNumber<T extends number>(value: T | unknown): value is number {
return Object.prototype.toString.call(value) === '[object Number]'
}

export function isString<T extends string>(value: T | unknown): value is string {
return Object.prototype.toString.call(value) === '[object String]'
}

export function isBoolean<T extends boolean>(value: T | unknown): value is boolean {
return Object.prototype.toString.call(value) === '[object Boolean]'
}

export function isNull<T extends null>(value: T | unknown): value is null {
return Object.prototype.toString.call(value) === '[object Null]'
}

export function isUndefine<T extends undefined>(value: T | unknown): value is undefined {
return Object.prototype.toString.call(value) === '[object Undefined]'
}

export function isObject<T extends object>(value: T | unknown): value is object {
return Object.prototype.toString.call(value) === '[object Object]'
}

export function isArray<T extends any[]>(value: T | unknown): value is T {
return Object.prototype.toString.call(value) === '[object Array]'
}

export function isFunction<T extends (...args: any[]) => any | void | never>(value: T | unknown): value is T {
return Object.prototype.toString.call(value) === '[object Function]'
}

export function isDate<T extends Date>(value: T | unknown): value is T {
return Object.prototype.toString.call(value) === '[object Date]'
}

export function isRegExp<T extends RegExp>(value: T | unknown): value is T {
return Object.prototype.toString.call(value) === '[object RegExp]'
}

export function isPromise<T extends Promise<any>>(value: T | unknown): value is T {
return Object.prototype.toString.call(value) === '[object Promise]'
}

export function isSet<T extends Set<any>>(value: T | unknown): value is T {
return Object.prototype.toString.call(value) === '[object Set]'
}

export function isMap<T extends Map<any, any>>(value: T | unknown): value is T {
return Object.prototype.toString.call(value) === '[object Map]'
}

export function isFile<T extends File>(value: T | unknown): value is T {
return Object.prototype.toString.call(value) === '[object File]'
}
1 change: 1 addition & 0 deletions src/utils/storage/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './local'
59 changes: 59 additions & 0 deletions src/utils/storage/local.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { deCrypto, enCrypto } from '../crypto'

interface StorageData<T = any> {
value: T
expire: number | null
}

function createLocalStorage() {
const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7 // 7 days

function set<T = any>(key: string, value: T, expire: number | null = DEFAULT_CACHE_TIME) {
const storageData: StorageData<T> = {
value,
expire: expire !== null ? new Date().getTime() + expire * 1000 : null,
}
const json = enCrypto(storageData)
window.localStorage.setItem(key, json)
}

function get(key: string) {
const json = window.localStorage.getItem(key)
if (json) {
let storageData: StorageData | null = null

try {
storageData = deCrypto(json)
}
catch {
// Prevent failure
}

if (storageData) {
const { value, expire } = storageData
if (expire === null || expire >= Date.now())
return value
}

remove(key)
return null
}
}

function remove(key: string) {
window.localStorage.removeItem(key)
}

function clear() {
window.localStorage.clear()
}

return {
set,
get,
remove,
clear,
}
}

export const ls = createLocalStorage()

0 comments on commit b03f804

Please sign in to comment.