mirror of https://github.com/sunface/rust-course
parent
2046b95337
commit
c6adb3a813
@ -0,0 +1,136 @@
|
||||
import {
|
||||
chakra,
|
||||
Flex,
|
||||
HStack,
|
||||
IconButton,
|
||||
useColorModeValue,
|
||||
useDisclosure,
|
||||
useUpdateEffect,
|
||||
Box,
|
||||
VStack,
|
||||
useMediaQuery
|
||||
} from "@chakra-ui/react"
|
||||
import siteConfig from "configs/site-config"
|
||||
import { useViewportScroll } from "framer-motion"
|
||||
import NextLink from "next/link"
|
||||
import React from "react"
|
||||
import { FaGithub, FaSearch } from "react-icons/fa"
|
||||
import Logo, { LogoIcon } from "src/components/logo"
|
||||
import { MobileNavButton, MobileNavContent } from "./mobile-nav"
|
||||
import AlgoliaSearch from "src/components/search/algolia-search"
|
||||
import { useRouter } from "next/router"
|
||||
import { ReserveUrls } from "src/data/reserve-urls"
|
||||
import Link from "next/link"
|
||||
import DarkMode from "components/dark-mode"
|
||||
import AccountMenu from "components/account-menu"
|
||||
|
||||
const navLinks = [{
|
||||
title: '主页',
|
||||
url: '/',
|
||||
},
|
||||
{
|
||||
title: '标签',
|
||||
url: ReserveUrls.Tags,
|
||||
},
|
||||
{
|
||||
title: '学习资料',
|
||||
url: ReserveUrls.Courses,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
function HeaderContent() {
|
||||
const router = useRouter()
|
||||
const { asPath } = router
|
||||
const mobileNav = useDisclosure()
|
||||
|
||||
|
||||
const mobileNavBtnRef = React.useRef<HTMLButtonElement>()
|
||||
const [isLargerThan768] = useMediaQuery("(min-width: 768px)")
|
||||
useUpdateEffect(() => {
|
||||
mobileNavBtnRef.current?.focus()
|
||||
}, [mobileNav.isOpen])
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Flex className="vertical-nav" h="100%" align="center" justify="space-between" px={[2,2,6,6]} direction="column" py="8">
|
||||
<VStack align="center">
|
||||
<NextLink href="/" passHref>
|
||||
<chakra.a style={{ marginTop: '-5px' }} aria-label="Chakra UI, Back to homepage">
|
||||
{isLargerThan768 ? <Logo width="130" /> : <Logo width="105" />}
|
||||
</chakra.a>
|
||||
</NextLink>
|
||||
|
||||
<VStack pt="6" ml={{ base: 1, md: 4, lg: 12 }} fontSize="1rem" minWidth="250px">
|
||||
{navLinks.map(link => <Box px="4" py="0.7rem" rounded="md" key={link.url} color={useColorModeValue("gray.700", "whiteAlpha.900")} aria-current={asPath === link.url ? "page" : undefined} _activeLink={{ bg: useColorModeValue("transparent", "rgba(48, 140, 122, 0.3)"), color: useColorModeValue("teal.500", "teal.200"), fontWeight: "bold", }} ><Link href={link.url}>{link.title}</Link></Box>)}
|
||||
</VStack>
|
||||
</VStack>
|
||||
|
||||
<VStack
|
||||
spacing="4"
|
||||
align="center"
|
||||
color={useColorModeValue("gray.500", "gray.400")}
|
||||
>
|
||||
<IconButton
|
||||
fontSize="1.4rem"
|
||||
aria-label="go to github"
|
||||
variant="ghost"
|
||||
color="current"
|
||||
_focus={null}
|
||||
icon={<FaSearch />}
|
||||
/>
|
||||
|
||||
<Link
|
||||
aria-label="Go to Chakra UI GitHub page"
|
||||
href={siteConfig.repo.url}
|
||||
>
|
||||
<IconButton
|
||||
size="md"
|
||||
fontSize="1.4rem"
|
||||
aria-label="go to github"
|
||||
variant="ghost"
|
||||
color="current"
|
||||
_focus={null}
|
||||
icon={<FaGithub />}
|
||||
/>
|
||||
</Link>
|
||||
<DarkMode fontSize="1.4rem"/>
|
||||
<AccountMenu />
|
||||
{/* <MobileNavButton
|
||||
ref={mobileNavBtnRef}
|
||||
aria-label="Open Menu"
|
||||
onClick={mobileNav.onOpen}
|
||||
/> */}
|
||||
</VStack>
|
||||
</Flex>
|
||||
<MobileNavContent isOpen={mobileNav.isOpen} onClose={mobileNav.onClose} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function VerticalNav(props) {
|
||||
const ref = React.useRef<HTMLHeadingElement>()
|
||||
|
||||
return (
|
||||
<chakra.header
|
||||
ref={ref}
|
||||
transition="box-shadow 0.2s"
|
||||
pos="fixed"
|
||||
top="0"
|
||||
zIndex="3"
|
||||
left="0"
|
||||
bottom="0"
|
||||
bg={useColorModeValue('white', 'gray.800')}
|
||||
{...props}
|
||||
>
|
||||
<chakra.div height="100%">
|
||||
<HeaderContent />
|
||||
</chakra.div>
|
||||
</chakra.header>
|
||||
)
|
||||
}
|
||||
|
||||
export default VerticalNav
|
||||
|
||||
|
After Width: | Height: | Size: 612 B |
@ -1,28 +0,0 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/imdotdev/im.dev/server/internal/cache"
|
||||
"github.com/imdotdev/im.dev/server/pkg/e"
|
||||
"github.com/imdotdev/im.dev/server/pkg/models"
|
||||
)
|
||||
|
||||
func GetUsers(q string) ([]*models.User, *e.Error) {
|
||||
allUsers := cache.Users
|
||||
|
||||
users := make([]*models.User, 0)
|
||||
for _, u := range allUsers {
|
||||
if strings.HasPrefix(strings.ToLower(u.Nickname), strings.ToLower(q)) {
|
||||
users = append(users, u)
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(strings.ToLower(u.Username), strings.ToLower(q)) {
|
||||
users = append(users, u)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/imdotdev/im.dev/server/internal/cache"
|
||||
"github.com/imdotdev/im.dev/server/pkg/db"
|
||||
"github.com/imdotdev/im.dev/server/pkg/e"
|
||||
"github.com/imdotdev/im.dev/server/pkg/models"
|
||||
)
|
||||
|
||||
func GetUsers(q string) ([]*models.User, *e.Error) {
|
||||
allUsers := cache.Users
|
||||
|
||||
users := make([]*models.User, 0)
|
||||
for _, u := range allUsers {
|
||||
if strings.HasPrefix(strings.ToLower(u.Nickname), strings.ToLower(q)) {
|
||||
users = append(users, u)
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(strings.ToLower(u.Username), strings.ToLower(q)) {
|
||||
users = append(users, u)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetUserDetail(id int64, username string) (*models.User, *e.Error) {
|
||||
user := &models.User{}
|
||||
err := user.Query(id, username, "")
|
||||
if err != nil {
|
||||
logger.Warn("query user error", "error", err)
|
||||
return nil, e.New(http.StatusInternalServerError, e.Internal)
|
||||
}
|
||||
|
||||
err = db.Conn.QueryRow("SELECT tagline,cover,location,avail_for,about,website,twitter,github,zhihu,weibo,facebook,stackoverflow from user_profile WHERE id=?", user.ID).Scan(
|
||||
&user.Tagline, &user.Cover, &user.Location, &user.AvailFor, &user.About, &user.Website, &user.Twitter,
|
||||
&user.Github, &user.Zhihu, &user.Weibo, &user.Facebook, &user.Stackoverflow,
|
||||
)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
logger.Warn("query user profile error", "error", err)
|
||||
return nil, e.New(http.StatusInternalServerError, e.Internal)
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func UpdateUser(u *models.User) *e.Error {
|
||||
_, err := db.Conn.Exec("UPDATE user SET nickname=?,avatar=?,email=?,updated=? WHERE id=?", u.Nickname, u.Avatar, u.Email, time.Now(), u.ID)
|
||||
if err != nil {
|
||||
if e.IsErrUniqueConstraint(err) {
|
||||
return e.New(http.StatusConflict, "email已经存在")
|
||||
}
|
||||
logger.Warn("update user error", "error", err)
|
||||
return e.New(http.StatusInternalServerError, e.Internal)
|
||||
}
|
||||
|
||||
var nid int64
|
||||
err = db.Conn.QueryRow("SELECT id FROM user_profile WHERE id=?", u.ID).Scan(&nid)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
logger.Warn("update user profile error", "error", err)
|
||||
return e.New(http.StatusInternalServerError, e.Internal)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
if err == sql.ErrNoRows {
|
||||
_, err = db.Conn.Exec("INSERT INTO user_profile (id,tagline,cover,location,avail_for,about,website,twitter,github,zhihu,weibo,facebook,stackoverflow,updated) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
u.ID, u.Tagline, u.Cover, u.Location, u.AvailFor, u.About, u.Website, u.Twitter, u.Github, u.Zhihu, u.Weibo, u.Facebook, u.Stackoverflow, now)
|
||||
} else {
|
||||
_, err = db.Conn.Exec("UPDATE user_profile SET tagline=?,cover=?,location=?,avail_for=?,about=?,website=?,twitter=?,github=?,zhihu=?,weibo=?,facebook=?,stackoverflow=?,updated=? WHERE id=?",
|
||||
u.Tagline, u.Cover, u.Location, u.AvailFor, u.About, u.Website, u.Twitter, u.Github, u.Zhihu, u.Weibo, u.Facebook, u.Stackoverflow, now, u.ID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.Warn("update user profile error", "error", err)
|
||||
return e.New(http.StatusInternalServerError, e.Internal)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,23 +1,43 @@
|
||||
import { Tag } from './tag'
|
||||
export interface Session {
|
||||
token: string
|
||||
createTime: string
|
||||
user : User
|
||||
token: string
|
||||
createTime: string
|
||||
user: User
|
||||
}
|
||||
|
||||
export interface User {
|
||||
id :number
|
||||
username: string
|
||||
nickname: string
|
||||
avatar: string
|
||||
role?: string
|
||||
email?: string
|
||||
// basic info
|
||||
id: number
|
||||
username: string
|
||||
nickname: string
|
||||
avatar: string
|
||||
role?: string
|
||||
email?: string
|
||||
|
||||
// about user
|
||||
tagline?: string
|
||||
cover?: string
|
||||
location?: string
|
||||
availFor?: string
|
||||
about?: string
|
||||
skills?: Tag[]
|
||||
|
||||
// social links
|
||||
website?: string
|
||||
twitter?: string
|
||||
github?: string
|
||||
zhihu?: string
|
||||
weibo?: string
|
||||
facebook?: string
|
||||
stackoverflow?: string
|
||||
|
||||
lastSeenAt?: string
|
||||
created?: string
|
||||
}
|
||||
|
||||
export interface UserSimple {
|
||||
id :number
|
||||
username: string
|
||||
nickname: string
|
||||
avatar: string
|
||||
id: number
|
||||
username: string
|
||||
nickname: string
|
||||
avatar: string
|
||||
}
|
Loading…
Reference in new issue