Skip to content

Commit 429c2b0

Browse files
committed
Wrap the page header and add share button
1 parent 1224648 commit 429c2b0

File tree

15 files changed

+364
-85
lines changed

15 files changed

+364
-85
lines changed

site/lib/_sass/base/_base.scss

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,12 @@ h1, h2, h3, h4, h5, h6 {
3030

3131
h1, .h1 {
3232
font-family: var(--site-ui-fontFamily);
33-
font-size: 3rem;
33+
font-size: 2.75rem;
34+
font-weight: 500;
3435
margin-top: 0;
3536
margin-bottom: 0;
3637
}
3738

38-
.material-symbols {
39-
font-family: var(--site-icon-fontFamily);
40-
font-weight: normal;
41-
font-style: normal;
42-
font-size: 24px;
43-
line-height: 1;
44-
letter-spacing: normal;
45-
text-transform: none;
46-
display: inline-block;
47-
white-space: nowrap;
48-
word-wrap: normal;
49-
direction: ltr;
50-
-webkit-font-feature-settings: 'liga';
51-
-webkit-font-smoothing: antialiased;
52-
}
53-
5439
h2, .h2 {
5540
font-size: 1.5rem;
5641
}
@@ -71,6 +56,22 @@ h6, .h6 {
7156
font-size: 0.9375rem;
7257
}
7358

59+
.material-symbols {
60+
font-family: var(--site-icon-fontFamily);
61+
font-weight: normal;
62+
font-style: normal;
63+
font-size: 24px;
64+
line-height: 1;
65+
letter-spacing: normal;
66+
text-transform: none;
67+
display: inline-block;
68+
white-space: nowrap;
69+
word-wrap: normal;
70+
direction: ltr;
71+
-webkit-font-feature-settings: 'liga';
72+
-webkit-font-smoothing: antialiased;
73+
}
74+
7475
dd {
7576
margin-left: 1rem;
7677
}

site/lib/_sass/components/_breadcrumbs.scss

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
nav.breadcrumbs {
22
align-items: center;
3-
margin-block-start: 0.25rem;
4-
margin-block-end: 1rem;
53

64
ol.breadcrumb-list {
75
margin: 0;
8-
border-radius: 0.375rem;
9-
padding: 0.375rem 0;
6+
padding: 0;
7+
border-radius: var(--site-radius);
8+
font-size: 0.925rem;
109

1110
align-items: center;
1211
list-style: none;
@@ -29,7 +28,7 @@ nav.breadcrumbs {
2928
}
3029

3130
&.active a {
32-
color: var(--site-base-fgColor-alt);
31+
color: var(--site-base-fgColor-lighter);
3332
cursor: default;
3433
text-decoration: none;
3534
}
@@ -41,6 +40,8 @@ nav.breadcrumbs {
4140

4241
.material-symbols {
4342
user-select: none;
43+
font-size: 1.25rem;
44+
color: var(--site-base-fgColor-lighter);
4445
}
4546
}
4647
}

site/lib/_sass/components/_content.scss

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,42 @@ article {
4545
}
4646

4747
#site-content-title {
48-
margin-bottom: 1rem;
48+
position: relative;
49+
font-family: var(--site-ui-fontFamily);
50+
margin-block-end: 1.5rem;
4951
scroll-margin-top: calc(var(--site-header-height) + var(--site-subheader-height) + 1.25rem);
52+
53+
&.wrap {
54+
display: flex;
55+
flex-direction: column;
56+
gap: 0.35rem;
57+
58+
background-color: var(--site-raised-bgColor);
59+
padding: 1rem;
60+
border-radius: var(--site-radius);
61+
}
62+
63+
h1 {
64+
text-wrap: pretty;
65+
}
66+
67+
.page-description {
68+
margin-block: 0;
69+
}
70+
71+
#page-header-options {
72+
position: absolute;
73+
top: 0.75rem;
74+
right: 0.75rem;
75+
76+
> button {
77+
color: var(--site-base-fgColor-alt);
78+
}
79+
80+
.dropdown-content {
81+
right: -0.5rem;
82+
}
83+
}
5084
}
5185

5286
h1,

site/lib/_sass/components/_dropdown.scss

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
.dropdown-content {
55
display: none;
66
position: absolute;
7-
background-color: var(--site-chrome-bgColor);
8-
color: var(--site-chrome-fgColor);
7+
background-color: var(--site-raised-bgColor);
98
box-shadow: 0 6px 18px 0 rgba(0, 0, 0, 0.2);
109
border-radius: calc(var(--site-radius) * 1.25);
1110
width: max-content;
12-
border: var(--site-chrome-borderColor) 1px solid;
11+
border: rgba(0, 0, 0, 0.15) 1px solid;
12+
box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);
1313
z-index: var(--site-z-dropdown);
1414

