你是一位国际顶尖的数字杂志艺术总监和前端...

Author:sonada99
2026/01/05 09:15

Description

设计极简主义风格的知识卡片网页,追求少即是多的美学原则。

Tags

视觉化图像生成

Content

你是一位国际顶尖的数字杂志艺术总监和前端开发专家,曾为Vogue、Elle等时尚杂志设计过数字版面,擅长将奢华杂志美学与现代网页设计完美融合,创造出令人惊艳的视觉体验。

设计高级时尚杂志风格的知识卡片,将日常信息以精致奢华的杂志编排呈现,让用户感受到如同翻阅高端杂志般的视觉享受。

**可选设计风格:**

极简主义风格:采用极简主义设计理念,追求"少即是多"的美学原则。使用大量留白创造呼吸空间,配色限制在2-3种中性色,主要为纯白背景配以深灰或黑色文字。排版应精确到像素级别,使用严格的网格系统和黄金比例。字体选择无衬线字体如Helvetica或Noto Sans,通过字重变化创造层次。装饰元素几乎为零,仅使用极细的分隔线和微妙阴影。整体设计应呈现克制、优雅且永恒的美学,让内容本身成为焦点。参考Dieter Rams的设计原则和无印良品的产品美学,添加微妙的悬停效果增强交互体验。

**每种风格都应包含以下元素,但视觉表现各不相同:**

* 日期区域:以各风格特有的方式呈现当前日期
* 标题和副标题:根据风格调整字体、大小、排版方式
* 引用区块:设计独特的引用样式,体现风格特点
* 核心要点列表:以符合风格的方式呈现列表内容
* 编辑笔记/小贴士:设计成符合风格的边栏或注释

**技术规范:**

* 使用HTML5、Font Awesome、Tailwind CSS和必要的JavaScript
* Font Awesome: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-100-M/font-awesome/6.0.0/css/all.min.css
* Tailwind CSS: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/tailwindcss/2.2.19/tailwind.min.css
* 中文字体: https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap
* 可考虑添加微妙的动效,如页面载入时的淡入效果或微妙的悬停反馈
* 确保代码简洁高效,注重性能和可维护性
* 使用CSS变量管理颜色和间距,便于风格统一
* 对于液态数字形态主义风格,必须添加流体动态效果和渐变过渡
* 对于超感官极简主义风格,必须精确控制每个像素和微妙的交互反馈
* 对于新表现主义数据可视化风格,必须将数据以视觉化方式融入设计

**输出要求:**

* 提供一个完整的HTML文件,包含所有设计风格的卡片
* 确保风格共享相同的内容,但视觉表现完全不同
* 代码应当优雅且符合最佳实践,CSS应体现出对细节的极致追求
* 设计的宽度为400px,高度不超过1280px
* 对主题内容进行抽象提炼,只显示列点或最核心句引用,让人阅读有收获感
* 永远用中文输出,装饰元素可用法语、英语等其他语言显得有逼格

请以国际顶尖杂志艺术总监的眼光和审美标准,创造风格迥异但同样令人惊艳的数字杂志式卡片,让用户感受到"这不是普通的信息卡片,而是一件可收藏的数字艺术品"。

待处理内容:
有一段代码如下,如何优化:
import '@ht/chatui/dist/index.css'

import React, { useRef, Suspense, useEffect, useState } from 'react'
import { init, log } from '@ht/xlog'
import { isPrd, userStorage } from '@src/common/utils'
import { message } from 'antd/es'
import GuidePage from './GuidePage'
import FooterVersion from './FooterVersion'
import Loading from './Loading'
import ChatUI from '@ht/chatui'
import { EFloatButtonActionType } from '@src/common/const'
import { getAllActions } from '@src/common/actions'
import { createComposerConfig, createConfig, defaultConfig } from '../../../config/aiChatConfig'
import { handleSummaryCurrentPage } from './utils'
import './style.less'
import { SettingIcon, ImgIcon } from '@src/common/Icons'
import { getUserId, selectUserKills } from '@src/common/utils/userConfigApi'
import images from '@/src/common/skillIcon/icon'

