Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/config/theme.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,30 @@ Use your browser's DevTools to inspect elements and discover classes. Here are t
| `.badge` | Badge component |
| `.tree` | File tree component |

**Footer**

| Class | Element |
|-------|---------|
| `.footer` | Page footer container |
| `.footer-links` | Footer link groups grid |
| `.footer-link-group` | Individual link group column |
| `.footer-link-group-title` | Group heading (e.g. "Resources") |
| `.footer-copyright` | Copyright text |
| `.footer-social` | Social links row |
| `.footer-powered` | "Powered by Stardust" text |

**Announcement**

| Class | Element |
|-------|---------|
| `.announcement` | Announcement bar container |
| `.announcement-info` | Info style (primary color tint) |
| `.announcement-warning` | Warning style (amber tint) |
| `.announcement-success` | Success style (green tint) |
| `.announcement-content` | Announcement text/link |
| `.announcement-dismiss` | Dismiss button |
| `.announcement.dismissed` | Hidden state after dismiss |

**Navigation**

| Class | Element |
Expand Down
51 changes: 51 additions & 0 deletions lib/src/generator/builders/page_layout_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ class PageLayoutBuilder {

final socialLinks = _buildSocialLinks();
final logoHtml = _buildLogo();
final announcement = _buildAnnouncement();

return '''
$announcement
<header class="header">
<div class="header-inner">
<button class="mobile-menu-toggle" id="mobile-menu-toggle" aria-label="Toggle menu">
Expand Down Expand Up @@ -65,6 +67,31 @@ class PageLayoutBuilder {
''';
}

String _buildAnnouncement() {
final announcement = config.header.announcement;
if (announcement == null) return '';

final style = announcement.style;
final content = switch (announcement.link) {
final String link => '<a href="$link" class="announcement-content">${announcement.text}</a>',
null => '<span class="announcement-content">${announcement.text}</span>',
};
final dismissBtn = announcement.dismissible
? '''
<button class="announcement-dismiss" aria-label="Dismiss announcement">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18"/>
<line x1="6" y1="6" x2="18" y2="18"/>
</svg>
</button>'''
: '';

return '''
<div class="announcement announcement-$style" id="announcement">
$content$dismissBtn
</div>''';
}

String _buildLogo() {
final logo = config.logo;

Expand Down Expand Up @@ -317,9 +344,13 @@ class PageLayoutBuilder {

String buildFooter() {
final footerSocial = _buildFooterSocialLinks();
final footerLinks = _buildFooterLinks();
final copyright = config.footer.copyright;

return '''
<footer class="footer">
$footerLinks
${copyright != null ? '<div class="footer-copyright">$copyright</div>' : ''}
$footerSocial
<div class="footer-powered">
Powered by
Expand All @@ -332,6 +363,26 @@ class PageLayoutBuilder {
''';
}

String _buildFooterLinks() {
final links = config.footer.links;
if (links.isEmpty) return '';

final groups = links.map((group) {
final items =
group.items.map((item) => '<li><a href="${item.href}">${item.label}</a></li>').join('\n ');

return '''
<div class="footer-link-group">
<h4 class="footer-link-group-title">${group.group}</h4>
<ul>
$items
</ul>
</div>''';
}).join('\n');

return '<div class="footer-links">\n$groups\n </div>';
}

String _titleCase(String text) => text
.replaceAll('-', ' ')
.replaceAll('_', ' ')
Expand Down
16 changes: 16 additions & 0 deletions lib/src/generator/builders/page_scripts_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,22 @@ class PageScriptsBuilder {
});
}

const announcement = document.getElementById('announcement');
if (announcement) {
const text = announcement.textContent.trim();
const key = 'stardust-dismiss-' + text.substring(0, 50).replace(/\\s+/g, '-').toLowerCase();
if (localStorage.getItem(key) === 'dismissed') {
announcement.classList.add('dismissed');
}
const dismissBtn = announcement.querySelector('.announcement-dismiss');
if (dismissBtn) {
dismissBtn.addEventListener('click', () => {
announcement.classList.add('dismissed');
localStorage.setItem(key, 'dismissed');
});
}
}

document.querySelectorAll('.code-group').forEach(group => {
const buttons = group.querySelectorAll('.tab-button');
const panels = group.querySelectorAll('.tab-panel');
Expand Down
98 changes: 98 additions & 0 deletions lib/src/generator/builders/page_styles_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class PageStylesBuilder {
}

${_buildBaseStyles()}
${_buildAnnouncementStyles()}
${_buildHeaderStyles()}
${_buildSearchStyles()}
${_buildLayoutStyles()}
Expand Down Expand Up @@ -91,6 +92,59 @@ ${_buildCustomStyles()}
return '\n /* Custom styles */\n $buffer';
}

String _buildAnnouncementStyles() => '''
.announcement {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
padding: 0.5rem 1rem;
font-size: 0.8125rem;
font-weight: 500;
text-align: center;
}

.announcement-info {
background: color-mix(in srgb, var(--color-primary) 10%, var(--color-bg));
color: var(--color-primary);
}

.announcement-warning {
background: color-mix(in srgb, #f59e0b 10%, var(--color-bg));
color: #b45309;
}

.announcement-success {
background: color-mix(in srgb, #10b981 10%, var(--color-bg));
color: #059669;
}

.announcement-content {
color: inherit;
text-decoration: none;
}

.announcement-content:hover {
text-decoration: underline;
}

.announcement-dismiss {
background: none;
border: none;
color: inherit;
cursor: pointer;
padding: 0.25rem;
opacity: 0.7;
}

.announcement-dismiss:hover {
opacity: 1;
}

.announcement.dismissed {
display: none;
}''';

String _buildBaseStyles() => '''
* {
margin: 0;
Expand Down Expand Up @@ -2206,6 +2260,50 @@ ${_buildCustomStyles()}

.footer-powered a:hover {
color: var(--color-primary);
}

.footer-links {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 2rem;
width: 100%;
max-width: 90rem;
padding: 0 1.5rem;
margin-bottom: 2rem;
}

.footer-link-group-title {
font-size: 0.8125rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--color-text);
margin-bottom: 0.75rem;
}

.footer-links ul {
list-style: none;
}

.footer-links li {
margin-bottom: 0.375rem;
}

.footer-links a {
color: var(--color-text-secondary);
text-decoration: none;
font-size: 0.875rem;
transition: color 0.15s;
}

.footer-links a:hover {
color: var(--color-primary);
}

.footer-copyright {
font-size: 0.8125rem;
color: var(--color-text-secondary);
margin-bottom: 0.75rem;
}''';

String _buildSocialStyles() => '''
Expand Down
29 changes: 29 additions & 0 deletions stardust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,35 @@ sidebar:
- slug: deployment/netlify
label: Netlify

header:
announcement:
text: "Stardust v1.0 is here! A Dart-native docs generator with zero config."
link: https://github.com/nexlabstudio/stardust
dismissible: true
style: info

footer:
copyright: "© 2026 Nexlab Studio. All rights reserved."
links:
- group: Resources
items:
- label: Documentation
href: /
- label: Components
href: /components/callouts
- label: Quick Start
href: /quickstart
- group: Community
items:
- label: GitHub
href: https://github.com/nexlabstudio/stardust
- label: Issues
href: https://github.com/nexlabstudio/stardust/issues
- group: More
items:
- label: CLI Reference
href: /cli/init

theme:
colors:
primary: "#6366f1"
Expand Down
Loading