Skip to content

Commit

Permalink
feat: activity
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei committed Jul 1, 2023
1 parent 22f4020 commit 7dc7d7d
Show file tree
Hide file tree
Showing 32 changed files with 201 additions and 23 deletions.
Binary file added public/apps/arc.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 public/apps/chrome.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 public/apps/chrome_canary.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 public/apps/code.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 public/apps/discord.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 public/apps/figma.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 public/apps/finder.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 public/apps/iterm2.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 public/apps/linear.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 public/apps/mail.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 public/apps/music.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 public/apps/netease.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 public/apps/qq.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 public/apps/qq_music.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 public/apps/safari.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 public/apps/slack.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 public/apps/telegram.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 public/apps/webstorm.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 public/apps/wechat.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 public/apps/xcode.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src/app/common/deleted/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Link from 'next/link'

import { NormalContainer } from '~/components/layout/container/Normal'
import { StyledButton } from '~/components/ui/button'

export default async function PageDeleted() {
return (
<NormalContainer>
<div className="mt-[250px] flex h-full flex-col items-center justify-center">
<h1 className="text-4xl font-bold">此页面已被删除</h1>

<StyledButton className="mt-8">
<Link href="/">返回首页</Link>
</StyledButton>
</div>
</NormalContainer>
)
}
12 changes: 7 additions & 5 deletions src/app/posts/(post-detail)/[category]/[slug]/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Loading } from '~/components/ui/loading'

export default () => (
<div className="absolute inset-0 flex h-[120px] center">
<Loading useDefaultLoadingText />
</div>
)
export default function Load() {
return (
<div className="flex h-[240px] w-full center">
<Loading useDefaultLoadingText />
</div>
)
}
2 changes: 2 additions & 0 deletions src/components/layout/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { memo } from 'react'
import { OnlyMobile } from '~/components/ui/viewport/OnlyMobile'
import { clsxm } from '~/utils/helper'

