Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
121bc76
move common components to site_shared package
schultek Apr 7, 2026
aedd5a2
move tutorial and do some cleanup
schultek Apr 8, 2026
0f19aaa
move styles
schultek Apr 8, 2026
78d9219
adapt tutorial components for shared use
schultek Apr 8, 2026
01243a8
share styles_hash_builder
schultek Apr 13, 2026
068b597
remove unneeded deps
schultek Apr 13, 2026
eda96e2
move shared components in subfolder
schultek Apr 13, 2026
99ab0d2
create shared dash layout
schultek Apr 13, 2026
752434c
move extensions to shared package
schultek Apr 13, 2026
f7ebc71
fix formatting
schultek Apr 14, 2026
2b74570
add reset styles and banner component to shared package
schultek Apr 14, 2026
ed4f1e6
Merge branch 'main' into feat/site_shared
schultek Apr 28, 2026
bb0d4ed
apply review
schultek Apr 28, 2026
c4007b2
add readme
schultek Apr 28, 2026
64db575
Merge branch 'main' into feat/site_shared
parlough Jun 10, 2026
377473d
Standardize on consistent, YAML-based banner
parlough Jun 10, 2026
6d63215
Clean up new README formatting
parlough Jun 10, 2026
ee6bc94
Account for review suggestions
parlough Jun 10, 2026
52d5303
Merge branch 'main' into feat/site_shared
parlough Jun 14, 2026
a81822c
Encode rather than escape stylesheet hash
parlough Jun 14, 2026
ecc0789
Update sidenav handling for changes on main
parlough Jun 14, 2026
33679ad
Consistently end SCSS files with extra new line
parlough Jun 14, 2026
311f56d
Misc clean up
parlough Jun 14, 2026
9e7fc51
Auto organize imports
parlough Jun 14, 2026
91e9489
Reformat with latest beta
parlough Jun 14, 2026
8d09e24
Inline remaining member of site-specific util file
parlough Jun 14, 2026
e0ecac3
Consolidate analytics usage to shared version
parlough Jun 14, 2026
88b7126
Clean up print override styles
parlough Jun 14, 2026
67757be
Remove some now unused styles
parlough Jun 14, 2026
9abc493
Move progress ring styles like the other components
parlough Jun 14, 2026
e2d90db
Clean up progress ring implementation a bit
parlough Jun 14, 2026
c15106a
Add missing license headers
parlough Jun 14, 2026
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
48 changes: 48 additions & 0 deletions packages/site_shared/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# site_shared

This package is the core library containing
shared logic, UI components, and the design system for
the Dart and Flutter documentation sites.

It provides a centralized location for APIs,
user interface elements, and logic intended for use by
both the `dart.dev` and `docs.flutter.dev` websites.
Using a shared package ensures a consistent design language and
feature set across Dart and Flutter web documentation platforms.

## What's included

The `site_shared` package provides several key capabilities to
build documentation websites using Dart, Jaspr, and Jaspr Content:

- **UI components** (`lib/components`):
Reusable, modular components built for use across documentation pages.
- **Common components** (`lib/components/common`):
Everyday UI elements such as breadcrumbs, buttons, code blocks, and more.
- **Layout components** (`lib/components/layout`):
Structural layout elements like theme switchers,
site switchers, banners, and menu toggles.
- **Interactive components**:
Integrations such as Dartpad (`lib/components/dartpad`),
tutorials, and user client-side feedback tools.
- **Markdown extensions and processors** (`lib/extensions`):
Custom processors that hook into the Dart Markdown parser to
extend its default syntax and behavior, such as `attribute_processor.dart`.
- **Core styles** (`lib/_sass`):
The shared base styles and component-specific SCSS styling.
These resources define the unified visual identity used by both websites.
- **Utilities and builders** (`lib/src`):
Reusable logic for code syntax highlighting (`lib/src/highlight`),
analytics integrations (`lib/src/analytics`),
builders (`lib/src/builders`), and various helper utilities.

## Goals

The primary aims of this shared package are to:

1. Streamline styling and standardize UI component implementation
across our various websites.
1. Prevent code duplication between the
`dart-lang/site-www` and `flutter/website` repositories.
1. Establish a robust codebase that can be
updated, maintained, and improved in a unified way.
4 changes: 4 additions & 0 deletions packages/site_shared/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include: package:analysis_defaults/analysis.yaml

