]+href=[""']([^""']+)[""'][^>]*>", RegexOptions.IgnoreCase);
+ foreach (Match linkMatch2 in linkMatches)
+ {
+ var url = linkMatch2.Groups[1].Value;
+ if (!string.IsNullOrWhiteSpace(url) && !relatedLinks.Contains(url))
+ {
+ relatedLinks.Add(url);
+ }
+ }
+
+ if (!string.IsNullOrWhiteSpace(title) && !string.IsNullOrWhiteSpace(bodyText))
+ {
+ newsItems.Add(new JuyaDetailedNewsItem(title, number ?? 0, bodyText, relatedLinks));
+ }
+ }
+
+ return newsItems;
+ }
+
+ private static string ExtractBodyText(string htmlContent)
+ {
+ if (string.IsNullOrWhiteSpace(htmlContent))
+ {
+ return "";
+ }
+
+ // 提取 blockquote 内容
+ var blockquoteMatch = Regex.Match(htmlContent, @"(.*?)
", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ if (blockquoteMatch.Success)
+ {
+ var text = blockquoteMatch.Groups[1].Value;
+ // 移除 标签但保留内容
+ text = Regex.Replace(text, @"
(.*?)
", "$1\n\n", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ // 移除其他 HTML 标签
+ text = Regex.Replace(text, @"<[^>]+>", "");
+ // 清理多余空白
+ text = Regex.Replace(text, @"\n{3,}", "\n\n");
+ return text.Trim();
+ }
+
+ // 如果没有 blockquote,提取所有 标签内容
+ var paragraphs = Regex.Matches(htmlContent, @"
(.*?)
", RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ if (paragraphs.Count > 0)
+ {
+ var text = string.Join("\n\n", paragraphs.Cast().Select(m =>
+ Regex.Replace(m.Groups[1].Value, @"<[^>]+>", "").Trim()));
+ return text.Trim();
+ }
+
+ // 最后尝试直接移除所有 HTML 标签
+ return Regex.Replace(htmlContent, @"<[^>]+>", "").Trim();
+ }
+
+ private void AddDailyNewsToView(JuyaDailyNews news)
+ {
+ var view = new DailyNewsView(news, _isNightVisual);
+ view.CoverImageClicked += (s, e) => TryOpenUrl(news.IssueUrl);
+ view.NewsItemClicked += (s, url) => TryOpenUrl(url);
+ NewsStackPanel.Children.Add(view);
+ _dailyViews.Add(view);
+ }
+
+ private async void OnScrollChanged(object? sender, ScrollChangedEventArgs e)
+ {
+ if (_isLoading || !_isAttached)
+ {
+ return;
+ }
+
+ var scrollViewer = (ScrollViewer)sender!;
+
+ var offset = scrollViewer.Offset;
+ var extent = scrollViewer.Extent;
+ var viewport = scrollViewer.Viewport;
+
+ if (offset.Y >= extent.Height - viewport.Height - 200)
+ {
+ await LoadMoreNewsAsync();
+ }
+ }
+
+ private async Task LoadMoreNewsAsync()
+ {
+ if (_isLoading || !_isAttached)
+ {
+ return;
+ }
+
+ var nextDates = Enumerable.Range(1, LoadMoreDays)
+ .Select(i => _earliestLoadedDate.AddDays(-i))
+ .Where(d => _cachedNews.ContainsKey(d) && !_loadedDates.Contains(d))
+ .ToList();
+
+ if (!nextDates.Any())
+ {
+ return;
+ }
+
+ _isLoading = true;
+ LoadingTextBlock.IsVisible = true;
+
+ try
+ {
+ await Dispatcher.UIThread.InvokeAsync(() =>
+ {
+ if (!_isAttached) return;
+
+ foreach (var date in nextDates.OrderByDescending(d => d))
+ {
+ AddDailyNewsToView(_cachedNews[date]);
+ _loadedDates.Add(date);
+ }
+
+ _earliestLoadedDate = _loadedDates.Min();
+ LoadingTextBlock.IsVisible = false;
+ UpdateAdaptiveLayout();
+ });
+ }
+ finally
+ {
+ _isLoading = false;
+ }
+ }
+
+ private async void OnRefreshButtonClick(object? sender, RoutedEventArgs e)
+ {
+ e.Handled = true;
+
+ if (_isLoading)
+ {
+ return;
+ }
+
+ _cachedNews.Clear();
+ _loadedDates.Clear();
+ _dailyViews.Clear();
+ NewsStackPanel.Children.Clear();
+ _earliestLoadedDate = DateTime.Today;
+
+ await LoadInitialNewsAsync();
+ }
+
+ private void TryOpenUrl(string? url)
+ {
+ if (string.IsNullOrWhiteSpace(url))
+ {
+ return;
+ }
+
+ try
+ {
+ var startInfo = new ProcessStartInfo
+ {
+ FileName = url,
+ UseShellExecute = true
+ };
+ Process.Start(startInfo);
+ }
+ catch
+ {
+ // 忽略错误
+ }
+ }
+
+ private void ApplyLoadingState()
+ {
+ StatusTextBlock.Text = "加载中...";
+ StatusTextBlock.IsVisible = true;
+ }
+
+ private void UpdateAdaptiveLayout()
+ {
+ var scale = ResolveScale();
+ var softScale = Math.Clamp(scale, 0.80, 1.32);
+ var totalWidth = Bounds.Width > 1 ? Bounds.Width : _currentCellSize * BaseWidthCells;
+ var totalHeight = Bounds.Height > 1 ? Bounds.Height : _currentCellSize * BaseHeightCells;
+
+ var unifiedMainRectangle = ResolveUnifiedMainRectangle();
+ RootBorder.CornerRadius = unifiedMainRectangle;
+ CardBorder.CornerRadius = unifiedMainRectangle;
+
+ var horizontalPadding = Math.Clamp(16 * softScale, 10, 24);
+ var verticalPadding = Math.Clamp(14 * softScale, 8, 20);
+ CardBorder.Padding = new Thickness(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
+
+ var headerHeight = Math.Clamp(40 * softScale, 28, 56);
+ HeaderGrid.Height = headerHeight;
+
+ BrandTextBlock.FontSize = Math.Clamp(20 * softScale, 14, 26);
+
+ var avatarSize = Math.Clamp(36 * softScale, 24, 48);
+ AvatarBorder.Width = avatarSize;
+ AvatarBorder.Height = avatarSize;
+ AvatarBorder.CornerRadius = new CornerRadius(avatarSize / 2);
+
+ var buttonFontSize = Math.Clamp(13 * softScale, 10, 16);
+ RefreshButton.FontSize = buttonFontSize;
+ RefreshButton.Padding = new Thickness(
+ Math.Clamp(8 * softScale, 6, 12),
+ Math.Clamp(4 * softScale, 2, 6)
+ );
+
+ StatusTextBlock.FontSize = Math.Clamp(16 * softScale, 12, 22);
+ LoadingTextBlock.FontSize = Math.Clamp(14 * softScale, 11, 18);
+
+ foreach (var view in _dailyViews)
+ {
+ view.UpdateLayout(softScale, totalWidth - horizontalPadding * 2);
+ }
+
+ ApplyNightModeVisual();
+ }
+
+ private double ResolveScale()
+ {
+ var expectedWidth = _currentCellSize * BaseWidthCells;
+ var expectedHeight = _currentCellSize * BaseHeightCells;
+ if (expectedWidth <= 0 || expectedHeight <= 0)
+ {
+ return 1d;
+ }
+
+ var actualWidth = Bounds.Width > 1 ? Bounds.Width : expectedWidth;
+ var actualHeight = Bounds.Height > 1 ? Bounds.Height : expectedHeight;
+ var scaleX = actualWidth / expectedWidth;
+ var scaleY = actualHeight / expectedHeight;
+ return Math.Clamp(Math.Min(scaleX, scaleY), 0.72, 2.4);
+ }
+
+ private CornerRadius ResolveUnifiedMainRectangle() => new(ResolveUnifiedMainRadiusValue());
+
+ private static double ResolveUnifiedMainRadiusValue() =>
+ HostAppearanceThemeProvider.GetOrCreate().GetCurrent().CornerRadiusTokens.Lg.TopLeft;
+}
+
+// 数据模型
+public sealed record JuyaDailyNews(
+ DateTime Date,
+ string Title,
+ string CoverImageUrl,
+ string IssueUrl,
+ string BilibiliUrl,
+ string YoutubeUrl,
+ IReadOnlyList OverviewCategories,
+ IReadOnlyList DetailedNews,
+ DateTimeOffset FetchedAt);
+
+public sealed record JuyaOverviewCategory(
+ string Name,
+ string Icon,
+ IReadOnlyList Items);
+
+public sealed record JuyaOverviewItem(
+ string Title,
+ string Url,
+ int? Number);
+
+public sealed record JuyaDetailedNewsItem(
+ string Title,
+ int Number,
+ string BodyText,
+ IReadOnlyList RelatedLinks);
diff --git a/README.md b/README.md
index 89d8176..47ff11b 100644
--- a/README.md
+++ b/README.md
@@ -1,53 +1,133 @@
-# LanMountainDesktop
+# 阑山桌面 / LanMountainDesktop
-`LanMountainDesktop` is the authoritative host repository for the desktop app and the host-side Plugin SDK.
+> 你的桌面,不止一面
-## Repository Ownership
+[](https://dotnet.microsoft.com/)
+[](https://avaloniaui.net/)
+[](LICENSE)
-This repository owns:
+> [!IMPORTANT]
+> **温馨提示**:本项目有部分成分由**氛围编程 (Vibe Coding)** 方式编写。
+>
+> 如果您对此类项目有固有的排斥感,请无视此项目,谢谢。
-- `LanMountainDesktop/`: desktop host app and plugin runtime
-- `LanMountainDesktop.PluginSdk/`: canonical plugin API baseline (`4.0.0`)
-- `LanMountainDesktop.Shared.Contracts/`: shared host/plugin contract types
-- `LanMountainDesktop.Appearance/`: host appearance and radius token generation
-- `LanMountainDesktop.Settings.Core/`: host settings primitives
-- `LanMountainDesktop.Tests/`: host and SDK tests
+## 简介
-This repository does not own:
+**阑山桌面**是一个跨平台桌面环境增强工具,面向需要高频查看信息、追求桌面效率与个性化体验的用户。
-- plugin market metadata or developer portal content
-- official sample plugin release source
-- independent ecosystem documentation hub
+基于 Avalonia UI 和 .NET 10 构建,支持 Windows、Linux、macOS 三大平台。
-## Ecosystem Boundaries
+
+
+
-- Host and SDK source of truth: `LanMountainDesktop` (this repo)
-- Plugin market and developer materials: standalone `LanAirApp` repo
-- Official sample plugin source of truth: standalone `LanMountainDesktop.SamplePlugin` repo
-- `ClassIsland`: reference-only project, not part of build or release flow
+## 核心特性
-## Plugin SDK v4 Baseline
+### 📊 信息聚合
+- 课程表、日历、天气、新闻、热搜
+- 所有信息一目了然,无需频繁切换窗口
-- API baseline: `4.0.0`
-- Manifest file: `plugin.json`
-- Package extension: `.laapp`
-- Entry model: `Initialize(HostBuilderContext, IServiceCollection)`
-- Appearance model: `IPluginAppearanceContext`, `PluginAppearanceSnapshot`, `PluginCornerRadiusTokens`, `PluginCornerRadiusPreset`
-- Component registration model: `AddPluginDesktopComponent(PluginDesktopComponentOptions options)`
+### 🎯 效率工具
+- 自习环境监测、计时器、知识卡片
+- 最近文档、浏览器快捷入口
+- 常用工具组件一键触达
-## Plugin Package Surfaces
+### 🎨 个性化桌面
+- 自由布局,随心所欲摆放组件
+- 多页桌面,工作学习场景分离
+- 主题切换、玻璃效果、圆角风格
-- `LanMountainDesktop.PluginSdk`: official plugin SDK package (includes `buildTransitive` default `.laapp` packaging targets)
-- `LanMountainDesktop.Shared.Contracts`: shared contract package for host/plugin boundaries
-- `LanMountainDesktop.PluginTemplate`: official `dotnet new` template package (`shortName`: `lmd-plugin`)
+### 🔌 插件生态
+- 通过 `.laapp` 插件扩展功能
+- 官方 Plugin SDK 支持自定义组件
+- 设置页、组件、集成功能一站式接入
-Use `scripts/Pack-PluginPackages.ps1` to generate local-feed packages for CI or workspace integration tests.
+## 为谁而设计
-## Workspace Market Resolution
+| 用户类型 | 典型场景 |
+|---------|---------|
+| 🎓 学生用户 | 课程表、自习监测、计时、天气和日常信息聚合 |
+| 💼 办公用户 | 日历、资讯、最近文档、常用工具入口 |
+| 🎨 效率爱好者 | 自由布局、主题切换、插件扩展 |
+| 🇨🇳 中文用户 | 本地化界面、农历和节假日等本地语境支持 |
-For local market debugging, the host resolves workspace files from the sibling repository path (`..\\LanAirApp`) instead of reading the in-repo mirror folder.
+## 快速开始
+
+### 环境要求
+- .NET SDK 10
+
+### 构建与运行
+
+```bash
+# 还原依赖
+dotnet restore
+
+# 构建项目
+dotnet build LanMountainDesktop.slnx -c Debug
+
+# 运行桌面宿主
+dotnet run --project LanMountainDesktop/LanMountainDesktop.csproj
+```
+
+### 运行测试
+
+```bash
+dotnet test LanMountainDesktop.slnx -c Debug
+```
+
+## 插件开发
+
+阑山桌面支持通过 Plugin SDK 开发自定义插件:
+
+```bash
+# 安装插件模板
+dotnet new install LanMountainDesktop.PluginTemplate
+
+# 创建新插件
+dotnet new lmd-plugin -n MyPlugin
+```
+
+- **Plugin SDK**: `LanMountainDesktop.PluginSdk` (API 4.0.0)
+- **共享契约**: `LanMountainDesktop.Shared.Contracts`
+- **迁移指南**: [PLUGIN_SDK_V4_MIGRATION.md](docs/PLUGIN_SDK_V4_MIGRATION.md)
+
+## 项目结构
+
+```
+LanMountainDesktop/
+├── LanMountainDesktop/ # 桌面宿主应用
+├── LanMountainDesktop.PluginSdk/ # 官方插件 SDK
+├── LanMountainDesktop.Shared.Contracts/ # 宿主与插件共享契约
+├── LanMountainDesktop.Appearance/ # 主题与外观基础设施
+├── LanMountainDesktop.Settings.Core/# 设置持久化基础设施
+└── LanMountainDesktop.Tests/ # 测试项目
+```
+
+## 生态边界
+
+| 项目 | 职责 |
+|-----|------|
+| **本仓库** | 桌面宿主、插件运行时、Plugin SDK、共享契约 |
+| [LanAirApp](https://github.com/yourorg/LanAirApp) | 插件市场元数据、开发者生态材料 |
+| [LanMountainDesktop.SamplePlugin](https://github.com/yourorg/LanMountainDesktop.SamplePlugin) | 官方示例插件 |
+
+## 文档索引
+
+- [产品定位](docs/PRODUCT.md) - 产品愿景与目标用户
+- [架构说明](docs/ARCHITECTURE.md) - 仓库结构与运行时主线
+- [开发指南](docs/DEVELOPMENT.md) - 构建、测试、调试
+- [视觉规范](docs/VISUAL_SPEC.md) - 主题、颜色、玻璃层级
+- [圆角规范](docs/CORNER_RADIUS_SPEC.md) - 圆角层级与动态规则
+- [贡献指南](docs/CONTRIBUTING.md) - PR、spec、文档协作规则
+
+## 技术栈
+
+- **UI 框架**: [Avalonia UI](https://avaloniaui.net/)
+- **开发平台**: [.NET 10](https://dotnet.microsoft.com/)
+- **支持平台**: Windows 10+, Linux, macOS
+
+## 许可证
+
+[MIT](LICENSE)
-See:
-- `docs/ECOSYSTEM_BOUNDARIES.md`
-- `docs/PLUGIN_SDK_V4_MIGRATION.md`
diff --git a/docs/JUYA_NEWS_DESIGN.md b/docs/JUYA_NEWS_DESIGN.md
new file mode 100644
index 0000000..a0b0b7d
--- /dev/null
+++ b/docs/JUYA_NEWS_DESIGN.md
@@ -0,0 +1,556 @@
+# 橘鸦新闻组件 UI 设计文档
+
+## 1. 数据源分析
+
+### RSS 结构
+```xml
+-
+ 2026-03-23
+ https://imjuya.github.io/juya-ai-daily/issue-37/
+ AI 早报 2026-03-23 视频版...
+
+
+
AI 早报 2026-03-23
+ 视频版: B站链接 | YouTube链接
+ 要闻
+
+ - 微信正式推出ClawBot插件... #1
+
+ 开发者
+
+ - Claude Code 测试新功能... #2
+
+ ...更多分类
+ ]]>
+
+ Mon, 23 Mar 2026 00:34:38 +0000
+
+```
+
+### 推送时间规律
+- **推送时间**: 每天凌晨 00:30 - 02:00 (UTC+0)
+- **北京时间**: 每天上午 08:30 - 10:00
+- **历史数据**: RSS包含约30天的历史数据(从2026-02-18开始)
+- **更新频率**: 每日一期,一期多条新闻
+
+### 内容结构
+每期早报包含:
+1. **封面图片** - 每日独特的封面图
+2. **视频版链接** - B站和YouTube双平台
+3. **要闻** - 2-3条重要新闻
+4. **开发者** - 技术相关动态
+5. **产品发布** - 新产品/功能
+6. **模型发布** - AI模型更新
+7. **其他分类** - 投资、开源、研究等
+
+---
+
+## 2. 设计理念
+
+### 品牌调性
+- **橘鸦官网风格**: 柔和、温暖、阅读友好
+- **主色调**: 砖红色/陶土色 (#bb5649) - 来自官网
+- **背景色**: 米白色/奶油色 (#fefefe, #f8f5ec) - 柔和不刺眼
+- **文字色**: 深灰蓝 (#34495e) - 温和专业
+- **视觉风格**: 简洁优雅、阅读舒适、温暖亲切
+
+### 设计关键词
+- 柔和温暖
+- 阅读友好
+- 优雅简洁
+- 舒适护眼
+- **垂直连续滚动** ← 核心交互
+
+---
+
+## 3. 色彩方案 (参考橘鸦官网)
+
+### 官网色彩提取
+```
+官网主色 (砖红/陶土): #bb5649
+官网文字: #34495e
+官网背景: #fefefe
+官网次要背景: #f8f5ec (米黄/奶油)
+官网引用块背景: rgba(192,91,77,.05)
+官网引用块边框: rgba(192,91,77,.3)
+官网链接悬停: #bb5649
+官网元信息: #757575
+```
+
+### 日间模式 (Light Mode) - 柔和风格
+| 元素 | 颜色 | 用途 |
+|-----|------|------|
+| 卡片背景 | #fefefe | 主卡片底色 (官网背景色) |
+| 卡片边框 | #e6e6e6 | 细微边框 |
+| 品牌标题 | #bb5649 | "橘鸦" 文字 (官网主色) |
+| 日期标题 | #bb5649 | 日期大标题 |
+| 新闻标题 | #34495e | 新闻条目文字 |
+| 分类标签 | #bb5649 | 要闻/开发者等 |
+| 时间戳 | #757575 | 发布时间 |
+| 悬停背景 | rgba(192,91,77,.05) | 条目悬停效果 |
+| 分隔线 | #e6e6e6 | 日期分隔 |
+| 加载提示 | #757575 | 加载更多提示 |
+
+### 夜间模式 (Dark Mode) - 柔和暗色
+| 元素 | 颜色 | 用途 |
+|-----|------|------|
+| 卡片背景 | #2d2a2a | 深暖灰 |
+| 卡片边框 | #3d3a3a | 细微边框 |
+| 品牌标题 | #d4736a | 柔和砖红 |
+| 日期标题 | #d4736a | 日期大标题 |
+| 新闻标题 | #e8e4e0 | 新闻条目文字 |
+| 分类标签 | #d4736a | 要闻/开发者等 |
+| 时间戳 | #9a9590 | 次要信息 |
+| 悬停背景 | rgba(212,115,106,.1) | 条目悬停效果 |
+| 分隔线 | #3d3a3a | 日期分隔 |
+| 加载提示 | #9a9590 | 加载更多提示 |
+
+---
+
+## 4. 布局设计
+
+### 组件尺寸
+- **默认尺寸**: 4格宽 x 4格高
+- **最小尺寸**: 4格宽 x 4格高
+- **滚动方向**: 垂直滚动
+
+### 垂直连续滚动布局
+
+```
+┌─────────────────────────────────────────┐
+│ 🧱 橘鸦 · AI早报 [🔗 官网] │ ← Header (固定或随滚动)
+├─────────────────────────────────────────┤
+│ │
+│ ┌───────────────────────────────────┐ │
+│ │ 📰 封面图 2026-03-23 │ │ ← 今天的新闻
+│ │ │ │
+│ └───────────────────────────────────┘ │
+│ │
+│ # 2026年3月23日 星期一 │ ← 日期大标题
+│ │
+│ ## 📌 要闻 │
+│ • 微信正式推出ClawBot插件... │
+│ • OpenAI发布GPT-5.4预览版... │
+│ │
+│ ## 💻 开发者 │
+│ • Claude Code测试新功能... │
+│ • 阶跃星辰推出StepPlan... │
+│ │
+│ 📺 视频版: B站 | YouTube │
+│ │
+│ ───────────────────────────────────── │ ← 日期分隔线
+│ │
+│ ┌───────────────────────────────────┐ │
+│ │ 📰 封面图 2026-03-22 │ │ ← 昨天的新闻
+│ │ │ │ (往下滑动显示)
+│ └───────────────────────────────────┘ │
+│ │
+│ # 2026年3月22日 星期日 │
+│ │
+│ ## 📌 要闻 │
+│ • OpenAI发布GPT-5.4... │
+│ • Google推出新功能... │
+│ │
+│ ## 💻 开发者 │
+│ • Anthropic更新Claude... │
+│ │
+│ 📺 视频版: B站 | YouTube │
+│ │
+│ ───────────────────────────────────── │
+│ │
+│ ┌───────────────────────────────────┐ │ ← 前天的新闻
+│ │ 📰 封面图 2026-03-21 │ │ (继续往下滑动)
+│ │ │ │
+│ └───────────────────────────────────┘ │
+│ │
+│ # 2026年3月21日 星期六 │
+│ │
+│ ... │
+│ │
+│ ───────────────────────────────────── │
+│ │
+│ 正在加载更多... ↓ │ ← 加载提示
+│ │
+└─────────────────────────────────────────┘
+```
+
+### 日期分隔设计
+```
+┌─────────────────────────────────────────┐
+│ │
+│ ─────────── 3月22日 星期日 ─────────── │ ← 日期分隔条
+│ │
+│ [昨天的新闻内容] │
+│ │
+└─────────────────────────────────────────┘
+```
+
+### 单期新闻结构
+```
+┌─────────────────────────────────────────┐
+│ │
+│ [封面图 - 16:9 比例] │
+│ │
+│ # 2026年3月23日 星期一 │ ← 日期大标题
+│ │
+│ ## 📌 要闻 │ ← 分类标题
+│ • 新闻条目1 │
+│ • 新闻条目2 │
+│ │
+│ ## 💻 开发者 │
+│ • 新闻条目3 │
+│ • 新闻条目4 │
+│ │
+│ ## 🚀 产品发布 │
+│ • 新闻条目5 │
+│ │
+│ 📺 视频版: [B站] [YouTube] │ ← 视频链接
+│ │
+└─────────────────────────────────────────┘
+```
+
+---
+
+## 5. 字体规范
+
+### 字体族
+```xml
+FontFamily="MiSans VF, avares://LanMountainDesktop/Assets/Fonts#MiSans"
+```
+
+### 字号规范
+
+| 元素 | 字号 | 字重 | 说明 |
+|-----|------|------|------|
+| 品牌标题 | 20px | SemiBold | 顶部固定标题 |
+| 日期大标题 | 22px | Bold | 每期日期 |
+| 分类标题 | 16px | SemiBold | 要闻/开发者等 |
+| 新闻条目 | 14px | Regular | 主要阅读内容 |
+| 视频链接 | 13px | Regular | 底部视频入口 |
+| 加载提示 | 13px | Regular | 加载更多 |
+
+---
+
+## 6. 核心交互: 垂直连续滚动
+
+### 滚动行为
+```
+用户往下滑动
+ ↓
+显示今天的新闻内容
+ ↓
+继续往下滑动
+ ↓
+显示日期分隔线
+ ↓
+显示昨天的新闻内容
+ ↓
+继续往下滑动
+ ↓
+显示前天的新闻内容
+ ↓
+...
+ ↓
+到达已加载内容的底部
+ ↓
+显示"正在加载更多..."
+ ↓
+自动加载更早的新闻
+```
+
+### 加载策略
+```csharp
+// 初始加载: 最近3天的新闻
+// 滚动到底部: 自动加载接下来3天
+// 最大加载: 30天历史数据
+// 内存管理: 只保留可视区域 ±3 天的数据
+```
+
+### 滚动位置记忆
+```csharp
+// 记录用户当前滚动位置
+// 切换主题/刷新时不重置位置
+// 下次打开组件时恢复到上次位置
+```
+
+---
+
+## 7. 交互设计
+
+### 悬停效果
+```
+新闻条目悬停:
+- 背景色: 透明 → rgba(192,91,77,.05)
+- 过渡时间: 200ms
+- 光标: Hand cursor
+```
+
+### 点击效果
+```
+新闻条目点击:
+- 打开浏览器跳转原文链接
+- 轻微缩放: scale(0.98)
+- 过渡时间: 100ms
+```
+
+### 封面图点击
+```
+封面图点击:
+- 打开当期官网页面
+- 轻微放大效果
+```
+
+### 日期标题点击
+```
+日期标题点击:
+- 展开/收起该期新闻
+- 箭头图标旋转动画
+```
+
+---
+
+## 8. 动画效果
+
+### 滚动动画
+```
+内容跟随滚动:
+- 自然滚动,无额外动画
+- 保持流畅 60fps
+```
+
+### 加载动画
+```
+新内容加载:
+- 淡入: opacity 0 → 1 (300ms)
+- 缓动: ease-out
+```
+
+### 日期分隔线动画
+```
+日期分隔线进入视口:
+- 轻微放大: scale(0.95) → scale(1)
+- 透明度: 0.5 → 1
+- 时长: 200ms
+```
+
+---
+
+## 9. 响应式适配
+
+### 缩放规则
+```csharp
+scale = Math.Clamp(currentCellSize / 48, 0.56, 2.0)
+
+字体缩放: baseFontSize * scale
+间距缩放: baseSpacing * scale
+```
+
+### 最小尺寸保障
+```
+最小字体: 11px
+最小间距: 8px
+最小触摸区域: 44px
+```
+
+---
+
+## 10. 代码结构预览
+
+### XAML 结构
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### DailyNewsView 组件
+```xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+---
+
+## 11. 数据模型
+
+```csharp
+// 每日早报数据
+public sealed record JuyaDailyNews(
+ DateTime Date,
+ string Title,
+ string CoverImageUrl,
+ string IssueUrl,
+ string BilibiliUrl,
+ string YoutubeUrl,
+ IReadOnlyList Categories,
+ DateTimeOffset FetchedAt);
+
+// 新闻分类
+public sealed record JuyaNewsCategory(
+ string Name,
+ string Icon,
+ IReadOnlyList Items);
+
+// 单条新闻
+public sealed record JuyaNewsItem(
+ string Title,
+ string Url,
+ int? Number);
+```
+
+---
+
+## 12. 与现有组件对比
+
+| 特性 | CnrDailyNews | IfengNews | **JuyaNews (建议)** |
+|-----|--------------|-----------|---------------------|
+| 浏览方式 | 静态展示 | 静态展示 | **垂直连续滚动** |
+| 历史查看 | 不支持 | 不支持 | **下滑自动加载** |
+| 交互方式 | 点击刷新 | 点击刷新 | **滚动浏览** |
+| 内容组织 | 平铺 | 平铺 | **按日期分组** |
+
+---
+
+## 13. 设计亮点
+
+1. **垂直滚动**: 像社交媒体一样自然浏览
+2. **连续阅读**: 今天→昨天→前天,无缝衔接
+3. **日期分隔**: 清晰的日期标识,不会混淆
+4. **自动加载**: 滑到底部自动加载更多历史
+5. **柔和色彩**: 砖红色 + 米白色,阅读舒适
+6. **主题适配**: 日间/夜间模式都柔和护眼
+
+---
+
+## 14. 实现建议
+
+### 滚动加载实现
+```csharp
+public partial class JuyaNewsWidget : UserControl
+{
+ private readonly List _loadedNews = new();
+ private DateTime _earliestLoadedDate;
+ private bool _isLoadingMore;
+
+ private void OnScrollChanged(object? sender, ScrollChangedEventArgs e)
+ {
+ var scrollViewer = (ScrollViewer)sender!;
+
+ // 检测是否滚动到底部
+ if (scrollViewer.VerticalOffset >= scrollViewer.ScrollableHeight - 100)
+ {
+ LoadMoreNews();
+ }
+ }
+
+ private async void LoadMoreNews()
+ {
+ if (_isLoadingMore) return;
+ _isLoadingMore = true;
+
+ // 加载接下来3天的新闻
+ var nextBatch = await FetchNewsBatch(_earliestLoadedDate.AddDays(-1), 3);
+
+ foreach (var news in nextBatch)
+ {
+ AddNewsToView(news);
+ _loadedNews.Add(news);
+ }
+
+ _earliestLoadedDate = nextBatch.Last().Date;
+ _isLoadingMore = false;
+ }
+}
+```
+
+### 内存优化
+```csharp
+// 只保留可视区域附近的新闻
+// 远离可视区域的新闻释放图片资源
+// 保留文字内容,图片按需加载
+```
+
+---
+
+*设计版本: v4.0*
+*更新日期: 2026-03-24*
+*更新内容: 改为垂直连续滚动浏览模式*
diff --git a/docs/PRODUCT.md b/docs/PRODUCT.md
index 58828d6..aea1a7a 100644
--- a/docs/PRODUCT.md
+++ b/docs/PRODUCT.md
@@ -4,7 +4,7 @@
### 产品一句话
-阑山桌面是一个可编排的桌面信息与交互空间,面向需要高频查看信息、追求桌面效率与个性化体验的用户。
+阑山桌面——你的桌面,不止一面。
### 产品定位