import { Activity } from './internal/Activity'
import { AnimatedLogo } from './internal/AnimatedLogo'
import { BluredBackground } from './internal/BluredBackground'
import styles from './internal/grid.module.css'
Expand Down Expand Up @@ -41,6 +42,7 @@ const MemoedHeader = memo(() => {

<HeaderLogoArea>
<AnimatedLogo />
<Activity />
{/* <SiteOwnerAvatar className="absolute bottom-[10px] right-[2px] hidden lg:inline-block" /> */}
<OnlyMobile>
<HeaderMeta />
Expand Down
86 changes: 86 additions & 0 deletions src/components/layout/header/internal/Activity.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use client'

import { useQuery } from '@tanstack/react-query'
import React, { useState } from 'react'
import { m } from 'framer-motion'
import Image from 'next/image'
import type { RequestError } from '@mx-space/api-client'

import { apiClient } from '~/utils/request'

// autocorrect: false
const appLabels: { [app: string]: string } = {
Slack: 'slack',
Arc: 'arc',
Code: 'code',
WebStorm: 'webstorm',
Linear: 'linear',
Figma: 'figma',
Telegram: 'telegram',
WeChat: 'wechat',
Discord: 'discord',
Mail: 'mail',
Safari: 'safari',
Music: 'music',
Finder: 'finder',
Messages: 'messages',
QQ: 'qq',
Chrome: 'chrome',
'Chrome Canary': 'chrome_canary',
QQ音乐: 'qq_music',
NeteaseMusic: 'netease',
iTerm2: 'iterm2',
Xcode: 'xcode',
}
// autocorrect: true
export function Activity() {
const [isEnabled, setIsEnabled] = useState(true)

const { data: processName } = useQuery(
['activity'],
async () => {
return await apiClient.proxy.fn.ps.update
.post<string>()
.catch((err: RequestError) => {
err.status === 404 && setIsEnabled(false)
return ''
})
},
{
refetchInterval: 5000,
retry: false,
enabled: isEnabled,
},
)

if (!processName) {
return null
}
if (!appLabels[processName]) {
console.log('Not collected process name: ', processName)
return null
}

return (
<div className="pointer-events-auto relative bottom-0 right-[-25px] top-0 flex items-center md:absolute">
<m.div
className="absolute left-1 top-1 h-6 w-6 select-none rounded-[6px] bg-zinc-500/10 dark:bg-zinc-200/10"
animate={{ opacity: [0, 0.65, 0], scale: [1, 1.4, 1] }}
transition={{
duration: 1.5,
repeat: Infinity,
}}
/>
<Image
width={32}
height={32}
src={`/apps/${appLabels[processName]}.png`}
alt={processName}
priority
fetchPriority="high"
unoptimized
className="pointer-events-none select-none"
/>
</div>
)
}
1 change: 1 addition & 0 deletions src/components/layout/header/internal/AnimatedLogo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const AnimatedLogo = () => {
<AnimatePresence>
{!shouldShowMeta && (
<m.div
layout
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
Expand Down
9 changes: 6 additions & 3 deletions src/components/layout/header/internal/HeaderContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ const AnimatedMenu: Component = ({ children }) => {

const ForDesktop: Component<{
shouldHideNavBg?: boolean
}> = ({ className, shouldHideNavBg }) => {
animatedIcon?: boolean
}> = ({ className, shouldHideNavBg, animatedIcon = true }) => {
const mouseX = useMotionValue(0)
const mouseY = useMotionValue(0)
const radius = useMotionValue(0)
Expand Down Expand Up @@ -130,6 +131,7 @@ const ForDesktop: Component<{
section.subMenu?.findIndex((item) => item.path === pathname) || -1
return (
<HeaderMenuItem
iconLayout={animatedIcon}
section={section}
key={section.path}
subItemActive={section.subMenu?.[subItemActive]}
Expand All @@ -151,7 +153,8 @@ const HeaderMenuItem = memo<{
section: IHeaderMenu
isActive: boolean
subItemActive?: IHeaderMenu
}>(({ section, isActive, subItemActive }) => {
iconLayout?: boolean
}>(({ section, isActive, subItemActive, iconLayout }) => {
const href = section.path

return (
Expand All @@ -164,7 +167,7 @@ const HeaderMenuItem = memo<{
<span className="relative flex items-center">
{isActive && (
<m.span
layoutId="header-menu-icon"
layoutId={iconLayout ? 'header-menu-icon' : undefined}
className={clsxm('mr-2 flex items-center')}
>
{subItemActive?.icon ?? section.icon}
Expand Down
2 changes: 1 addition & 1 deletion src/components/layout/header/internal/SiteOwnerAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const SiteOwnerAvatar: Component = ({ className }) => {
className,
)}
>
<Image src={avatar} alt="Site Owner Avatar" width={25} height={25} />
<Image src={avatar} alt="Site Owner Avatar" width={40} height={40} />
</div>
)
}
13 changes: 5 additions & 8 deletions src/lib/route-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export enum Routes {

Projects = '/projects',
Project = '/projects/',

PageDeletd = '/common/deleted',
}

type Noop = never
Expand Down Expand Up @@ -75,12 +77,12 @@ export type RouteParams<T extends Routes> = T extends Routes.Home
? OnlySlug
: T extends Routes.Project
? OnlyId
: never
: {}

export const routeBuilder = <T extends Routes>(
export function routeBuilder<T extends Routes>(
route: T,
params: RouteParams<typeof route>,
) => {
) {
let href: string = route
switch (route) {
case Routes.Note: {
Expand Down Expand Up @@ -123,11 +125,6 @@ export const routeBuilder = <T extends Routes>(
href += p.id
break
}
case Routes.NoteTopics:
case Routes.Notes:
case Routes.Login: {
break
}
}
return href
}
8 changes: 7 additions & 1 deletion src/providers/root/socket-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
'use client'

import { useEffect } from 'react'
import { useEffect, useRef } from 'react'
import { useRouter } from 'next/navigation'

export const SocketContainer: Component = () => {
const connectOnce = useRef(false)
const router = useRouter()
useEffect(() => {
if (connectOnce.current) return
import('~/socket').then((module) => {
const { socketClient } = module
connectOnce.current = true
socketClient.setRouter(router)
socketClient.initIO()
})
}, [])
Expand Down
62 changes: 59 additions & 3 deletions src/socket/handler.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
import type { NoteModel } from '@mx-space/api-client'
import type { EventTypes } from '~/types/events'
import type { NoteModel, PostModel } from '@mx-space/api-client'
import type { AppRouterInstance } from 'next/dist/shared/lib/app-router-context'

import { setOnlineCount } from '~/atoms'
import { routeBuilder, Routes } from '~/lib/route-builder'
import { toast } from '~/lib/toast'
import {
getCurrentNoteData,
setCurrentNoteData,
} from '~/providers/note/CurrentNoteDataProvider'
import {
getCurrentPageData,
setCurrentPageData,
} from '~/providers/page/CurrentPageDataProvider'
import {
getCurrentPostData,
setCurrentPostData,
} from '~/providers/post/CurrentPostDataProvider'
import { EventTypes } from '~/types/events'
import { isDev } from '~/utils/env'

export const eventHandler = (type: EventTypes, data: any) => {
export const eventHandler = (
type: EventTypes,
data: any,
router: AppRouterInstance,
) => {
switch (type) {
case 'VISITOR_ONLINE':
case 'VISITOR_OFFLINE': {
Expand All @@ -18,6 +32,28 @@ export const eventHandler = (type: EventTypes, data: any) => {
break
}

case EventTypes.POST_UPDATE: {
const post = data as PostModel
if (getCurrentPostData()?.id === post.id) {
setCurrentPostData((draft) => {
const nextPost = { ...data }
Reflect.deleteProperty(nextPost, 'category')
Object.assign(draft, nextPost)
})
toast('文章已更新')
}
break
}

case EventTypes.POST_DELETE: {
const post = data as PostModel
if (getCurrentPostData()?.id === post.id) {
router.push(routeBuilder(Routes.PageDeletd, {}))
toast.error('文章已删除')
}
break
}

case 'NOTE_UPDATE': {
const note = data as NoteModel
if (getCurrentNoteData()?.data.id === note.id) {
Expand All @@ -29,6 +65,26 @@ export const eventHandler = (type: EventTypes, data: any) => {
break
}

case 'NOTE_DELETE': {
const note = data as NoteModel
if (getCurrentNoteData()?.data.id === note.id) {
router.push(routeBuilder(Routes.PageDeletd, {}))
toast.error('手记已删除')
}
break
}

case EventTypes.PAGE_UPDATED: {
const { slug } = data
if (getCurrentPageData()?.slug === slug) {
setCurrentPageData((draft) => {
Object.assign(draft, data)
})
toast('页面已更新')
}
break
}

default: {
if (isDev) {
console.log(type, data)
Expand Down
9 changes: 8 additions & 1 deletion src/socket/socket-client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { io } from 'socket.io-client'
import type { EventTypes } from '~/types/events'
import type { AppRouterInstance } from 'next/dist/shared/lib/app-router-context'
import type { Socket } from 'socket.io-client'

import { simpleCamelcaseKeys as camelcaseKeys } from '@mx-space/api-client'
Expand All @@ -12,6 +13,8 @@ import { eventHandler } from './handler'
class SocketClient {
public socket!: Socket

private router: AppRouterInstance

constructor() {
this.socket = io(`${GATEWAY_URL}/web`, {
timeout: 10000,
Expand All @@ -21,6 +24,10 @@ class SocketClient {
transports: ['websocket'],
})
}

setRouter(router: AppRouterInstance) {
this.router = router
}
initIO() {
if (!this.socket) {
return
Expand Down Expand Up @@ -51,7 +58,7 @@ class SocketClient {

window.dispatchEvent(new CustomEvent(type, { detail: data }))

eventHandler(type, data)
eventHandler(type, data, this.router)
}
emit(event: EventTypes, payload: any) {
return new Promise((resolve) => {
Expand Down
2 changes: 1 addition & 1 deletion src/types/events.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { NoteModel } from '@mx-space/api-client'

export enum EventTypes {
export const enum EventTypes {
GATEWAY_CONNECT = 'GATEWAY_CONNECT',
GATEWAY_DISCONNECT = 'GATEWAY_DISCONNECT',

Expand Down

0 comments on commit 7dc7d7d

Please sign in to comment.