Rework flashcards library to match the rest of the app's visual language
Compared side-by-side against Dashboard, the library screen used entirely different visual primitives: a gradient primary button Dashboard doesn't use anywhere, per-row bordered cards with low contrast against the dark background, and a translucent pill badge instead of the icon-circle pattern used everywhere else (stat tiles, review queue, recent activity). - Study/Save/Commit import now use Dashboard's actual primary button style (flat ROYAL_BLUE, not the login/session-dialog gradient) - Added a stat-tile row (Due today / New available / Decks) using Dashboard's exact icon-circle + value + label construction, replacing the due/new counts previously crammed into the deck dropdown's text - The note list now lives in one bordered card with a section title (matching Dashboard's chart/list panels) instead of each row being its own separate low-contrast card - Per-row card-type indicator is now an icon circle (clipboard-list / notebook-pen) matching the Recent Activity list pattern, instead of a translucent color-coded pill badge
This commit is contained in:
+171
-52
@@ -6,6 +6,13 @@ const Cloze := preload("res://scripts/ui/flashcard_cloze.gd")
|
|||||||
|
|
||||||
var main
|
var main
|
||||||
|
|
||||||
|
var stats_row: HFlowContainer
|
||||||
|
var stat_due_value: Label
|
||||||
|
var stat_new_value: Label
|
||||||
|
var stat_decks_value: Label
|
||||||
|
var list_card: PanelContainer
|
||||||
|
var list_section_title: Label
|
||||||
|
|
||||||
var deck_selector: OptionButton
|
var deck_selector: OptionButton
|
||||||
var deck_ids: Array = []
|
var deck_ids: Array = []
|
||||||
var new_deck_button: Button
|
var new_deck_button: Button
|
||||||
@@ -56,17 +63,28 @@ func _ready() -> void:
|
|||||||
size_flags_vertical = Control.SIZE_EXPAND_FILL
|
size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
add_theme_constant_override("separation", 14)
|
add_theme_constant_override("separation", 14)
|
||||||
_build_dropdown_backdrop()
|
_build_dropdown_backdrop()
|
||||||
|
_build_stats()
|
||||||
_build_toolbar()
|
_build_toolbar()
|
||||||
_build_filters()
|
_build_filters()
|
||||||
status_label = Label.new()
|
status_label = Label.new()
|
||||||
status_label.add_theme_font_override("font", Brand.font)
|
status_label.add_theme_font_override("font", Brand.font)
|
||||||
add_child(status_label)
|
add_child(status_label)
|
||||||
|
|
||||||
|
list_card = PanelContainer.new()
|
||||||
|
list_card.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
|
list_card.add_theme_stylebox_override("panel", _list_card_box(UIThemeService.is_dark_mode()))
|
||||||
|
add_child(list_card)
|
||||||
|
var list_card_content := VBoxContainer.new()
|
||||||
|
list_card_content.add_theme_constant_override("separation", 10)
|
||||||
|
list_card.add_child(list_card_content)
|
||||||
|
list_section_title = _section_title("Your flashcards")
|
||||||
|
list_card_content.add_child(list_section_title)
|
||||||
list_scroll = ScrollContainer.new()
|
list_scroll = ScrollContainer.new()
|
||||||
list_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
list_scroll.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
add_child(list_scroll)
|
list_card_content.add_child(list_scroll)
|
||||||
list_container = VBoxContainer.new()
|
list_container = VBoxContainer.new()
|
||||||
list_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
list_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
list_container.add_theme_constant_override("separation", 8)
|
list_container.add_theme_constant_override("separation", 14)
|
||||||
list_scroll.add_child(list_container)
|
list_scroll.add_child(list_container)
|
||||||
debounce_timer = Timer.new()
|
debounce_timer = Timer.new()
|
||||||
debounce_timer.one_shot = true
|
debounce_timer.one_shot = true
|
||||||
@@ -93,6 +111,79 @@ func on_show(_payload: Variant = null) -> void:
|
|||||||
_reload_notes()
|
_reload_notes()
|
||||||
|
|
||||||
|
|
||||||
|
func _build_stats() -> void:
|
||||||
|
var previous_due := stat_due_value.text if stat_due_value != null else "--"
|
||||||
|
var previous_new := stat_new_value.text if stat_new_value != null else "--"
|
||||||
|
var previous_decks := stat_decks_value.text if stat_decks_value != null else "--"
|
||||||
|
if stats_row == null:
|
||||||
|
stats_row = HFlowContainer.new()
|
||||||
|
stats_row.add_theme_constant_override("separation", 24)
|
||||||
|
add_child(stats_row)
|
||||||
|
move_child(stats_row, 0)
|
||||||
|
for child in stats_row.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
stat_due_value = _add_stat(stats_row, "Due today", "clock-3", Brand.AMBER)
|
||||||
|
stat_new_value = _add_stat(stats_row, "New available", "clipboard-plus", Brand.ROYAL_BLUE)
|
||||||
|
stat_decks_value = _add_stat(stats_row, "Decks", "clipboard-list", Brand.PURPLE)
|
||||||
|
stat_due_value.text = previous_due
|
||||||
|
stat_new_value.text = previous_new
|
||||||
|
stat_decks_value.text = previous_decks
|
||||||
|
|
||||||
|
|
||||||
|
func _add_stat(row: HFlowContainer, title: String, icon_name: String, accent: Color) -> Label:
|
||||||
|
var dark := UIThemeService.is_dark_mode()
|
||||||
|
var cell := HBoxContainer.new()
|
||||||
|
cell.custom_minimum_size = Vector2(200, 56)
|
||||||
|
cell.add_theme_constant_override("separation", 12)
|
||||||
|
row.add_child(cell)
|
||||||
|
var icon_panel := PanelContainer.new()
|
||||||
|
icon_panel.custom_minimum_size = Vector2(48, 48)
|
||||||
|
icon_panel.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
icon_panel.add_theme_stylebox_override("panel", Brand.icon_circle_box(dark, accent, 24))
|
||||||
|
var icon := TextureRect.new()
|
||||||
|
icon.texture = load("res://assets/icons/lucide/%s.svg" % icon_name)
|
||||||
|
icon.custom_minimum_size = Vector2(22, 22)
|
||||||
|
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
|
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
|
icon_panel.add_child(icon)
|
||||||
|
cell.add_child(icon_panel)
|
||||||
|
var copy := VBoxContainer.new()
|
||||||
|
copy.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
var caption := Label.new()
|
||||||
|
caption.text = title
|
||||||
|
caption.add_theme_font_size_override("font_size", 13)
|
||||||
|
caption.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||||
|
copy.add_child(caption)
|
||||||
|
var value := Label.new()
|
||||||
|
value.text = "--"
|
||||||
|
value.add_theme_font_size_override("font_size", 24)
|
||||||
|
value.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||||
|
copy.add_child(value)
|
||||||
|
cell.add_child(copy)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
func _list_card_box(dark: bool) -> StyleBoxFlat:
|
||||||
|
var box := StyleBoxFlat.new()
|
||||||
|
box.bg_color = Color("081426") if dark else Color.WHITE
|
||||||
|
box.border_color = Color("26344f") if dark else Brand.LIGHT_BORDER
|
||||||
|
box.set_border_width_all(1)
|
||||||
|
box.set_corner_radius_all(8)
|
||||||
|
box.content_margin_left = 18
|
||||||
|
box.content_margin_right = 18
|
||||||
|
box.content_margin_top = 16
|
||||||
|
box.content_margin_bottom = 16
|
||||||
|
return box
|
||||||
|
|
||||||
|
|
||||||
|
func _section_title(text: String) -> Label:
|
||||||
|
var label := Label.new()
|
||||||
|
label.text = text
|
||||||
|
label.add_theme_font_size_override("font_size", 16)
|
||||||
|
label.add_theme_color_override("font_color", Brand.text_color(UIThemeService.is_dark_mode()))
|
||||||
|
return label
|
||||||
|
|
||||||
|
|
||||||
func _build_toolbar() -> void:
|
func _build_toolbar() -> void:
|
||||||
var row := HFlowContainer.new()
|
var row := HFlowContainer.new()
|
||||||
row.add_theme_constant_override("separation", 10)
|
row.add_theme_constant_override("separation", 10)
|
||||||
@@ -113,11 +204,7 @@ func _build_toolbar() -> void:
|
|||||||
study_button = Button.new()
|
study_button = Button.new()
|
||||||
study_button.text = "Study"
|
study_button.text = "Study"
|
||||||
study_button.custom_minimum_size = Vector2(110, 44)
|
study_button.custom_minimum_size = Vector2(110, 44)
|
||||||
study_button.add_theme_stylebox_override("normal", Brand.gradient_button_box())
|
_style_primary_button(study_button)
|
||||||
study_button.add_theme_stylebox_override("hover", Brand.gradient_button_box())
|
|
||||||
study_button.add_theme_stylebox_override("pressed", Brand.gradient_button_box())
|
|
||||||
study_button.add_theme_color_override("font_color", Color.WHITE)
|
|
||||||
study_button.add_theme_color_override("font_hover_color", Color.WHITE)
|
|
||||||
study_button.pressed.connect(_start_study)
|
study_button.pressed.connect(_start_study)
|
||||||
row.add_child(study_button)
|
row.add_child(study_button)
|
||||||
|
|
||||||
@@ -156,6 +243,19 @@ func _build_toolbar() -> void:
|
|||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
func _style_primary_button(button: Button) -> void:
|
||||||
|
var normal := StyleBoxFlat.new()
|
||||||
|
normal.bg_color = Brand.ROYAL_BLUE
|
||||||
|
normal.set_corner_radius_all(6)
|
||||||
|
var hover := normal.duplicate() as StyleBoxFlat
|
||||||
|
hover.bg_color = Color("3474ee")
|
||||||
|
button.add_theme_stylebox_override("normal", normal)
|
||||||
|
button.add_theme_stylebox_override("hover", hover)
|
||||||
|
button.add_theme_stylebox_override("pressed", normal)
|
||||||
|
button.add_theme_color_override("font_color", Color.WHITE)
|
||||||
|
button.add_theme_color_override("font_hover_color", Color.WHITE)
|
||||||
|
|
||||||
|
|
||||||
func _build_dropdown_backdrop() -> void:
|
func _build_dropdown_backdrop() -> void:
|
||||||
dropdown_backdrop = Control.new()
|
dropdown_backdrop = Control.new()
|
||||||
dropdown_backdrop.visible = false
|
dropdown_backdrop.visible = false
|
||||||
@@ -250,15 +350,22 @@ func _on_decks_changed(loaded_decks: Array) -> void:
|
|||||||
deck_selector.clear()
|
deck_selector.clear()
|
||||||
deck_selector.add_item("All decks")
|
deck_selector.add_item("All decks")
|
||||||
deck_ids = [""]
|
deck_ids = [""]
|
||||||
|
var total_due := 0
|
||||||
|
var total_new := 0
|
||||||
for summary in decks:
|
for summary in decks:
|
||||||
var deck: Dictionary = summary.get("deck", {})
|
var deck: Dictionary = summary.get("deck", {})
|
||||||
var label := "%s (%d due, %d new)" % [str(deck.get("name", "Deck")), int(summary.get("due", 0)), int(summary.get("new", 0))]
|
deck_selector.add_item(str(deck.get("name", "Deck")))
|
||||||
deck_selector.add_item(label)
|
|
||||||
deck_ids.append(str(deck.get("id", "")))
|
deck_ids.append(str(deck.get("id", "")))
|
||||||
|
total_due += int(summary.get("due", 0))
|
||||||
|
total_new += int(summary.get("new", 0))
|
||||||
if previous_selection != null:
|
if previous_selection != null:
|
||||||
var restored := deck_ids.find(previous_selection)
|
var restored := deck_ids.find(previous_selection)
|
||||||
if restored >= 0:
|
if restored >= 0:
|
||||||
deck_selector.select(restored)
|
deck_selector.select(restored)
|
||||||
|
if stat_due_value != null:
|
||||||
|
stat_due_value.text = str(total_due)
|
||||||
|
stat_new_value.text = str(total_new)
|
||||||
|
stat_decks_value.text = str(decks.size())
|
||||||
|
|
||||||
|
|
||||||
func _selected_deck_id() -> String:
|
func _selected_deck_id() -> String:
|
||||||
@@ -288,35 +395,56 @@ func _on_notes_loaded(response: Dictionary) -> void:
|
|||||||
func _render_notes() -> void:
|
func _render_notes() -> void:
|
||||||
for child in list_container.get_children():
|
for child in list_container.get_children():
|
||||||
child.queue_free()
|
child.queue_free()
|
||||||
status_label.text = "" if notes.size() > 0 else "No flashcards match these filters yet."
|
var dark := UIThemeService.is_dark_mode()
|
||||||
for note in notes:
|
if list_section_title != null:
|
||||||
list_container.add_child(_note_row(note))
|
list_section_title.text = "Your flashcards (%d)" % notes.size()
|
||||||
|
status_label.text = ""
|
||||||
|
if notes.is_empty():
|
||||||
|
var empty_label := Label.new()
|
||||||
|
empty_label.text = "No flashcards match these filters yet."
|
||||||
|
empty_label.add_theme_color_override("font_color", Brand.muted_color(dark))
|
||||||
|
list_container.add_child(empty_label)
|
||||||
|
return
|
||||||
|
for index in notes.size():
|
||||||
|
if index > 0:
|
||||||
|
list_container.add_child(_row_separator(dark))
|
||||||
|
list_container.add_child(_note_row(notes[index]))
|
||||||
|
|
||||||
|
|
||||||
func _note_row(note: Dictionary) -> Control:
|
func _note_row(note: Dictionary) -> Control:
|
||||||
var dark := UIThemeService.is_dark_mode()
|
var dark := UIThemeService.is_dark_mode()
|
||||||
var card := PanelContainer.new()
|
var type_str := str(note.get("type", "basic"))
|
||||||
var card_box := Brand.content_card_box(dark, false, Brand.ROYAL_BLUE)
|
var accent := Brand.TEAL if type_str == "cloze" else Brand.ROYAL_BLUE
|
||||||
card_box.content_margin_left = 16
|
|
||||||
card_box.content_margin_right = 16
|
|
||||||
card_box.content_margin_top = 14
|
|
||||||
card_box.content_margin_bottom = 14
|
|
||||||
card.add_theme_stylebox_override("panel", card_box)
|
|
||||||
var row := BoxContainer.new()
|
var row := BoxContainer.new()
|
||||||
row.vertical = compact_layout
|
row.vertical = compact_layout
|
||||||
row.add_theme_constant_override("separation", 12)
|
row.add_theme_constant_override("separation", 14)
|
||||||
card.add_child(row)
|
|
||||||
|
var icon_panel := PanelContainer.new()
|
||||||
|
icon_panel.custom_minimum_size = Vector2(40, 40)
|
||||||
|
icon_panel.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
icon_panel.add_theme_stylebox_override("panel", Brand.icon_circle_box(dark, accent, 20))
|
||||||
|
var icon := TextureRect.new()
|
||||||
|
icon.texture = load("res://assets/icons/lucide/%s.svg" % ("notebook-pen" if type_str == "cloze" else "clipboard-list"))
|
||||||
|
icon.custom_minimum_size = Vector2(18, 18)
|
||||||
|
icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
|
icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
|
icon_panel.add_child(icon)
|
||||||
|
row.add_child(icon_panel)
|
||||||
|
|
||||||
var content := VBoxContainer.new()
|
var content := VBoxContainer.new()
|
||||||
content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
content.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
content.add_theme_constant_override("separation", 6)
|
content.add_theme_constant_override("separation", 4)
|
||||||
row.add_child(content)
|
row.add_child(content)
|
||||||
var type_str := str(note.get("type", "basic"))
|
|
||||||
|
|
||||||
var header_row := HBoxContainer.new()
|
var header_row := HBoxContainer.new()
|
||||||
header_row.add_theme_constant_override("separation", 8)
|
header_row.add_theme_constant_override("separation", 8)
|
||||||
content.add_child(header_row)
|
content.add_child(header_row)
|
||||||
header_row.add_child(_type_badge(type_str, dark))
|
var type_label := Label.new()
|
||||||
|
type_label.text = type_str.capitalize()
|
||||||
|
type_label.add_theme_font_size_override("font_size", 12)
|
||||||
|
type_label.add_theme_color_override("font_color", accent)
|
||||||
|
header_row.add_child(type_label)
|
||||||
var tags: Array = note.get("tags", [])
|
var tags: Array = note.get("tags", [])
|
||||||
if tags.size() > 0:
|
if tags.size() > 0:
|
||||||
var tags_label := Label.new()
|
var tags_label := Label.new()
|
||||||
@@ -333,13 +461,17 @@ func _note_row(note: Dictionary) -> Control:
|
|||||||
prompt_label.add_theme_font_override("font", Brand.font)
|
prompt_label.add_theme_font_override("font", Brand.font)
|
||||||
content.add_child(prompt_label)
|
content.add_child(prompt_label)
|
||||||
|
|
||||||
|
var actions := HBoxContainer.new()
|
||||||
|
actions.add_theme_constant_override("separation", 8)
|
||||||
|
row.add_child(actions)
|
||||||
|
|
||||||
var edit_button := Button.new()
|
var edit_button := Button.new()
|
||||||
edit_button.text = "Edit"
|
edit_button.text = "Edit"
|
||||||
edit_button.custom_minimum_size = Vector2(70, 40)
|
edit_button.custom_minimum_size = Vector2(70, 40)
|
||||||
edit_button.add_theme_stylebox_override("normal", Brand.secondary_button_box(dark))
|
edit_button.add_theme_stylebox_override("normal", Brand.secondary_button_box(dark))
|
||||||
edit_button.add_theme_stylebox_override("hover", Brand.secondary_button_box(dark, true))
|
edit_button.add_theme_stylebox_override("hover", Brand.secondary_button_box(dark, true))
|
||||||
edit_button.pressed.connect(_open_editor.bind(str(note.get("id", "")), note))
|
edit_button.pressed.connect(_open_editor.bind(str(note.get("id", "")), note))
|
||||||
row.add_child(edit_button)
|
actions.add_child(edit_button)
|
||||||
|
|
||||||
var archive_button := Button.new()
|
var archive_button := Button.new()
|
||||||
archive_button.text = "Archive"
|
archive_button.text = "Archive"
|
||||||
@@ -351,30 +483,16 @@ func _note_row(note: Dictionary) -> Control:
|
|||||||
FlashcardService.archive_notes([str(note.get("id", ""))], true)
|
FlashcardService.archive_notes([str(note.get("id", ""))], true)
|
||||||
await get_tree().create_timer(0.3).timeout
|
await get_tree().create_timer(0.3).timeout
|
||||||
_reload_notes())
|
_reload_notes())
|
||||||
row.add_child(archive_button)
|
actions.add_child(archive_button)
|
||||||
|
|
||||||
return card
|
return row
|
||||||
|
|
||||||
|
|
||||||
func _type_badge(type_str: String, dark: bool) -> PanelContainer:
|
func _row_separator(dark: bool) -> ColorRect:
|
||||||
var accent := Brand.TEAL if type_str == "cloze" else Brand.ROYAL_BLUE
|
var line := ColorRect.new()
|
||||||
var badge := PanelContainer.new()
|
line.custom_minimum_size = Vector2(0, 1)
|
||||||
var box := StyleBoxFlat.new()
|
line.color = Color("1c2b49") if dark else Brand.LIGHT_BORDER
|
||||||
box.bg_color = Color(accent, 0.16 if dark else 0.12)
|
return line
|
||||||
box.border_color = accent
|
|
||||||
box.set_border_width_all(1)
|
|
||||||
box.set_corner_radius_all(8)
|
|
||||||
box.content_margin_left = 8
|
|
||||||
box.content_margin_right = 8
|
|
||||||
box.content_margin_top = 2
|
|
||||||
box.content_margin_bottom = 2
|
|
||||||
badge.add_theme_stylebox_override("panel", box)
|
|
||||||
var label := Label.new()
|
|
||||||
label.text = type_str.capitalize()
|
|
||||||
label.add_theme_font_size_override("font_size", 11)
|
|
||||||
label.add_theme_color_override("font_color", accent)
|
|
||||||
badge.add_child(label)
|
|
||||||
return badge
|
|
||||||
|
|
||||||
|
|
||||||
# ---------- Note editor ----------
|
# ---------- Note editor ----------
|
||||||
@@ -464,11 +582,7 @@ func _build_editor_overlay() -> void:
|
|||||||
var save_button := Button.new()
|
var save_button := Button.new()
|
||||||
save_button.text = "Save"
|
save_button.text = "Save"
|
||||||
save_button.custom_minimum_size = Vector2(0, 46)
|
save_button.custom_minimum_size = Vector2(0, 46)
|
||||||
save_button.add_theme_stylebox_override("normal", Brand.gradient_button_box())
|
_style_primary_button(save_button)
|
||||||
save_button.add_theme_stylebox_override("hover", Brand.gradient_button_box())
|
|
||||||
save_button.add_theme_stylebox_override("pressed", Brand.gradient_button_box())
|
|
||||||
save_button.add_theme_color_override("font_color", Color.WHITE)
|
|
||||||
save_button.add_theme_color_override("font_hover_color", Color.WHITE)
|
|
||||||
save_button.pressed.connect(_save_editor)
|
save_button.pressed.connect(_save_editor)
|
||||||
content.add_child(save_button)
|
content.add_child(save_button)
|
||||||
|
|
||||||
@@ -635,7 +749,7 @@ func _build_import_overlay() -> void:
|
|||||||
import_commit_button.text = "Commit import"
|
import_commit_button.text = "Commit import"
|
||||||
import_commit_button.custom_minimum_size = Vector2(0, 46)
|
import_commit_button.custom_minimum_size = Vector2(0, 46)
|
||||||
import_commit_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
import_commit_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
Style.style_primary_button(import_commit_button)
|
_style_primary_button(import_commit_button)
|
||||||
import_commit_button.pressed.connect(_commit_pending_import)
|
import_commit_button.pressed.connect(_commit_pending_import)
|
||||||
actions.add_child(import_commit_button)
|
actions.add_child(import_commit_button)
|
||||||
|
|
||||||
@@ -703,6 +817,11 @@ func _refresh_status() -> void:
|
|||||||
export_menu.add_theme_stylebox_override("panel", Brand.panel_box(dark))
|
export_menu.add_theme_stylebox_override("panel", Brand.panel_box(dark))
|
||||||
if import_menu != null:
|
if import_menu != null:
|
||||||
import_menu.add_theme_stylebox_override("panel", Brand.panel_box(dark))
|
import_menu.add_theme_stylebox_override("panel", Brand.panel_box(dark))
|
||||||
|
if list_card != null:
|
||||||
|
list_card.add_theme_stylebox_override("panel", _list_card_box(dark))
|
||||||
|
if list_section_title != null:
|
||||||
|
list_section_title.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||||
|
_build_stats()
|
||||||
_render_notes()
|
_render_notes()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -34,17 +34,23 @@ func _run() -> void:
|
|||||||
theme_service.set_dark_mode(true)
|
theme_service.set_dark_mode(true)
|
||||||
hub._render_notes()
|
hub._render_notes()
|
||||||
await process_frame
|
await process_frame
|
||||||
var dark_card := hub.list_container.get_child(0) as PanelContainer
|
var dark_list_box := hub.list_card.get_theme_stylebox("panel") as StyleBoxFlat
|
||||||
var dark_box := dark_card.get_theme_stylebox("panel") as StyleBoxFlat
|
_assert(dark_list_box.bg_color.is_equal_approx(Color("081426")),
|
||||||
_assert(dark_box.bg_color.is_equal_approx(Brand.content_card_box(true, false, Brand.ROYAL_BLUE).bg_color),
|
"the flashcards list card should use the dark surface while dark mode is active")
|
||||||
"flashcard note cards should use the dark surface while dark mode is active")
|
var dark_row := hub.list_container.get_child(0) as BoxContainer
|
||||||
|
var dark_icon_box := (dark_row.get_child(0) as PanelContainer).get_theme_stylebox("panel") as StyleBoxFlat
|
||||||
|
_assert(dark_icon_box.bg_color.is_equal_approx(Brand.icon_circle_box(true, Brand.ROYAL_BLUE, 20).bg_color),
|
||||||
|
"a basic card's type icon should use its dark accent styling")
|
||||||
|
|
||||||
theme_service.set_dark_mode(false)
|
theme_service.set_dark_mode(false)
|
||||||
await process_frame
|
await process_frame
|
||||||
var light_card := hub.list_container.get_child(0) as PanelContainer
|
var light_list_box := hub.list_card.get_theme_stylebox("panel") as StyleBoxFlat
|
||||||
var light_box := light_card.get_theme_stylebox("panel") as StyleBoxFlat
|
_assert(light_list_box.bg_color.is_equal_approx(Color.WHITE),
|
||||||
_assert(light_box.bg_color.is_equal_approx(Brand.content_card_box(false, false, Brand.ROYAL_BLUE).bg_color),
|
"toggling the app theme should rebuild the flashcards list card with the light surface (the library screen's theme_changed handler was previously a no-op)")
|
||||||
"toggling the app theme should rebuild flashcard note cards with the light surface (the library screen's theme_changed handler was previously a no-op)")
|
var light_row := hub.list_container.get_child(0) as BoxContainer
|
||||||
|
var light_icon_box := (light_row.get_child(0) as PanelContainer).get_theme_stylebox("panel") as StyleBoxFlat
|
||||||
|
_assert(light_icon_box.bg_color.is_equal_approx(Brand.icon_circle_box(false, Brand.ROYAL_BLUE, 20).bg_color),
|
||||||
|
"a basic card's type icon should use its light accent styling")
|
||||||
var light_menu_box := hub.export_menu.get_theme_stylebox("panel") as StyleBoxFlat
|
var light_menu_box := hub.export_menu.get_theme_stylebox("panel") as StyleBoxFlat
|
||||||
_assert(light_menu_box.bg_color.is_equal_approx(Brand.panel_box(false).bg_color),
|
_assert(light_menu_box.bg_color.is_equal_approx(Brand.panel_box(false).bg_color),
|
||||||
"the export menu panel should also restyle to the light surface after a theme toggle")
|
"the export menu panel should also restyle to the light surface after a theme toggle")
|
||||||
@@ -55,17 +61,16 @@ func _run() -> void:
|
|||||||
hub._update_responsive_layout()
|
hub._update_responsive_layout()
|
||||||
await process_frame
|
await process_frame
|
||||||
_assert(hub.compact_layout, "the flashcards library should detect a phone-width viewport")
|
_assert(hub.compact_layout, "the flashcards library should detect a phone-width viewport")
|
||||||
var compact_card := hub.list_container.get_child(0) as PanelContainer
|
var compact_row := hub.list_container.get_child(0) as BoxContainer
|
||||||
var compact_row := compact_card.get_child(0) as BoxContainer
|
|
||||||
_assert(compact_row.vertical, "phone-width flashcard rows should stack their content above the edit/archive actions instead of clipping")
|
_assert(compact_row.vertical, "phone-width flashcard rows should stack their content above the edit/archive actions instead of clipping")
|
||||||
_assert(compact_card.get_combined_minimum_size().x <= hub.size.x,
|
_assert(compact_row.get_combined_minimum_size().x <= hub.size.x,
|
||||||
"a phone-width flashcard row should fit inside the viewport (minimum %.1f px)" % compact_card.get_combined_minimum_size().x)
|
"a phone-width flashcard row should fit inside the viewport (minimum %.1f px)" % compact_row.get_combined_minimum_size().x)
|
||||||
|
|
||||||
hub.size = Vector2(1280, 800)
|
hub.size = Vector2(1280, 800)
|
||||||
hub._update_responsive_layout()
|
hub._update_responsive_layout()
|
||||||
await process_frame
|
await process_frame
|
||||||
_assert(not hub.compact_layout, "a wide viewport should restore the flashcards library's desktop row layout")
|
_assert(not hub.compact_layout, "a wide viewport should restore the flashcards library's desktop row layout")
|
||||||
var wide_row := (hub.list_container.get_child(0) as PanelContainer).get_child(0) as BoxContainer
|
var wide_row := hub.list_container.get_child(0) as BoxContainer
|
||||||
_assert(not wide_row.vertical, "a wide viewport should lay flashcard row content out horizontally again")
|
_assert(not wide_row.vertical, "a wide viewport should lay flashcard row content out horizontally again")
|
||||||
|
|
||||||
hub.free()
|
hub.free()
|
||||||
|
|||||||
Reference in New Issue
Block a user