fix: 优化 CSS 结构

This commit is contained in:
2026-04-21 00:15:57 +08:00
parent cf2f29cbd7
commit 4246061c29
13 changed files with 128 additions and 122 deletions

View File

@@ -1,42 +1,93 @@
# 贡献指南 # 贡献指南与二次开发
欢迎为此项目做出贡献!\ 欢迎为此项目做出贡献!
本项目是一个开源项目, 我们鼓励社区成员参与改进.
## 开发规范 ## 开发规范
1. 分支划分: 分支划分:
- `main` 分支: 稳定版本
- `dev` 分支: 开发版本 - `main` 分支: 稳定版本, 仅当稳定版本释出或修补版本时将 `dev` 合并到 `main`
- 功能分支: 从 `dev` 分支创建, 命名格式为 `feature/描述``fix/描述``refactor/描述` - `dev` 分支: 主线开发版本, 自身仅用于非重构的问题修复和整合功能分支
1. 代码风格: - 功能与重构分支: 从 `dev` 分支创建, 命名格式为 `feature/描述``fix/描述``refactor/v版本号`()
- 请使用 Black 格式化代码 - 不要将功能与重构分支先应被合并至 `dev` 后在 `dev` 完成文档开发后再释出至 `main`
- 遵循 PEP 8 规范 代码格式化:
- 添加适当的文档字符串 - 对于 Python, 使用 `black` 格式化
1. 提交消息: - 对于 Markdown, 使用 `mdformat` 格式化
- 对于 Textual CSS, 使用 `prettier` 格式化
- 格式化不是必需的, 可以整合入一次 `style` 提交, 但 `main``dev` 分支上的代码应尽量整洁, 以便合并时审查
提交消息:
- 使用简体中文或英文撰写清晰的提交消息 - 使用简体中文或英文撰写清晰的提交消息
- 格式: 遵循 Conventional Commits 规范 - 提交消息格式: 遵循 [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) 规范, 建议使用 `koji` 工具
1. 合并方式: 合并方式:
-使用 Fast-forward 合并 - 为了一致性和可追溯性, 项目自 v0.4.0 重构后重新初始化仓库起就禁止使用 Fast-forward 合并
- 可以设置 `git config merge.ff false` - 可以设置 `git config merge.ff false`
## 设置开发环境 ## 设置开发环境
```bash ```bash
# 克隆仓库 # 克隆仓库
git clone https://gitea.imwangzhiyu.xyz/ajax/HeurAMS git clone https://git.pluv27.top/pluv/HeurAMS
cd HeurAMS cd HeurAMS
# 可能需要切换分支 # 可能需要切换到 dev 分支
git checkout dev
# 安装依赖 # 如果决定使用 uv (推荐)
pip install -r requirements.txt
# 安装开发版本 ## 首先要安装uv, 例如通过 pip 或者其他包管理器
pip install -e . python3 -m pip install uv
uv sync # 同步开发运行环境
uv run heurams # 验证包安装
uv run tui # 启动 TUI
# 如果决定使用原生 python 环境 (不推荐, 但我们保留了这种方式以便在不支持 uv 的环境运行 HeurAMS)
## 安装依赖并将 HeurAMS 安装为本地包
python3 -m pip install -r requirements.txt
python3 -m pip install -e .
python3 -m heurams # 验证安装
python3 -m heurams.__interface__ # 启动 TUI
``` ```
## 许可证 ## 许可证与外部引用
贡献者同意其贡献将在 AGPL-3.0 许可证下发布. 贡献者拥有其贡献部分的版权同意其贡献将在 AGPL-3.0 许可证下发布.
如果您认为有必要引入其他开源的 vendor, 请在 PR 中注明或手动联系以便我们审查 vendor 许可证并更改此处和网站上的关于与版权声明
如果您认为有必要引入其他专有的网络服务(就像现在项目中的 edgetts), 请也在 PR 中注明
如果您认为有必要升级某个依赖或运行环境的版本, 请也在 PR 中注明
## 新的用户界面前端与其他语言移植
HeurAMS 被设计为一个可独立于前端的程序库, 这意味着:
- 我们的内置 Textual TUI 前端不是唯一可用的前端
- 您可以在自己的项目中以独立进程/服务调用 HeurAMS (但不能在代码中链接), 而免于受 AGPL-3.0 "污染"
- 如果您有一个自己开发的且可用的 HeurAMS 前端 (例如我们暂未实现的 flutter 前端), 并且以 AGPL-3.0/GPL-3.0 开放源代码, 可以联系我们将它转移到 HeurAMS 的官方仓库中以便共同维护, 您将保留您的版权并可主导该仓库下的开发工作 :)
- 如果您通过独立进程/服务调用方式开发了另外的软件, 开源但不愿使用 AGPL-3.0/GPL-3.0 许可证, 也可以联系我们, 我们乐于将您的项目链接添加到友链中
- 如果您想创建程序库的其他语言 (例如 dart) 版本以协助此语言下的方便集成, 并且同样以 AGPL-3.0/GPL-3.0 开放源代码, 也可以联系我们将它转移到 HeurAMS 的官方仓库中以便共同维护, 您将保留您的版权并可主导该仓库下的开发工作 :)
## 软件开发之外的贡献
即使您不是软件开发人员, 我们也欢迎您加入贡献!
您可以:
- 协助创建各种语言的翻译来翻译软件的界面 (但我们目前还没有 i18n 平台, 所以如果您想贡献翻译, 可能需要手动联系我们)
- 制作图像、主题、音效乃至制作开放的记忆单元集给其他用户使用
- 改进软件配套的文档
- 维护软件的开发/交流群组
- 给其他用户答疑解惑或分享自己的经验
- 在讨论区提出新想法或反馈问题
您的角色您来定!