formatter:
trailing_commas: preserve
14 changes: 14 additions & 0 deletions packages/site_shared/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
builders:
stylesHashBuilder:
import: "package:site_shared/src/builders/styles_hash_builder.dart"
builder_factories: ["stylesHashBuilder"]
build_extensions:
"web/assets/css/main.css":
- "lib/src/style_hash.dart"
auto_apply: dependents
build_to: source
required_inputs:
- ".css"
defaults:
dev_options:
fixed_hash: true
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ button {
cursor: pointer;

&.filled-button,
&.text-button, &.outlined-button {
&.text-button,
&.outlined-button {
display: flex;
align-items: center;
width: fit-content;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@
}
}

&.install-card {
&.install-card {
gap: 0.25rem;

.card-leading {
Expand Down
26 changes: 26 additions & 0 deletions packages/site_shared/lib/_sass/components/_menu-toggle.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Toggle between menu and close buttons if sidenav is open or not.
body:not(.sidenav-closed) #menu-toggle {
@media (min-width: 1024px) {
display: none;
}
}

#menu-toggle span.material-symbols {
&:first-child {
display: inline;
}

&:last-child {
display: none;
}
}

body.open_menu #menu-toggle span.material-symbols {
&:first-child {
display: none;
}

&:last-child {
display: inline;
}
}
14 changes: 14 additions & 0 deletions packages/site_shared/lib/_sass/components/_progress-ring.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.progress-ring {
circle {
fill: none;
stroke-linecap: round;
}

.ring-inactive {
stroke: var(--site-inset-borderColor);
}

.ring-active {
stroke: var(--site-primary-color);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
@use '../base/mixins';

#site-switcher {
position: relative;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
}

// On non-touch devices, show tooltip on hover or focus.
@media all and not (pointer: coarse) {
@media all and (not (pointer: coarse)) {
&:hover .tooltip {
visibility: visible;
}
Expand All @@ -60,4 +60,4 @@
visibility: visible;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:meta/meta.dart';

import 'analytics_server.dart'
if (dart.library.js_interop) 'analytics_web.dart';
import 'src/analytics/analytics_server.dart'
if (dart.library.js_interop) 'src/analytics/analytics_web.dart';

/// Used to report analytic events.
final analytics = AnalyticsImplementation();
final Analytics analytics = AnalyticsImplementation();

/// Contains methods for reporting analytics events.
/// Used for reporting analytics events.
abstract class Analytics {
@internal
/// Reports an event named [eventName], along with the specified [parameters].
void sendEvent(String eventName, Map<String, Object?> parameters);

/// Reports whether the user found the current page [helpful].
void sendFeedback(bool helpful) {
sendEvent('feedback', {'feedback_type': helpful ? 'up' : 'down'});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ import 'material_icon.dart';
/// - https://schema.org/BreadcrumbList
/// - https://www.w3.org/TR/wai-aria-practices/examples/breadcrumb/index.html
class PageBreadcrumbs extends StatelessComponent {
const PageBreadcrumbs({super.key});
const PageBreadcrumbs({this.crumbs, super.key});

final List<BreadcrumbItem>? crumbs;

@override
Component build(BuildContext context) {
final crumbs = _breadcrumbsForPage(context.pages, context.page);
final crumbs =
this.crumbs ?? _breadcrumbsForPage(context.pages, context.page);
if (crumbs == null || crumbs.isEmpty) {
return const Component.empty();
}
Expand Down Expand Up @@ -54,7 +57,7 @@ class PageBreadcrumbs extends StatelessComponent {
///
/// Uses page metadata to generate breadcrumb titles with fallbacks:
/// `breadcrumb` > `shortTitle` > `title`.
List<_BreadcrumbItem>? _breadcrumbsForPage(List<Page> pages, Page page) {
List<BreadcrumbItem>? _breadcrumbsForPage(List<Page> pages, Page page) {
final pageUrl = page.url;

// Only show breadcrumbs if the URL isn't empty.
Expand All @@ -71,7 +74,7 @@ class PageBreadcrumbs extends StatelessComponent {
.toList(growable: false);
if (segments.isEmpty) return null;

final breadcrumbs = <_BreadcrumbItem>[];
final breadcrumbs = <BreadcrumbItem>[];
var currentPath = '';

// Build breadcrumbs for each segment except the current page.
Expand All @@ -88,7 +91,7 @@ class PageBreadcrumbs extends StatelessComponent {

if (indexPage.breadcrumb case final indexBreadcrumb?) {
breadcrumbs.add(
_BreadcrumbItem(
BreadcrumbItem(
title: indexBreadcrumb,
url: indexPage.url,
),
Expand All @@ -104,7 +107,7 @@ class PageBreadcrumbs extends StatelessComponent {

// Add the current page as the final breadcrumb.
breadcrumbs.add(
_BreadcrumbItem(
BreadcrumbItem(
title: pageBreadcrumb,
url: pageUrl,
),
Expand All @@ -127,8 +130,8 @@ extension on Page {
}
}

final class _BreadcrumbItem {
const _BreadcrumbItem({required this.title, required this.url});
final class BreadcrumbItem {
const BreadcrumbItem({required this.title, required this.url});

final String title;
final String url;
Expand All @@ -142,7 +145,7 @@ final class _BreadcrumbItemComponent extends StatelessComponent {
required this.isLast,
});

final _BreadcrumbItem crumb;
final BreadcrumbItem crumb;
final int index;
final bool isLast;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class Button extends StatelessComponent {
const Button({
super.key,
this.icon,
this.trailingIcon,
this.href,
this.content,
this.style = ButtonStyle.text,
Expand All @@ -30,6 +31,7 @@ class Button extends StatelessComponent {
final String? title;
final ButtonStyle style;
final String? icon;
final String? trailingIcon;
final String? id;
final String? href;
final Map<String, String> attributes;
Expand All @@ -48,14 +50,16 @@ class Button extends StatelessComponent {

final mergedClasses = [
style.cssClass,
if (icon != null && content == null) 'icon-button',
if ((icon != null || trailingIcon != null) && content == null)
'icon-button',
...?classes,
].toClasses;

final children = <Component>[
if (icon case final iconId?) MaterialIcon(iconId),
if (content case final contentText?)
asRaw ? RawText(contentText) : .text(contentText),
if (trailingIcon case final iconId?) MaterialIcon(iconId),
];

if (href case final href?) {
Expand Down Expand Up @@ -90,17 +94,3 @@ enum ButtonStyle {
ButtonStyle.text => 'text-button',
};
}

class SegmentedButton extends StatelessComponent {
const SegmentedButton({
super.key,
required this.children,
});

final List<Component> children;

@override
Component build(BuildContext context) {
return span(classes: ['segmented-button'].toClasses, children);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:jaspr/jaspr.dart';
import 'package:universal_web/web.dart' as web;

import '../../util.dart';
import '../util/global_event_listener.dart';
import '../utils/global_event_listener.dart';
import 'material_icon.dart';

/// A set of Material Design-like chips for configuration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// found in the LICENSE file.

import 'package:jaspr/jaspr.dart';

import 'package:universal_web/web.dart' as web;

import '../button.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,14 @@ import '../button.dart';
/// The cookie banner to show on a user's first time visiting the site.
@client
final class CookieNotice extends StatefulComponent {
const CookieNotice({super.key});
const CookieNotice({
super.key,
required this.host,
this.alwaysDarkMode = false,
});

final String host;
final bool alwaysDarkMode;

@override
State<CookieNotice> createState() => _CookieNoticeState();
Expand Down Expand Up @@ -60,13 +67,16 @@ final class _CookieNoticeState extends State<CookieNotice> {
Component build(BuildContext context) {
return section(
id: 'cookie-notice',
classes: [if (showNotice) 'show'].toClasses,
classes: [
if (showNotice) 'show',
if (component.alwaysDarkMode) 'always-dark-mode',
].toClasses,
attributes: {'data-nosnippet': 'true'},
[
div(classes: 'container', [
const p([
p([
.text(
'docs.flutter.dev uses cookies from Google to deliver and '
'${component.host} uses cookies from Google to deliver and '
'enhance the quality of its services and to analyze traffic.',
),
]),
Expand Down
Loading
Loading