refactor: clean up codebase by removing redundant comments

Remove unnecessary JSDoc comments and redundant explanations from components, types, and data files. Simplify code structure while maintaining functionality.

Clean up language handling logic in components by removing redundant comments and simplifying state management. Move type imports to dedicated type import statements where applicable.
This commit is contained in:
joyzhao
2025-06-21 09:28:10 +08:00
parent ea01dc6dd8
commit 67f713565a
15 changed files with 9 additions and 168 deletions

View File

@@ -1,4 +1,5 @@
import { useTranslations, type Lang } from "@/i18n/utils"; import { useTranslations } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { personalInfo } from "@/lib/data"; import { personalInfo } from "@/lib/data";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
@@ -7,11 +8,9 @@ import Container from "./ui/Container";
import { type FooterProps } from "@/types"; import { type FooterProps } from "@/types";
export default function Footer({ lang: propLang }: FooterProps) { export default function Footer({ lang: propLang }: FooterProps) {
// 优先使用props传入的语言如果没有则尝试从HTML lang属性获取
const [lang, setLang] = useState<Lang>(propLang || defaultLang); const [lang, setLang] = useState<Lang>(propLang || defaultLang);
useEffect(() => { useEffect(() => {
// 在客户端运行时从HTML lang属性获取当前语言
const htmlLang = document.documentElement.lang as Lang; const htmlLang = document.documentElement.lang as Lang;
if (htmlLang && (!propLang || htmlLang !== lang)) { if (htmlLang && (!propLang || htmlLang !== lang)) {
setLang(htmlLang); setLang(htmlLang);

View File

@@ -2,21 +2,17 @@ import { personalInfo } from "@/lib/data";
import LanguageSwitcher from "./LanguageSwitcher"; import LanguageSwitcher from "./LanguageSwitcher";
import ThemeToggle from "./ui/theme-toggle"; import ThemeToggle from "./ui/theme-toggle";
import Container from "./ui/Container"; import Container from "./ui/Container";
import { useTranslations, getLocalizedPath, type Lang } from "@/i18n/utils"; import { useTranslations, getLocalizedPath } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { Menu, X } from "lucide-react"; import { Menu, X } from "lucide-react";
import { defaultLang } from "@/i18n/ui"; import { defaultLang } from "@/i18n/ui";
import { type GlassHeaderProps } from "@/types"; import { type GlassHeaderProps } from "@/types";
// 从window.document.documentElement.lang获取当前语言
export default function GlassHeader({ lang: propLang }: GlassHeaderProps) { export default function GlassHeader({ lang: propLang }: GlassHeaderProps) {
// 优先使用props传入的语言如果没有则尝试从HTML lang属性获取
const [lang, setLang] = useState<Lang>(propLang || defaultLang); const [lang, setLang] = useState<Lang>(propLang || defaultLang);
useEffect(() => { useEffect(() => {
// 在客户端运行时从HTML lang属性获取当前语言
const htmlLang = document.documentElement.lang as Lang; const htmlLang = document.documentElement.lang as Lang;
if (htmlLang && (!propLang || htmlLang !== lang)) { if (htmlLang && (!propLang || htmlLang !== lang)) {
setLang(htmlLang); setLang(htmlLang);

View File

@@ -1,23 +1,21 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { getLocalizedPath, type Lang } from "@/i18n/utils"; import { getLocalizedPath } from "@/i18n/utils";
import type { Lang } from "@/types/i18n";
import { languages as i18nLanguages, defaultLang } from "@/i18n/ui"; import { languages as i18nLanguages, defaultLang } from "@/i18n/ui";
import { Languages, Check, ChevronDown } from "lucide-react"; import { Check, ChevronDown } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
import { type LanguageSwitcherProps } from "@/types"; import { type LanguageSwitcherProps } from "@/types";
const availableLanguages = Object.entries(i18nLanguages).map(([code, name]) => ({ const availableLanguages = Object.entries(i18nLanguages).map(([code, name]) => ({
code: code as Lang, code: code as Lang,
name, name,
// 语言图标映射
icon: code === 'en' ? '🇬🇧' : code === 'zh' ? '🇨🇳' : '🌐' icon: code === 'en' ? '🇬🇧' : code === 'zh' ? '🇨🇳' : '🌐'
})); }));
export default function LanguageSwitcher({ lang: propLang }: LanguageSwitcherProps) { export default function LanguageSwitcher({ lang: propLang }: LanguageSwitcherProps) {
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
// 获取当前语言优先使用props传入的语言
const [currentLang, setCurrentLang] = useState<Lang>(propLang || defaultLang); const [currentLang, setCurrentLang] = useState<Lang>(propLang || defaultLang);
// 在客户端运行时从HTML lang属性获取当前语言
useEffect(() => { useEffect(() => {
if (typeof document !== 'undefined') { if (typeof document !== 'undefined') {
const htmlLang = document.documentElement.lang as Lang; const htmlLang = document.documentElement.lang as Lang;
@@ -50,39 +48,28 @@ export default function LanguageSwitcher({ lang: propLang }: LanguageSwitcherPro
const currentPathParts = currentPathname.split('/').filter(p => p); const currentPathParts = currentPathname.split('/').filter(p => p);
let basePath = ''; let basePath = '';
// Check if the first part of the path is a known language code
if (currentPathParts.length > 0 && Object.keys(i18nLanguages).includes(currentPathParts[0])) { if (currentPathParts.length > 0 && Object.keys(i18nLanguages).includes(currentPathParts[0])) {
// If the first part is a language code, remove it to get the base path
basePath = '/' + currentPathParts.slice(1).join('/'); basePath = '/' + currentPathParts.slice(1).join('/');
} else { } else {
// If no language code in path, use the current path as base
basePath = currentPathname; basePath = currentPathname;
} }
// Ensure basePath always starts with a slash, or is just a slash for the root
if (!basePath.startsWith('/')) { if (!basePath.startsWith('/')) {
basePath = '/' + basePath; basePath = '/' + basePath;
} }
// Fix for empty paths
if (basePath === '//') basePath = '/'; if (basePath === '//') basePath = '/';
if (basePath === '') basePath = '/'; if (basePath === '') basePath = '/';
let newPath; let newPath;
// If the target language is the default language and prefixDefaultLocale is false (as per our astro.config.mjs)
// then no language prefix is needed.
if (languageOpt.code === defaultLang) { if (languageOpt.code === defaultLang) {
newPath = basePath; newPath = basePath;
} else { } else {
// For non-default languages, prefix with the language code.
newPath = `/${languageOpt.code}${basePath}`; newPath = `/${languageOpt.code}${basePath}`;
} }
// Clean up double slashes, just in case
newPath = newPath.replace(/\/\/+/g, '/'); newPath = newPath.replace(/\/\/+/g, '/');
// Handle case where basePath might be empty resulting in just /zh or /en
if (newPath === '') newPath = '/'; if (newPath === '') newPath = '/';
// Prevent unnecessary redirects to the same page
if (newPath !== currentPathname) { if (newPath !== currentPathname) {
window.location.href = newPath; window.location.href = newPath;
} }
@@ -120,7 +107,7 @@ export default function LanguageSwitcher({ lang: propLang }: LanguageSwitcherPro
role="menuitem" role="menuitem"
> >
<span className="flex items-center"> <span className="flex items-center">
<span className="mr-2">{lang.icon}</span> {/* Display icon */} <span className="mr-2">{lang.icon}</span>
{lang.name} {lang.name}
</span> </span>
{selectedLanguage.code === lang.code && <Check size={16} className="text-primary" />} {selectedLanguage.code === lang.code && <Check size={16} className="text-primary" />}

View File

@@ -2,10 +2,6 @@ import { motion, type Variants } from "framer-motion";
import { useTranslations } from "@/i18n/utils"; import { useTranslations } from "@/i18n/utils";
import { type SkillItem } from "@/types"; import { type SkillItem } from "@/types";
/**
* All skills data with corresponding skillicons names
* Using skillicons.dev for consistent icon display
*/
const allSkills: SkillItem[] = [ const allSkills: SkillItem[] = [
// Programming Languages // Programming Languages
{ name: "TypeScript", icon: "typescript" }, { name: "TypeScript", icon: "typescript" },

View File

@@ -6,11 +6,6 @@ interface ContainerProps {
className?: string; className?: string;
} }
/**
* Container component for consistent content width across the site
* @param children - The content to be wrapped
* @param className - Additional classes to apply
*/
export default function Container({ export default function Container({
children, children,
className className

View File

@@ -1,25 +1,9 @@
/**
* Translations module
* Contains all translation data for the application
*/
/**
* Available languages in the application
*/
export const languages = { export const languages = {
en: 'English', en: 'English',
zh: '简体中文', zh: '简体中文',
} as const; } as const;
/**
* Default language for the application
*/
export const defaultLang = 'en'; export const defaultLang = 'en';
/**
* Structured translations data
* Organized by language and feature area
*/
export const translations = { export const translations = {
en: { en: {
nav: { nav: {

View File

@@ -1,44 +1,18 @@
/**
* Internationalization utilities module
* Contains helper functions for i18n functionality
*/
import { defaultLang, languages, flatTranslations } from './translations'; import { defaultLang, languages, flatTranslations } from './translations';
import type { Lang } from '@/types/i18n'; import type { Lang } from '@/types/i18n';
/**
* Translation key type
* Represents a dot-notation path to a translation string
*/
export type TranslationKey = string; export type TranslationKey = string;
/**
* Get translation function
* Returns a function that can be used to get translations for a specific language
*
* @param lang - The language to get translations for
* @returns A translation function
*/
export function useTranslations(lang: Lang | undefined) { export function useTranslations(lang: Lang | undefined) {
const currentLang = lang || defaultLang; const currentLang = lang || defaultLang;
/**
* Translation function
* Gets a translation string for the specified key and replaces placeholders
*
* @param key - The translation key (dot notation)
* @param args - Optional arguments to replace placeholders in the translation
* @returns The translated string
*/
return function t(key: TranslationKey, ...args: any[]): string { return function t(key: TranslationKey, ...args: any[]): string {
// Get translation from flattened translations for better performance
let translation = flatTranslations[currentLang][key]; let translation = flatTranslations[currentLang][key];
// Fallback to default language if translation not found
if (!translation && currentLang !== defaultLang) { if (!translation && currentLang !== defaultLang) {
translation = flatTranslations[defaultLang][key]; translation = flatTranslations[defaultLang][key];
} }
// Fallback to key if translation not found in any language
if (!translation) { if (!translation) {
console.warn(`Translation key not found: ${key}`); console.warn(`Translation key not found: ${key}`);
return key; return key;

View File

@@ -1,23 +1,7 @@
/**
* Data module (Legacy)
* This file is kept for backward compatibility
* All data has been moved to src/lib/data/ directory
*/
// Re-export all data from the new modules
export { personalInfo } from './data/personal-info'; export { personalInfo } from './data/personal-info';
export { projects } from './data/projects'; export { projects } from './data/projects';
export { services } from './data/services'; export { services } from './data/services';
// For TypeScript type checking
import { personalInfo } from './data/personal-info';
import { projects } from './data/projects';
import { services } from './data/services';
// Type exports are now handled in src/types/index.ts
// This file is now just a re-export wrapper
// The actual data is in the respective files in src/lib/data/ directory
// export const projects = { // export const projects = {
// en: [{ // en: [{
// id: "taskify", // id: "taskify",

View File

@@ -1,9 +1,3 @@
/**
* Data index module
* Re-exports all data modules to maintain backward compatibility
*/
// Re-export all data modules
export { personalInfo } from './personal-info'; export { personalInfo } from './personal-info';
export { projects } from './projects'; export { projects } from './projects';
export { services } from './services'; export { services } from './services';

View File

@@ -1,13 +1,4 @@
/**
* Personal information data module
* Contains all personal information used throughout the site
*/
import type { PersonalInfo } from '@/types'; import type { PersonalInfo } from '@/types';
/**
* Personal information data
* This data is used in various components like Header, Footer, and About sections
*/
export const personalInfo: PersonalInfo = { export const personalInfo: PersonalInfo = {
name: "Joy Zhao", name: "Joy Zhao",
location: "China", location: "China",

View File

@@ -1,13 +1,4 @@
/**
* Projects data module
* Contains all project information displayed in the projects page
*/
import type { Project } from '@/types'; import type { Project } from '@/types';
/**
* Projects data with localization support
* Each project contains information like id, tag, title, description, tech stack, etc.
*/
export const projects = { export const projects = {
en: [ en: [
{ {

View File

@@ -1,13 +1,4 @@
/**
* Services data module
* Contains all service information displayed in the services section
*/
import type { Service } from '@/types'; import type { Service } from '@/types';
/**
* Services data with localization support
* Each service contains information like title, icon, items, and color
*/
export const services = { export const services = {
en: [ en: [
{ {

View File

@@ -10,7 +10,7 @@ import type { Lang } from './i18n';
export interface SkillItem { export interface SkillItem {
name: string; name: string;
icon: string; icon: string;
color: string; color?: string;
} }
/** /**

View File

@@ -1,19 +1,9 @@
/**
* Data types module
* Contains type definitions for all data structures used in the application
*/
import type { Lang } from './i18n.ts'; import type { Lang } from './i18n.ts';
/**
* Multi-language text type
*/
export type LocalizedText = { export type LocalizedText = {
[K in Lang]: string; [K in Lang]: string;
}; };
/**
* Personal information interface
*/
export interface PersonalInfo { export interface PersonalInfo {
name: string; name: string;
location: string; location: string;
@@ -45,18 +35,12 @@ export interface PersonalInfo {
}; };
} }
/**
* Project image interface
*/
export interface ProjectImage { export interface ProjectImage {
bg: string; bg: string;
hover: string; hover: string;
text: string; text: string;
} }
/**
* Project interface
*/
export interface Project { export interface Project {
id: string; id: string;
tag: string; tag: string;
@@ -69,17 +53,11 @@ export interface Project {
link: string; link: string;
} }
/**
* Service icon interface
*/
export interface ServiceIcon { export interface ServiceIcon {
svg: string; svg: string;
gradient: string; gradient: string;
} }
/**
* Service interface
*/
export interface Service { export interface Service {
title: string; title: string;
icon: ServiceIcon; icon: ServiceIcon;

View File

@@ -1,36 +1,17 @@
/**
* Internationalization types module
* Contains type definitions for i18n functionality
*/
import { languages } from '@/i18n/translations'; import { languages } from '@/i18n/translations';
/**
* Language type definition
*/
export type Lang = keyof typeof languages; export type Lang = keyof typeof languages;
/**
* UI translation keys type
*/
export type UiKeys = string; export type UiKeys = string;
/**
* Language switcher component props
*/
export interface LanguageSwitcherProps { export interface LanguageSwitcherProps {
lang: Lang; lang: Lang;
} }
/**
* Glass header component props
*/
export interface GlassHeaderProps { export interface GlassHeaderProps {
lang: Lang; lang: Lang;
} }
/**
* Footer component props
*/
export interface FooterProps { export interface FooterProps {
lang?: Lang; lang?: Lang;
} }