Chandra
view release on metacpan or search on metacpan
lib/Chandra/Theme.pm view on Meta::CPAN
}
a { color: var(--chandra-primary); text-decoration: none; }
a:hover { text-decoration: underline; }
code, pre, kbd {
font-family: var(--chandra-font-mono);
font-size: 0.9em;
}
pre {
background: var(--chandra-surface);
border: 1px solid var(--chandra-border);
border-radius: var(--chandra-radius);
padding: 12px 16px;
overflow-x: auto;
}
code {
background: var(--chandra-surface);
padding: 2px 6px;
border-radius: 3px;
}
pre code { background: none; padding: 0; }
hr {
border: none;
border-top: 1px solid var(--chandra-border);
margin: 16px 0;
}
h1, h2, h3, h4, h5, h6 {
margin: 24px 0 8px;
line-height: 1.25;
}
h1 { font-size: 2em; }
h2 { font-size: 1.5em; }
h3 { font-size: 1.25em; }
CSS
}
sub _component_css {
return <<'CSS';
/* ââ Buttons ââââââââââââââââââââââââââââââââââââââââââââ */
button, .chandra-btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 16px;
border: 1px solid var(--chandra-border);
border-radius: var(--chandra-radius);
background: var(--chandra-surface);
color: var(--chandra-text);
font-family: inherit;
font-size: inherit;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
}
button:hover, .chandra-btn:hover { background: var(--chandra-hover); }
button:disabled { opacity: 0.5; cursor: not-allowed; }
.chandra-btn-primary {
background: var(--chandra-primary);
color: #fff;
border-color: var(--chandra-primary);
}
.chandra-btn-primary:hover { opacity: 0.9; }
.chandra-btn-danger {
background: var(--chandra-danger);
color: #fff;
border-color: var(--chandra-danger);
}
.chandra-btn-secondary {
background: transparent;
border-color: var(--chandra-border);
}
/* ââ Inputs âââââââââââââââââââââââââââââââââââââââââââââ */
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="search"], input[type="url"],
input[type="tel"], input[type="date"], input[type="time"],
textarea, select {
padding: 6px 10px;
border: 1px solid var(--chandra-input-border);
border-radius: var(--chandra-radius);
background: var(--chandra-input-bg);
color: var(--chandra-text);
font-family: inherit;
font-size: inherit;
transition: border-color 0.15s, box-shadow 0.15s;
}
input:focus, textarea:focus, select:focus {
outline: none;
border-color: var(--chandra-primary);
box-shadow: 0 0 0 2px rgba(33, 150, 243, 0.2);
}
/* ââ Form fields (Chandra::Form) ââââââââââââââââââââââââ */
.chandra-form { display: flex; flex-direction: column; gap: 12px; }
.chandra-field { display: flex; flex-direction: column; gap: 4px; }
.chandra-label { font-weight: 500; font-size: 0.9em; color: var(--chandra-text-muted); }
.chandra-submit {
align-self: flex-start;
padding: 8px 24px;
background: var(--chandra-primary);
color: #fff;
border: none;
border-radius: var(--chandra-radius);
cursor: pointer;
font-weight: 500;
}
.chandra-submit:hover { opacity: 0.9; }
.chandra-error { color: var(--chandra-danger); font-size: 0.85em; }
.chandra-group { border: 1px solid var(--chandra-border); border-radius: var(--chandra-radius); padding: 12px; }
.chandra-group legend { font-weight: 600; padding: 0 6px; }
/* ââ Table (Chandra::Table) âââââââââââââââââââââââââââââ */
.chandra-table-wrap { font-family: inherit; }
.chandra-table { width: 100%; border-collapse: collapse; }
.chandra-table th, .chandra-table td {
padding: 8px 12px;
text-align: left;
border-bottom: 1px solid var(--chandra-border);
}
.chandra-table th {
background: var(--chandra-surface);
font-weight: 600;
user-select: none;
}
.chandra-table-sortable { cursor: pointer; }
.chandra-table-sortable:hover { background: var(--chandra-hover); }
.chandra-table-stripe { background: var(--chandra-surface); }
.chandra-table-selected { background: var(--chandra-selected) !important; }
.chandra-table-select { width: 40px; text-align: center; }
.chandra-table-empty, .chandra-table-loading {
text-align: center;
padding: 24px;
color: var(--chandra-text-muted);
}
.chandra-table-filters { padding: 8px 0; display: flex; gap: 8px; flex-wrap: wrap; }
.chandra-table-filter { font-size: 0.9em; }
.chandra-table-pagination {
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
padding: 12px 0;
}
.chandra-table-page-btn {
padding: 4px 10px;
font-size: 0.85em;
}
.chandra-table-page-active {
background: var(--chandra-primary) !important;
color: #fff;
border-color: var(--chandra-primary);
}
.chandra-table-info { margin-right: 12px; font-size: 0.85em; color: var(--chandra-text-muted); }
/* ââ Context menu âââââââââââââââââââââââââââââââââââââââ */
.chandra-context-menu {
background: var(--chandra-bg);
border: 1px solid var(--chandra-border);
border-radius: var(--chandra-radius);
box-shadow: var(--chandra-shadow);
padding: 4px 0;
min-width: 180px;
}
.chandra-context-menu-item {
padding: 6px 16px;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
}
.chandra-context-menu-item:hover { background: var(--chandra-hover); }
/* ââ Scrollbar (webkit) âââââââââââââââââââââââââââââââââ */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
background: var(--chandra-border);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover { background: var(--chandra-text-muted); }
CSS
}
1;
__END__
=head1 NAME
Chandra::Theme - CSS theme system for Chandra apps
=head1 SYNOPSIS
use Chandra::App;
use Chandra::Theme;
my $app = Chandra::App->new(title => 'My App');
# Built-in themes
Chandra::Theme->apply($app, 'dark');
Chandra::Theme->apply($app, 'light');
# Auto-detect OS preference
Chandra::Theme->apply($app, 'auto');
# Custom theme (merged with light as base)
Chandra::Theme->apply($app, {
primary => '#6200ea',
bg => '#fafafa',
surface => '#ffffff',
radius => '12px',
});
$app->run;
=head1 DESCRIPTION
C<Chandra::Theme> provides a CSS theme system using CSS custom properties.
It includes built-in light and dark themes, styles for all Chandra
components (Form, Table, ContextMenu), and base typography/reset styles.
=head1 CSS CUSTOM PROPERTIES
All tokens are available as C<--chandra-*> CSS variables:
( run in 0.815 second using v1.01-cache-2.11-cpan-140bd7fdf52 )