Chandra
view release on metacpan or search on metacpan
examples/multiwindow_example.pl view on Meta::CPAN
sub render_todos {
my $theme = $store->get('theme', 'light');
my $is_dark = $theme eq 'dark';
my @visible = $filter eq 'all' ? @todos
: $filter eq 'active' ? grep { !$_->{done} } @todos
: grep { $_->{done} } @todos;
my $done_color = $is_dark ? '#666' : '#888';
my $items = join '', map {
my $id = $_->{id};
my $text = $_->{text};
my $checked = $_->{done} ? 'checked' : '';
my $strike = $_->{done} ? qq(style="text-decoration:line-through;color:$done_color") : '';
qq(<li>
<input type="checkbox" $checked
onchange="window.chandra.invoke('toggle',[$id])">
<span $strike>$text</span>
<button onclick="window.chandra.invoke('remove',[$id])">â</button>
</li>)
} @visible;
my $remaining = scalar grep { !$_->{done} } @todos;
my $total = scalar @todos;
my $all_active = $filter eq 'all' ? 'active' : '';
my $active_active = $filter eq 'active' ? 'active' : '';
my $done_active = $filter eq 'done' ? 'active' : '';
# Dark mode colors
my $bg = $is_dark ? '#1a1a2e' : '#fafafa';
my $toolbar_bg = $is_dark ? '#16213e' : '#fff';
my $toolbar_bdr = $is_dark ? '#0f3460' : '#eee';
my $btn_bg = $is_dark ? '#0f3460' : '#ecf0f1';
my $btn_fg = $is_dark ? '#eee' : '#333';
my $li_border = $is_dark ? '#0f3460' : '#f0f0f0';
my $li_fg = $is_dark ? '#eee' : 'inherit';
my $footer_fg = $is_dark ? '#888' : '#888';
my $del_btn = $is_dark ? '#555' : '#ccc';
return qq(
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: system-ui, sans-serif; margin: 0; background: $bg; color: $li_fg; }
h1 { background: #e74c3c; color: #fff; margin: 0; padding: 16px 20px; font-size: 1.4em; }
.toolbar { display:flex; gap:8px; padding:12px 20px; background:$toolbar_bg; border-bottom:1px solid $toolbar_bdr; }
button { cursor:pointer; border:none; border-radius:4px; padding:6px 12px; font-size:.9em; }
.btn-add { background:#e74c3c; color:#fff; }
.btn-settings { background:$btn_bg; color:$btn_fg; margin-left:auto; }
.filters { display:flex; gap:4px; }
.filters button { background:$btn_bg; color:$btn_fg; }
.filters button.active { background:#3498db; color:#fff; }
ul { list-style:none; margin:0; padding:0 20px; }
li { display:flex; align-items:center; gap:8px; padding:10px 0;
border-bottom:1px solid $li_border; }
li input[type=checkbox] { width:18px; height:18px; cursor:pointer; }
li span { flex:1; }
li button { background:transparent; color:$del_btn; font-size:1.1em; padding:2px 6px; }
li button:hover { color:#e74c3c; }
.footer { padding:12px 20px; color:$footer_fg; font-size:.85em; }
</style>
</head>
<body>
<h1>Todos</h1>
<div class="toolbar">
<button class="btn-add"
onclick="window.chandra.invoke('open_add', [])">+ Add Todo</button>
<div class="filters">
<button class="$all_active"
onclick="window.chandra.invoke('set_filter',['all'])">All</button>
<button class="$active_active"
onclick="window.chandra.invoke('set_filter',['active'])">Active</button>
<button class="$done_active"
onclick="window.chandra.invoke('set_filter',['done'])">Done</button>
</div>
<button class="btn-settings"
onclick="window.chandra.invoke('open_settings',[])">â Settings</button>
</div>
<ul>$items</ul>
<div class="footer">$remaining of $total item(s) remaining</div>
</body>
</html>
);
}
sub refresh_main {
$app->set_content(render_todos());
$app->refresh();
}
# -----------------------------------------------------------------------
# Main window bindings
# -----------------------------------------------------------------------
my $next_id = 1;
$app->bind('toggle', sub {
my ($id) = @_;
for my $t (@todos) {
$t->{done} = !$t->{done} if $t->{id} == $id;
}
$store->set('todos', \@todos);
refresh_main();
return undef;
});
$app->bind('remove', sub {
my ($id) = @_;
@todos = grep { $_->{id} != $id } @todos;
$store->set('todos', \@todos);
refresh_main();
return undef;
});
$app->bind('set_filter', sub {
my ($f) = @_;
$filter = $f;
refresh_main();
( run in 1.509 second using v1.01-cache-2.11-cpan-39bf76dae61 )