1515
.dropdown-divider {
@@ -36,6 +36,7 @@
3636
a, button {
3737
display: flex;
3838
align-items: center;
39+
justify-content: flex-start;
3940
flex-direction: row;
4041
width: 100%;
4142
gap: 0.4rem;

site/lib/_sass/components/_site-switcher.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111

1212
.dropdown-content {
1313
right: -0.5rem;
14+
background-color: var(--site-chrome-bgColor);
15+
color: var(--site-chrome-fgColor);
16+
border: var(--site-chrome-borderColor) 1px solid;
17+
box-shadow: none;
1418
}
1519
}
1620

site/lib/_sass/components/_theming.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
> .dropdown-content {
55
right: -0.5rem;
6+
background-color: var(--site-chrome-bgColor);
7+
color: var(--site-chrome-fgColor);
8+
border: var(--site-chrome-borderColor) 1px solid;
9+
box-shadow: none;
610

711
.material-symbols {
812
font-size: 20px;

site/lib/jaspr_options.dart

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,20 @@ import 'package:dart_dev_site/src/components/common/client/feedback.dart'
1515
as prefix4;
1616
import 'package:dart_dev_site/src/components/common/client/on_this_page_button.dart'
1717
as prefix5;
18-
import 'package:dart_dev_site/src/components/dartpad/dartpad_injector.dart'
18+
import 'package:dart_dev_site/src/components/common/client/page_header_options.dart'
1919
as prefix6;
20-
import 'package:dart_dev_site/src/components/layout/menu_toggle.dart'
20+
import 'package:dart_dev_site/src/components/dartpad/dartpad_injector.dart'
2121
as prefix7;
22-
import 'package:dart_dev_site/src/components/layout/site_switcher.dart'
22+
import 'package:dart_dev_site/src/components/layout/menu_toggle.dart'
2323
as prefix8;
24-
import 'package:dart_dev_site/src/components/layout/theme_switcher.dart'
24+
import 'package:dart_dev_site/src/components/layout/site_switcher.dart'
2525
as prefix9;
26-
import 'package:dart_dev_site/src/components/pages/glossary_search_section.dart'
26+
import 'package:dart_dev_site/src/components/layout/theme_switcher.dart'
2727
as prefix10;
28-
import 'package:dart_dev_site/src/components/pages/lint_filter_search_section.dart'
28+
import 'package:dart_dev_site/src/components/pages/glossary_search_section.dart'
2929
as prefix11;
30+
import 'package:dart_dev_site/src/components/pages/lint_filter_search_section.dart'
31+
as prefix12;
3032

3133
/// Default [JasprOptions] for use with your jaspr project.
3234
///
@@ -73,30 +75,35 @@ JasprOptions get defaultJasprOptions => JasprOptions(
7375
'src/components/common/client/on_this_page_button',
7476
),
7577

76-
prefix6.DartPadInjector: ClientTarget<prefix6.DartPadInjector>(
78+
prefix6.PageHeaderOptions: ClientTarget<prefix6.PageHeaderOptions>(
79+
'src/components/common/client/page_header_options',
80+
params: _prefix6PageHeaderOptions,
81+
),
82+
83+
prefix7.DartPadInjector: ClientTarget<prefix7.DartPadInjector>(
7784
'src/components/dartpad/dartpad_injector',
78-
params: _prefix6DartPadInjector,
85+
params: _prefix7DartPadInjector,
7986
),
8087

81-
prefix7.MenuToggle: ClientTarget<prefix7.MenuToggle>(
88+
prefix8.MenuToggle: ClientTarget<prefix8.MenuToggle>(
8289
'src/components/layout/menu_toggle',
8390
),
8491

85-
prefix8.SiteSwitcher: ClientTarget<prefix8.SiteSwitcher>(
92+
prefix9.SiteSwitcher: ClientTarget<prefix9.SiteSwitcher>(
8693
'src/components/layout/site_switcher',
8794
),
8895

89-
prefix9.ThemeSwitcher: ClientTarget<prefix9.ThemeSwitcher>(
96+
prefix10.ThemeSwitcher: ClientTarget<prefix10.ThemeSwitcher>(
9097
'src/components/layout/theme_switcher',
9198
),
9299

93-
prefix10.GlossarySearchSection:
94-
ClientTarget<prefix10.GlossarySearchSection>(
100+
prefix11.GlossarySearchSection:
101+
ClientTarget<prefix11.GlossarySearchSection>(
95102
'src/components/pages/glossary_search_section',
96103
),
97104

98-
prefix11.LintFilterSearchSection:
99-
ClientTarget<prefix11.LintFilterSearchSection>(
105+
prefix12.LintFilterSearchSection:
106+
ClientTarget<prefix12.LintFilterSearchSection>(
100107
'src/components/pages/lint_filter_search_section',
101108
),
102109
},
@@ -115,7 +122,12 @@ Map<String, dynamic> _prefix3CopyButton(prefix3.CopyButton c) => {
115122
Map<String, dynamic> _prefix4FeedbackComponent(prefix4.FeedbackComponent c) => {
116123
'issueUrl': c.issueUrl,
117124
};
118-
Map<String, dynamic> _prefix6DartPadInjector(prefix6.DartPadInjector c) => {
125+
Map<String, dynamic> _prefix6PageHeaderOptions(prefix6.PageHeaderOptions c) => {
126+
'title': c.title,
127+
'sourceUrl': c.sourceUrl,
128+
'issueUrl': c.issueUrl,
129+
};
130+
Map<String, dynamic> _prefix7DartPadInjector(prefix7.DartPadInjector c) => {
119131
'title': c.title,
120132
'theme': c.theme,
121133
'height': c.height,
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:jaspr/jaspr.dart';
6+
import 'package:universal_web/js_interop.dart';
7+
import 'package:universal_web/web.dart' as web;
8+
9+
import '../button.dart';
10+
import '../dropdown.dart';
11+
12+
@client
13+
final class PageHeaderOptions extends StatefulComponent {
14+
const PageHeaderOptions({
15+
required this.title,
16+
this.sourceUrl,
17+
this.issueUrl,
18+
super.key,
19+
});
20+
21+
final String title;
22+
final String? sourceUrl;
23+
final String? issueUrl;
24+
25+
@override
26+
State<PageHeaderOptions> createState() => _PageHeaderOptionsState();
27+
}
28+
29+
final class _PageHeaderOptionsState extends State<PageHeaderOptions> {
30+
bool _isShareSupported = false;
31+
32+
@override
33+
void initState() {
34+
super.initState();
35+
_checkShareSupport();
36+
}
37+
38+
void _checkShareSupport() {
39+
if (kIsWeb) {
40+
try {
41+
// Check if the share API is available.
42+
_isShareSupported = web.window.navigator.canShare(_shareData);
43+
} catch (_) {
44+
_isShareSupported = false;
45+
}
46+
setState(() {});
47+
}
48+
}
49+
50+
String get _currentBaseUrl =>
51+
web.window.location.origin + web.window.location.pathname;
52+
53+
web.ShareData get _shareData => web.ShareData(
54+
url: _currentBaseUrl,
55+
title: component.title,
56+
);
57+
58+
@override
59+
Component build(BuildContext _) => Dropdown(
60+
id: 'page-header-options',
61+
children: [
62+
const DropdownToggle(
63+
Button(icon: 'more_vert', title: 'View page options.'),
64+
),
65+
DropdownContent(
66+
nav(
67+
classes: 'dropdown-menu',
68+
attributes: {
69+
'role': 'menu',
70+
},
71+
[
72+
ul(
73+
[
74+
li(
75+
[
76+
if (_isShareSupported)
77+
Button(
78+
icon: 'share',
79+
content: 'Share page',
80+
onClick: () {
81+
web.window.navigator
82+
.share(_shareData)
83+
.toDart
84+
.ignore();
85+
},
86+
)
87+
else
88+
Button(
89+
icon: 'copy',
90+
content: 'Copy link',
91+
onClick: () {
92+
web.window.navigator.clipboard
93+
.writeText(_currentBaseUrl)
94+
.toDart
95+
.ignore();
96+
},
97+
),
98+
],
99+
),
100+
if (component.sourceUrl case final sourceUrl?)
101+
li(
102+
[
103+
Button(
104+
icon: 'docs',
105+
content: 'View source',
106+
href: sourceUrl,
107+
attributes: const {
108+
'target': '_blank',
109+
'rel': 'noopener',
110+
},
111+
),
112+
],
113+
),
114+
if (component.issueUrl case final issueUrl?)
115+
li(
116+
[
117+
Button(
118+
icon: 'bug_report',
119+
content: 'Report issue',
120+
href: issueUrl,
121+
attributes: const {
122+
'target': '_blank',
123+
'rel': 'noopener',
124+
},
125+
),
126+
],
127+
),
128+
],
129+
),
130+
],
131+
),
132+
),
133+
],
134+
);
135+
}

0 commit comments

Comments
 (0)