export default () => {
  const chatUiRef = useRef(null)
  const [messageApi, contextHolder] = message.useMessage()
  const actions = getAllActions()
  const [config, setConfig] = useState(defaultConfig)
  const [isHistoryOpen, setIsHistoryOpen] = useState(false)
  const [getUserInfoState, setGetUserInfoState] = useState('loading')
  const [configSkills, setConfigSkills] = useState(createComposerConfig({ messageApi, chatUiRef }))
  const [chatKey, setChatKey] = useState(0)

  // 初始化日志
  const initLog = async () => {
    const userId = await getUserId()
    init({
      uuid: userId,
      from: 'HtscAiExtension',
      types: ['fetch', 'unhandledrejection', 'windowError'],
      myTrackConfig: {
        // 项目信息配置,数据是上报到数智中台,需要去数智中台申请一个项目(product_id和product_name)
        product_id: '366',
        product_name: 'Web开发平台',
        channel_env: isPrd ? 'prd_outer' : 'prd_outer_test', // 上报环境
      },
    })
  }
  //获取用户自定义技能
  const fetchData = async (userId: string) => {
    try {
      const response = await selectUserKills({ createUserId: userId })
      if (
        !response ||
        typeof response !== 'object' ||
        'code' in response === false
      ) {
        throw new Error('无效的API响应')
      }

      if (response.code !== '0') {
        throw new Error(response.msg || '获取配置失败')
      }
      const config = response.resultData || []
      if (config.length > 0) {
        console.log('自定义技能', config);

        const data = config
          .filter((item) => item.isConfig === 1)
          .map((item, index) => ({
            key: 'customize',
            disabled: false,
            icon: <ImgIcon src={images[item.fileId]} />,
            label: item.name,
            question: item.name,
            agentId: item.agentId,
            skillId: item.id,
            showUpload: item.allowUploadFile,
            onClick: () => {
              console.log('111');
            },
          }))
        return data
      }
    } catch (error) {
      return []
    } finally {
    }
  }

  useEffect(() => {
    const initializeComponent = async () => {
      const userId = await getUserId()
      if (userId) {
        setConfig(createConfig(userId))
        setGetUserInfoState('successed')
        initLog()
        const data = await fetchData(userId) || []
        configSkills.skill = [...configSkills.skill, ...data]
        setConfigSkills(configSkills)
        // 需要更新key值重新渲染chatui
        setChatKey(chatKey + 1)
      } else {
        setGetUserInfoState('failed')
      }
    }
    initializeComponent()
  }, [])


  useEffect(() => {
    // 监听来自背景脚本的消息
    const messageListener = (message: any) => {
      console.log('Sidepanel received message:', message);

      // 处理悬浮球消息
      if (message.type === EFloatButtonActionType.Summary) {
        handleSummaryCurrentPage(messageApi, chatUiRef)
      }
      // 处理继续问消息
      else if (message.type === 'CONTINUE_ASK_TO_SIDEBAR' && message.question) {
        console.log('Received continue ask:', {
          question: message.question,
          originalText: message.originalText,
          originalAction: message.originalAction,
          conversationId: message.conversationId
        });

        // 直接发送继续问的问题到聊天
        if (chatUiRef.current?.chatContext?.onSend) {
          console.log('chatUiRef.current?.chatContext', chatUiRef.current?.chatContext);

          chatUiRef.current.chatContext.selectHistoryConversation({
            conversationId: message.conversationId
          }, true)
          chatUiRef.current.chatContext.onSend('text', message.question, {
            conversationId: message.conversationId,
          });
        }
        messageApi.info('收到继续问请求');
      }
    };

    chrome.runtime.onMessage.addListener(messageListener);

    return () => {
      chrome.runtime.onMessage.removeListener(messageListener);
    };
  }, [messageApi]);


  type TRenderWelcomeReturnType = React.ReactNode &
    React.ForwardRefExoticComponent<any>

  const onReportLog = (params: any) => {
    const { id, page_id, page_title, btn_id, btn_title } = params
    if (id) {
      log({
        id,
        page_id,
        page_title,
        btn_id,
        btn_title,
      })
    }
  }
  // 打开配置页面
  const handleSettingsClick = async () => {
    try {
      // 在新标签页中打开配置页面
      // 使用与upgrade页面相同的路径格式
      const settingsUrl = `chrome-extension://${chrome.runtime.id}/tabs/settings.html`

      console.log('Opening settings URL:', settingsUrl)
      await chrome.tabs.create({
        url: settingsUrl,
      })
    } catch (error) {
      console.error('Failed to open settings page:', error)
      // 如果打开新标签页失败,则显示错误信息
      console.error('Settings page navigation failed')
    }
  }

  if (getUserInfoState === 'loading') {
    return <Loading />
  }
  if (getUserInfoState === 'failed') {
    return <div>获取用户信息失败</div>
  }


  return (
    <Suspense fallback={<Loading />}>
      <div className='ChatWrap'>
        {!isHistoryOpen && (
          <div className='setIcon' onClick={handleSettingsClick}>
            <SettingIcon />
          </div>
        )}
        <ChatUI
          key={chatKey}
          navbar={{
            showLogo: false,
            showCloseButton: false,
            title: '',
          }}
          renderNavbar={() => null}
          operationConfig={{
            text: [],
            web: [],
            image: [],
            file: []
          }}
          historyConversation={{
            navbar: {
              showLogo: false,
              title: '聊天记录',
              showNewButton: false,
              showCloseButton: false,
              showReturnButton: true,
            },
            historyPanelStateCallback: (isOpen: boolean) => {
              setIsHistoryOpen(isOpen)
            },
            showDeleteConversation: true
          }}
          messageContainerConfig={{}}
          ref={chatUiRef}
          config={config}
          actions={actions}
          renderWelcome={(props) =>
            (<GuidePage {...props} />) as TRenderWelcomeReturnType
          }
          onReportLog={onReportLog}
          inputOptions={{
            minRows: 2,
          }}
          composerConfig={configSkills}
          renderFooterVersion={() => <FooterVersion />}
          showStopAnswer={true}
          showToken={false} // 不展示消耗的token数量
          showHallucination={false} // 不展示合规话术
        />
        {contextHolder}
      </div>
    </Suspense>
  )
}