View File

@@ -1,8 +1,8 @@
zmq_debug = true zmq_debug = false
_zmq_debug_desc = "[调试] ZeroMQ 调试服务器, 这会在 zmq_debug_port 上打开一个服务器\n调试工具可远程在 HeurAMS 内执行任意 python 代码, 无必要请关闭" _zmq_debug_desc = "[调试] ZeroMQ 调试服务器, 这会在 zmq_debug_port 上打开一个服务器\n调试工具可远程在 HeurAMS 内执行任意 python 代码, 无必要请关闭"
zmq_debug_port = 5555 zmq_debug_port = 5555
_zmq_debug_port_desc = "[调试] ZeroMQ 调试服务器端口" _zmq_debug_port_desc = "[调试] ZeroMQ 调试服务器端口"
enable_built_in_interface = false enable_built_in_interface = true
_enable_built_in_interface_desc = "启用内置基本用户界面\n(当且仅当 HeurAMS 作为程序库时禁用, 以跳过用户界面逻辑)" _enable_built_in_interface_desc = "启用内置基本用户界面\n(当且仅当 HeurAMS 作为程序库时禁用, 以跳过用户界面逻辑)"
_paths_desc = "用户数据路径定义" _paths_desc = "用户数据路径定义"

View File

@@ -1,14 +0,0 @@
# encoding=utf-8
import jieba
# jieba.enable_paddle()# 启动paddle模式。 0.40版之后开始支持,早期版本不支持
strs = ["我来到北京清华大学", "乒乓球拍卖完了", "中国科学技术大学"]
# for str in strs:
# seg_list = jieba.cut(str,use_paddle=True) # 使用paddle模式
# print("Paddle Mode: " + '/'.join(list(seg_list)))
seg_list = jieba.cut("秦孝公据崤函之固, 拥雍州之地", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
seg_list = jieba.cut("他来到了网易杭研大厦") # 默认是精确模式
print(", ".join(seg_list))

View File

@@ -1,15 +0,0 @@
# 运行时对象
Atom: 原子, 由核子, 电子, 轨道对象一并构成, 用于处理记忆所需一系列对象
Nucleon: 核子, 负责解析文件动态内容, 并储存记忆材料内容与谜题定义, 是静态只读但可临时覆盖内容的\
Electron: 电子, 负责处理记忆算法数据\
Orbital: 轨道, 储存记忆阶段信息与谜题阶段内出现配置
# 状态机对象
Transitions: 一种状态机框架库
Reactor: 状态机库
Phaser...
rating: 用户评估生成的值
quality: 用于单元反馈的值

View File

@@ -80,3 +80,4 @@ class HeurAMSApp(App):
def panic(self, *args): def panic(self, *args):
self._close_messages_no_wait() self._close_messages_no_wait()
raise self._exception raise self._exception

View File

@@ -2,22 +2,6 @@ NavigatorScreen {
align: center middle; align: center middle;
} }
.infview {
width: 5fr
}
.dataview {
width: 3fr
}
.repo_listitem {
layout: grid;
grid-size: 2;
}
.repo_listitem_btn {
dock: right;
offset: -5% 0
}
#dialog { #dialog {
grid-size: 2; grid-size: 2;
@@ -29,33 +13,3 @@ NavigatorScreen {
border: thick $background 80%; border: thick $background 80%;
background: $surface; background: $surface;
} }
#dashboardtop {
height: 4
}
#input-container {
height: 3;
margin-top: 1;
align: center middle;
}
.container {
height: auto;
padding: 0 0 1 0;
}
#message-input {
width: 1fr;
margin-right: 1;
}
#status-bar {
height: 1;
margin-top: 1;
text-style: italic;
color: $text-muted;
}
.session-label {
color: $primary;
text-style: bold;
}

View File

@@ -3,7 +3,7 @@
} }
#header { #header {
height: 4; height: 3;
} }
.repo-list-item { .repo-list-item {

View File

@@ -0,0 +1,27 @@
.foot {
align-vertical: bottom;
}
Switch {
dock: right;
}
Label {
width: auto
}
Select {
width: 55%;
dock: right;
}
Input {
width: 55%;
dock: right;
}
Horizontal {
width: 100%;
height: 4;
padding: 0 0 1 0;
}

View File

@@ -41,6 +41,7 @@ class AboutScreen(Screen):
API 版本代号: `{version.codename.capitalize()}` API 版本代号: `{version.codename.capitalize()}`
一个基于启发式算法与认知科学理论的辅助记忆调度器, 旨在帮助用户更高效地进行记忆工作与学习规划. 一个基于启发式算法与认知科学理论的辅助记忆调度器, 旨在帮助用户更高效地进行记忆工作与学习规划.
一个开放, 优雅, 易于扩展的间隔重复调度器实验平台, 旨在帮助研究者更高效地进行前沿记忆算法的研究.
以 AGPL-3.0 开放源代码, 这直接意味着任何个体直接基于此代码对外或内部提供的应用和服务, 无论本地或网络, 必须向所有用户公开完整修改后的源代码, 且继续沿用 AGPL-3.0 协议. 以 AGPL-3.0 开放源代码, 这直接意味着任何个体直接基于此代码对外或内部提供的应用和服务, 无论本地或网络, 必须向所有用户公开完整修改后的源代码, 且继续沿用 AGPL-3.0 协议.

View File

@@ -35,7 +35,7 @@ class DashboardScreen(Screen):
("q", "go_back", "返回"), ("q", "go_back", "返回"),
] ]
CSS_PATH = Path(__file__).parent.parent / "css" / "screens" / "dashboard.tcss" CSS_PATH = rootdir / 'interface' / "css" / "screens" / "dashboard.tcss"
def __init__( def __init__(
self, self,
@@ -53,10 +53,9 @@ class DashboardScreen(Screen):
with ScrollableContainer(): with ScrollableContainer():
yield Horizontal( # 顶部的状态 yield Horizontal( # 顶部的状态
Vertical( Vertical(
Label(f'欢迎使用 "潜进" 版本 {version.ver}'), Label(f"当前日时间戳: {timer.get_daystamp()}"),
Label(f"当前 UNIX 日时间戳: {timer.get_daystamp()}"),
Label( Label(
f"应用时区修正: UTC+{config_var.get()['services']['timer']['timezone_offset'] / 3600}" f"应用时区修正: UTC+{str(config_var.get()['services']['timer']['timezone_offset'] / 3600).rstrip('.0')}"
), ),
Label( Label(
f"默认算法设置: {config_var.get()['interface']['global']['algorithm']}" f"默认算法设置: {config_var.get()['interface']['global']['algorithm']}"
@@ -80,7 +79,7 @@ class DashboardScreen(Screen):
yield ListView(id="repo_list", classes="repo-list") # 单元集选择 yield ListView(id="repo_list", classes="repo-list") # 单元集选择
yield Label( yield Label(
f'"潜进" 启发式辅助记忆调度器 版本 {version.ver} {version.stage.capitalize()}' f'版本 {version.ver} {version.stage.capitalize()}'
) # 版本信息 ) # 版本信息
yield Footer() yield Footer()
@@ -107,6 +106,10 @@ class DashboardScreen(Screen):
"touched": 0, "touched": 0,
"have_activated_ever": 0, "have_activated_ever": 0,
} }
repo.preview = {
"review": 0,
"new": repo.config['scheduled_num'],
}
initial_time = float("inf") initial_time = float("inf")
for i in range(repo.data_length): for i in range(repo.data_length):
e = pt.Electron.from_data( e = pt.Electron.from_data(
@@ -118,11 +121,13 @@ class DashboardScreen(Screen):
repo.progress["have_activated_ever"] = 1 repo.progress["have_activated_ever"] = 1
repo.progress["touched"] += 1 repo.progress["touched"] += 1
repo.nearest_review_time = min(repo.nearest_review_time, e.nextdate()) repo.nearest_review_time = min(repo.nearest_review_time, e.nextdate())
if (timer.get_daystamp() >= e.nextdate()):
repo.preview['review'] += 1
# initial_time = min(initial_time, e.) # initial_time = min(initial_time, e.)
repo.need_review = timer.get_daystamp() >= repo.nearest_review_time repo.need_review = timer.get_daystamp() >= repo.nearest_review_time
repo.prompt = f"""{repo.manifest['title']} ({repo.config['algorithm']}) repo.prompt = f"""{repo.manifest['title']} \\[{repo.config['algorithm']}]
[d]进度: {repo.progress['touched']}/{repo.progress['total']} ({round(repo.progress['touched']/repo.progress['total']*100, 1)}%)[/d] [d]进度: {repo.progress['touched']}/{repo.progress['total']} ({round(repo.progress['touched']/repo.progress['total']*100, 1)}%)[/d]
[d]{'需要复习' if repo.need_review else ("暂未开始" if not repo.progress['have_activated_ever'] else '无需操作')}[/d]""" [d]{f'需要学习: {repo.preview['review']}R + {repo.preview['new']}U' if repo.need_review else (f"暂未开始: 0R + {repo.preview['new']}U" if not repo.progress['have_activated_ever'] else '无需操作')}[/d]"""
def on_mount(self) -> None: def on_mount(self) -> None:
"""挂载组件时初始化""" """挂载组件时初始化"""

View File

@@ -1,7 +1,7 @@
"""记忆准备界面""" """记忆准备界面"""
from textual.app import ComposeResult from textual.app import ComposeResult
from textual.containers import ScrollableContainer from textual.containers import ScrollableContainer, Container
from textual.reactive import reactive from textual.reactive import reactive
from textual.screen import Screen from textual.screen import Screen
from textual.widget import Widget from textual.widget import Widget
@@ -15,6 +15,7 @@ from textual.widgets import (
Rule, Rule,
Sparkline, Sparkline,
) )
from textual.lazy import Reveal, Lazy
import heurams.kernel.particles as pt import heurams.kernel.particles as pt
import heurams.services.hasher as hasher import heurams.services.hasher as hasher
@@ -46,7 +47,7 @@ class PreparationScreen(Screen):
def compose(self) -> ComposeResult: def compose(self) -> ComposeResult:
yield Header(show_clock=True) yield Header(show_clock=True)
with ScrollableContainer(id="vice_container"): with Reveal(ScrollableContainer(id="vice_container")):
yield Label(f"准备就绪: [b]{self.repo.manifest['title']}[/b]\n") yield Label(f"准备就绪: [b]{self.repo.manifest['title']}[/b]\n")
yield Label(f"[b]仓库路径: {self.repo.source}[/b]") yield Label(f"[b]仓库路径: {self.repo.source}[/b]")
yield Label(f"\n单元数量: {len(self.repo)}\n") yield Label(f"\n单元数量: {len(self.repo)}\n")

View File

@@ -44,6 +44,7 @@ class SettingScreen(Screen):
BINDINGS = [ BINDINGS = [
("q", "go_back", "返回"), ("q", "go_back", "返回"),
] ]
CSS_PATH = rootdir / 'interface' / "css" / "screens" / "setting.tcss"
def __init__( def __init__(
self, self,
@@ -66,6 +67,7 @@ class SettingScreen(Screen):
yield Collapsible( yield Collapsible(
*a, title=i + f'\n{config_var.get().get(f"_{i}_desc", "")}' *a, title=i + f'\n{config_var.get().get(f"_{i}_desc", "")}'
) )
yield Label("退出页面时, 所作的更改会立即保存, 但仍建议重启软件以确保新的配置得到应用", classes="foot")
yield Footer() yield Footer()
def _get_subcfg(self, parent_epath: str): def _get_subcfg(self, parent_epath: str):
@@ -112,7 +114,6 @@ class SettingScreen(Screen):
prompt=f'{parent.get(f"{i}", "")}', prompt=f'{parent.get(f"{i}", "")}',
id=domize(f"{parent_epath}.{i}"), id=domize(f"{parent_epath}.{i}"),
), ),
classes="container",
) )
) )
elif isinstance(parent[f"_{i}_candidate"], list): elif isinstance(parent[f"_{i}_candidate"], list):
@@ -124,7 +125,6 @@ class SettingScreen(Screen):
prompt=f'{parent.get(f"{i}", "")}', prompt=f'{parent.get(f"{i}", "")}',
id=domize(f"{parent_epath}.{i}"), id=domize(f"{parent_epath}.{i}"),
), ),
classes="container",
) )
) )
else: else:
@@ -138,7 +138,6 @@ class SettingScreen(Screen):
type="number", type="number",
id=domize(f"{parent_epath}.{i}"), id=domize(f"{parent_epath}.{i}"),
), ),
classes="container",
) )
) )
elif isinstance(parent[i], str): elif isinstance(parent[i], str):
@@ -151,7 +150,6 @@ class SettingScreen(Screen):
type="text", type="text",
id=domize(f"{parent_epath}.{i}"), id=domize(f"{parent_epath}.{i}"),
), ),
classes="container",
) )
) )
elif isinstance(parent[i], bool): elif isinstance(parent[i], bool):
@@ -161,7 +159,6 @@ class SettingScreen(Screen):
Switch( Switch(
value=parent[i], id=domize(f"{parent_epath}.{i}") value=parent[i], id=domize(f"{parent_epath}.{i}")
), ),
classes="container",
) )
) )
elif isinstance(parent[i], int): elif isinstance(parent[i], int):
@@ -174,7 +171,6 @@ class SettingScreen(Screen):
type="integer", type="integer",
id=domize(f"{parent_epath}.{i}"), id=domize(f"{parent_epath}.{i}"),
), ),
classes="container",
) )
) )
elif isinstance(parent[i], list): elif isinstance(parent[i], list):

View File

@@ -1,5 +1,4 @@
from .evalizor import Evalizer from .evalizor import Evalizer
from .lict import Lict from .lict import Lict
from .refvar import RefVar
__all__ = ["Evalizer", "Lict", "RefVar"] __all__ = ["Evalizer", "Lict"]