hale-commenting-system 3.0.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,8 +11,8 @@ Create `patternfly-react-seed/.env` (this file is already in `.gitignore`):
11
11
  VITE_GITHUB_CLIENT_ID=YOUR_GITHUB_OAUTH_CLIENT_ID
12
12
 
13
13
  # Target repo for Issues/Comments
14
- VITE_GITHUB_OWNER=JustinXHale
15
- VITE_GITHUB_REPO=pfseed-commenting-system
14
+ VITE_GITHUB_OWNER=YOUR_GITHUB_USERNAME
15
+ VITE_GITHUB_REPO=YOUR_REPO_NAME
16
16
  ```
17
17
 
18
18
  ### Server-only secret (local dev)
package/README.md CHANGED
@@ -12,6 +12,15 @@ A commenting system for PatternFly React applications that allows designers and
12
12
  - **Responsive** - Works on desktop and mobile devices
13
13
  - **Easy Integration** - Automated setup script for seamless installation
14
14
 
15
+ ## Prerequisites
16
+
17
+ This package was developed for **PatternFly React Seed** projects, but can be used with similar PatternFly React applications that have:
18
+ - Webpack-based setup with `webpack.dev.js`
19
+ - `src/app/` directory structure
20
+ - PatternFly React Core and Icons dependencies
21
+
22
+ The automated integration script (`npx hale-commenting-system init`) works best with PatternFly React Seed or projects with a similar structure.
23
+
15
24
  ## Installation
16
25
 
17
26
  ```bash
@@ -131,4 +140,4 @@ MIT
131
140
 
132
141
  ## Support
133
142
 
134
- For issues, questions, or contributions, please visit the [repository](https://github.com/patternfly/patternfly-react-seed).
143
+ For issues or questions, please open an issue on npm or contact the package maintainer.
package/package.json CHANGED
@@ -1,15 +1,21 @@
1
1
  {
2
2
  "name": "hale-commenting-system",
3
- "version": "3.0.0",
3
+ "version": "3.1.1",
4
4
  "description": "A commenting system for PatternFly React applications that allows designers and developers to add comments directly on design pages, sync with GitHub Issues, and link Jira tickets.",
5
- "repository": "https://github.com/patternfly/patternfly-react-seed.git",
6
5
  "homepage": "https://www.npmjs.com/package/hale-commenting-system",
7
6
  "license": "MIT",
8
7
  "main": "src/app/commenting-system/index.ts",
9
8
  "types": "src/app/commenting-system/index.ts",
10
9
  "bin": {
11
- "hale-commenting-system": "./scripts/integrate.js"
10
+ "hale-commenting-system": "scripts/integrate.js"
12
11
  },
12
+ "files": [
13
+ "src/app/commenting-system/",
14
+ "scripts/",
15
+ "README.md",
16
+ "LICENSE",
17
+ "GITHUB_OAUTH_ENV_TEMPLATE.md"
18
+ ],
13
19
  "scripts": {
14
20
  "prebuild": "npm run type-check && npm run clean",
15
21
  "build": "webpack --config webpack.prod.js",
@@ -1359,13 +1359,43 @@ async function main() {
1359
1359
  }
1360
1360
  ]);
1361
1361
 
1362
+ // Ask for target repo to store comments/issues
1363
+ console.log('\nWhere do you want to store comments as GitHub Issues?');
1364
+ console.log('This should be a repository you have write access to.\n');
1365
+
1366
+ const repoAnswers = await prompt([
1367
+ {
1368
+ type: 'input',
1369
+ name: 'owner',
1370
+ message: 'GitHub repository owner (username or organization):',
1371
+ default: owner,
1372
+ validate: (input) => {
1373
+ if (!input.trim()) return 'Owner is required';
1374
+ return true;
1375
+ }
1376
+ },
1377
+ {
1378
+ type: 'input',
1379
+ name: 'repo',
1380
+ message: 'GitHub repository name:',
1381
+ default: repo,
1382
+ validate: (input) => {
1383
+ if (!input.trim()) return 'Repository name is required';
1384
+ return true;
1385
+ }
1386
+ }
1387
+ ]);
1388
+
1389
+ const targetOwner = repoAnswers.owner;
1390
+ const targetRepo = repoAnswers.repo;
1391
+
1362
1392
  // Validate GitHub credentials
1363
1393
  console.log('\n🔍 Validating GitHub credentials...');
1364
1394
  githubValid = await validateGitHubCredentials(
1365
1395
  githubAnswers.clientId,
1366
1396
  githubAnswers.clientSecret,
1367
- owner,
1368
- repo
1397
+ targetOwner,
1398
+ targetRepo
1369
1399
  );
1370
1400
 
1371
1401
  if (!githubValid) {
@@ -1378,8 +1408,8 @@ async function main() {
1378
1408
  githubConfig = {
1379
1409
  clientId: githubAnswers.clientId,
1380
1410
  clientSecret: githubAnswers.clientSecret,
1381
- owner: owner,
1382
- repo: repo
1411
+ owner: targetOwner,
1412
+ repo: targetRepo
1383
1413
  };
1384
1414
  } else {
1385
1415
  console.log('\n⏭️ Skipping GitHub setup. You can add it later by editing .env and .env.server files.\n');
@@ -1469,8 +1499,8 @@ async function main() {
1469
1499
  generateFiles({
1470
1500
  github: githubConfig,
1471
1501
  jira: jiraConfig,
1472
- owner: owner,
1473
- repo: repo
1502
+ owner: githubConfig ? githubConfig.owner : owner,
1503
+ repo: githubConfig ? githubConfig.repo : repo
1474
1504
  });
1475
1505
 
1476
1506
  // Step 5: Integrate into project
@@ -1,7 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(npm run type-check:*)"
5
- ]
6
- }
7
- }
package/.editorconfig DELETED
@@ -1,17 +0,0 @@
1
- # Editor configuration, see http://editorconfig.org
2
- root = true
3
-
4
- [*]
5
- charset = utf-8
6
- indent_style = space
7
- indent_size = 2
8
- insert_final_newline = true
9
- trim_trailing_whitespace = true
10
-
11
- [*.snap]
12
- max_line_length = off
13
- trim_trailing_whitespace = false
14
-
15
- [*.md]
16
- max_line_length = off
17
- trim_trailing_whitespace = false
package/.eslintrc.js DELETED
@@ -1,75 +0,0 @@
1
- module.exports = {
2
- // tells eslint to use the TypeScript parser
3
- "parser": "@typescript-eslint/parser",
4
- // tell the TypeScript parser that we want to use JSX syntax
5
- "parserOptions": {
6
- "tsx": true,
7
- "jsx": true,
8
- "js": true,
9
- "useJSXTextNode": true,
10
- "project": "./tsconfig.json",
11
- "tsconfigRootDir": "."
12
- },
13
- // we want to use the recommended rules provided from the typescript plugin
14
- "extends": [
15
- "eslint:recommended",
16
- "plugin:react/recommended",
17
- "plugin:@typescript-eslint/recommended"
18
- ],
19
- "globals": {
20
- "window": "readonly",
21
- "describe": "readonly",
22
- "test": "readonly",
23
- "expect": "readonly",
24
- "it": "readonly",
25
- "process": "readonly",
26
- "document": "readonly",
27
- "insights": "readonly",
28
- "shallow": "readonly",
29
- "render": "readonly",
30
- "mount": "readonly"
31
- },
32
- "overrides": [
33
- {
34
- "files": ["src/**/*.ts", "src/**/*.tsx"],
35
- "parser": "@typescript-eslint/parser",
36
- "plugins": ["@typescript-eslint"],
37
- "extends": ["plugin:@typescript-eslint/recommended"],
38
- "rules": {
39
- "react/prop-types": "off",
40
- "@typescript-eslint/no-unused-vars": "error"
41
- },
42
- },
43
- ],
44
- "settings": {
45
- "react": {
46
- "version": "^16.11.0"
47
- }
48
- },
49
- // includes the typescript specific rules found here: https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#supported-rules
50
- "plugins": [
51
- "@typescript-eslint",
52
- "react-hooks",
53
- "eslint-plugin-react-hooks"
54
- ],
55
- "rules": {
56
- "sort-imports": [
57
- "error",
58
- {
59
- "ignoreDeclarationSort": true
60
- }
61
- ],
62
- "@typescript-eslint/explicit-function-return-type": "off",
63
- "react-hooks/rules-of-hooks": "error",
64
- "react-hooks/exhaustive-deps": "warn",
65
- "@typescript-eslint/interface-name-prefix": "off",
66
- "prettier/prettier": "off",
67
- "import/no-unresolved": "off",
68
- "import/extensions": "off",
69
- "react/prop-types": "off"
70
- },
71
- "env": {
72
- "browser": true,
73
- "node": true
74
- }
75
- }
package/.prettierignore DELETED
@@ -1 +0,0 @@
1
- package.json
package/.prettierrc DELETED
@@ -1,4 +0,0 @@
1
- {
2
- "singleQuote": true,
3
- "printWidth": 120
4
- }
@@ -1,248 +0,0 @@
1
- import * as React from 'react';
2
- import { NavLink, useLocation } from 'react-router-dom';
3
- import {
4
- Button,
5
- Masthead,
6
- MastheadBrand,
7
- MastheadLogo,
8
- MastheadMain,
9
- MastheadToggle,
10
- Nav,
11
- NavExpandable,
12
- NavItem,
13
- NavList,
14
- Page,
15
- PageSidebar,
16
- PageSidebarBody,
17
- SkipToContent,
18
- Switch,
19
- } from '@patternfly/react-core';
20
- import { IAppRoute, IAppRouteGroup, routes } from '@app/routes';
21
- import { BarsIcon, ExternalLinkAltIcon, GithubIcon } from '@patternfly/react-icons';
22
- import { CommentOverlay, CommentPanel, useComments, useGitHubAuth } from '@app/commenting-system';
23
-
24
- interface IAppLayout {
25
- children: React.ReactNode;
26
- }
27
-
28
- const AppLayout: React.FunctionComponent<IAppLayout> = ({ children }) => {
29
- const [sidebarOpen, setSidebarOpen] = React.useState(true);
30
- const { commentsEnabled, setCommentsEnabled, drawerPinnedOpen, setDrawerPinnedOpen, floatingWidgetMode, setFloatingWidgetMode } = useComments();
31
- const { isAuthenticated, user, login, logout } = useGitHubAuth();
32
- const masthead = (
33
- <Masthead>
34
- <MastheadMain>
35
- <MastheadToggle>
36
- <Button
37
- icon={<BarsIcon />}
38
- variant="plain"
39
- onClick={() => setSidebarOpen(!sidebarOpen)}
40
- aria-label="Global navigation"
41
- />
42
- </MastheadToggle>
43
- <MastheadBrand data-codemods>
44
- <MastheadLogo data-codemods>
45
- <svg height="40px" viewBox="0 0 679 158">
46
- <title>PatternFly logo</title>
47
- <defs>
48
- <linearGradient x1="68%" y1="2.25860997e-13%" x2="32%" y2="100%" id="linearGradient-basic-masthead">
49
- <stop stopColor="#2B9AF3" offset="0%"></stop>
50
- <stop stopColor="#73BCF7" stopOpacity="0.502212631" offset="100%"></stop>
51
- </linearGradient>
52
- </defs>
53
- <g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd">
54
- <g
55
- transform="translate(206.000000, 45.750000)"
56
- fill="var(--pf-t--global--text--color--regular)"
57
- fillRule="nonzero"
58
- >
59
- <path d="M0,65.25 L0,2.25 L33.21,2.25 C37.35,2.25 41.025,3.135 44.235,4.905 C47.445,6.675 49.98,9.09 51.84,12.15 C53.7,15.21 54.63,18.72 54.63,22.68 C54.63,26.46 53.7,29.865 51.84,32.895 C49.98,35.925 47.43,38.31 44.19,40.05 C40.95,41.79 37.29,42.66 33.21,42.66 L15.48,42.66 L15.48,65.25 L0,65.25 Z M15.48,29.88 L31.41,29.88 C33.69,29.88 35.52,29.22 36.9,27.9 C38.28,26.58 38.97,24.87 38.97,22.77 C38.97,20.61 38.28,18.855 36.9,17.505 C35.52,16.155 33.69,15.48 31.41,15.48 L15.48,15.48 L15.48,29.88 Z"></path>
60
- <path d="M77.04,66.06 C73.68,66.06 70.695,65.43 68.085,64.17 C65.475,62.91 63.435,61.17 61.965,58.95 C60.495,56.73 59.76,54.18 59.76,51.3 C59.76,46.74 61.485,43.215 64.935,40.725 C68.385,38.235 73.2,36.99 79.38,36.99 C83.1,36.99 86.7,37.44 90.18,38.34 L90.18,36 C90.18,31.26 87.15,28.89 81.09,28.89 C77.49,28.89 72.69,30.15 66.69,32.67 L61.47,21.96 C69.15,18.48 76.56,16.74 83.7,16.74 C90.3,16.74 95.43,18.315 99.09,21.465 C102.75,24.615 104.58,29.04 104.58,34.74 L104.58,65.25 L90.18,65.25 L90.18,62.37 C88.26,63.69 86.235,64.635 84.105,65.205 C81.975,65.775 79.62,66.06 77.04,66.06 Z M73.62,51.03 C73.62,52.53 74.28,53.7 75.6,54.54 C76.92,55.38 78.75,55.8 81.09,55.8 C84.69,55.8 87.72,55.05 90.18,53.55 L90.18,47.43 C87.42,46.71 84.54,46.35 81.54,46.35 C79.02,46.35 77.07,46.755 75.69,47.565 C74.31,48.375 73.62,49.53 73.62,51.03 Z"></path>
61
- <path d="M137.25,65.88 C125.73,65.88 119.97,60.84 119.97,50.76 L119.97,29.79 L110.34,29.79 L110.34,17.64 L119.97,17.64 L119.97,5.4 L134.55,2.25 L134.55,17.64 L147.87,17.64 L147.87,29.79 L134.55,29.79 L134.55,47.88 C134.55,49.98 135.015,51.465 135.945,52.335 C136.875,53.205 138.51,53.64 140.85,53.64 C143.01,53.64 145.2,53.31 147.42,52.65 L147.42,64.44 C146.1,64.86 144.42,65.205 142.38,65.475 C140.34,65.745 138.63,65.88 137.25,65.88 Z"></path>
62
- <path d="M177.57,65.88 C166.05,65.88 160.29,60.84 160.29,50.76 L160.29,29.79 L150.66,29.79 L150.66,17.64 L160.29,17.64 L160.29,5.4 L174.87,2.25 L174.87,17.64 L188.19,17.64 L188.19,29.79 L174.87,29.79 L174.87,47.88 C174.87,49.98 175.335,51.465 176.265,52.335 C177.195,53.205 178.83,53.64 181.17,53.64 C183.33,53.64 185.52,53.31 187.74,52.65 L187.74,64.44 C186.42,64.86 184.74,65.205 182.7,65.475 C180.66,65.745 178.95,65.88 177.57,65.88 Z"></path>
63
- <path d="M217.62,66.15 C212.76,66.15 208.365,65.055 204.435,62.865 C200.505,60.675 197.4,57.72 195.12,54 C192.84,50.28 191.7,46.11 191.7,41.49 C191.7,36.87 192.795,32.7 194.985,28.98 C197.175,25.26 200.16,22.305 203.94,20.115 C207.72,17.925 211.92,16.83 216.54,16.83 C221.22,16.83 225.36,17.955 228.96,20.205 C232.56,22.455 235.395,25.53 237.465,29.43 C239.535,33.33 240.57,37.8 240.57,42.84 L240.57,46.44 L206.64,46.44 C207.6,48.66 209.1,50.475 211.14,51.885 C213.18,53.295 215.58,54 218.34,54 C222.42,54 225.6,52.8 227.88,50.4 L237.51,58.95 C234.51,61.47 231.435,63.3 228.285,64.44 C225.135,65.58 221.58,66.15 217.62,66.15 Z M206.37,36.27 L226.26,36.27 C225.48,33.99 224.205,32.16 222.435,30.78 C220.665,29.4 218.61,28.71 216.27,28.71 C213.87,28.71 211.8,29.37 210.06,30.69 C208.32,32.01 207.09,33.87 206.37,36.27 Z"></path>
64
- <path d="M247.41,65.25 L247.41,17.64 L261.99,17.64 L261.99,22.41 C265.23,18.51 269.4,16.56 274.5,16.56 C277.08,16.62 278.91,17.01 279.99,17.73 L279.99,30.42 C277.95,29.46 275.64,28.98 273.06,28.98 C270.78,28.98 268.665,29.505 266.715,30.555 C264.765,31.605 263.19,33.09 261.99,35.01 L261.99,65.25 L247.41,65.25 Z"></path>
65
- <path d="M286.29,65.25 L286.29,17.64 L300.87,17.64 L300.87,20.88 C304.47,18.12 308.73,16.74 313.65,16.74 C317.37,16.74 320.655,17.55 323.505,19.17 C326.355,20.79 328.59,23.04 330.21,25.92 C331.83,28.8 332.64,32.13 332.64,35.91 L332.64,65.25 L318.06,65.25 L318.06,37.89 C318.06,35.25 317.28,33.15 315.72,31.59 C314.16,30.03 312.06,29.25 309.42,29.25 C305.76,29.25 302.91,30.51 300.87,33.03 L300.87,65.25 L286.29,65.25 Z"></path>
66
- <polygon points="342 65.25 342 2.25 392.04 2.25 392.04 15.66 357.48 15.66 357.48 27.45 380.52 27.45 380.52 40.41 357.48 40.41 357.48 65.25"></polygon>
67
- <polygon points="399.96 65.25 399.96 2.25 414.54 0 414.54 65.25"></polygon>
68
- <path d="M429.21,84.69 C428.07,84.69 426.96,84.645 425.88,84.555 C424.8,84.465 423.9,84.33 423.18,84.15 L423.18,71.73 C424.38,71.97 425.88,72.09 427.68,72.09 C432.36,72.09 435.51,70.05 437.13,65.97 L437.13,65.88 L418.86,17.64 L434.97,17.64 L445.5,47.61 L457.74,17.64 L473.49,17.64 L452.16,67.68 C450.42,71.82 448.5,75.135 446.4,77.625 C444.3,80.115 441.87,81.915 439.11,83.025 C436.35,84.135 433.05,84.69 429.21,84.69 Z"></path>
69
- </g>
70
- <g transform="translate(0.000000, 0.000000)">
71
- <path
72
- d="M61.826087,0 L158,0 L158,96.173913 L147.695652,96.173913 C100.271201,96.173913 61.826087,57.7287992 61.826087,10.3043478 L61.826087,0 L61.826087,0 Z"
73
- fill="#0066CC"
74
- ></path>
75
- <path
76
- d="M158,3.43478261 L65.2608696,158 L138,158 C149.045695,158 158,149.045695 158,138 L158,3.43478261 L158,3.43478261 Z"
77
- fill="url(#linearGradient-basic-masthead)"
78
- ></path>
79
- <path
80
- d="M123.652174,-30.9130435 L30.9130435,123.652174 L103.652174,123.652174 C114.697869,123.652174 123.652174,114.697869 123.652174,103.652174 L123.652174,-30.9130435 L123.652174,-30.9130435 Z"
81
- fill="url(#linearGradient-basic-masthead)"
82
- transform="translate(77.282609, 46.369565) scale(1, -1) rotate(90.000000) translate(-77.282609, -46.369565) "
83
- ></path>
84
- </g>
85
- </g>
86
- </svg>
87
- </MastheadLogo>
88
- </MastheadBrand>
89
- </MastheadMain>
90
- </Masthead>
91
- );
92
-
93
- const location = useLocation();
94
-
95
- const renderNavItem = (route: IAppRoute, index: number) => (
96
- <NavItem key={`${route.label}-${index}`} id={`${route.label}-${index}`} isActive={route.path === location.pathname}>
97
- <NavLink
98
- to={route.path}
99
- >
100
- {route.label}
101
- </NavLink>
102
- </NavItem>
103
- );
104
-
105
- const renderNavGroup = (group: IAppRouteGroup, groupIndex: number) => {
106
- // Special handling for Comments group
107
- if (group.label === 'Comments') {
108
- return (
109
- <NavExpandable
110
- key={`${group.label}-${groupIndex}`}
111
- id={`${group.label}-${groupIndex}`}
112
- title="Hale Commenting System"
113
- isActive={group.routes.some((route) => route.path === location.pathname)}
114
- >
115
- <NavItem
116
- onClick={(e) => {
117
- e.stopPropagation();
118
- setFloatingWidgetMode(!floatingWidgetMode);
119
- if (!floatingWidgetMode) {
120
- setDrawerPinnedOpen(false); // Close drawer if opening floating widget
121
- }
122
- }}
123
- style={{ cursor: 'pointer' }}
124
- >
125
- <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
126
- <ExternalLinkAltIcon />
127
- <span>{floatingWidgetMode ? 'Close widget' : 'Pop out'}</span>
128
- </div>
129
- </NavItem>
130
- <NavItem>
131
- <div
132
- data-comment-controls
133
- style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', paddingRight: '1rem' }}
134
- >
135
- <span>Enable Comments</span>
136
- <Switch
137
- id="comments-enabled-switch"
138
- isChecked={commentsEnabled}
139
- onChange={(_event, checked) => {
140
- setCommentsEnabled(checked);
141
- if (checked) {
142
- setDrawerPinnedOpen(true);
143
- }
144
- }}
145
- aria-label="Enable or disable comments"
146
- />
147
- </div>
148
- </NavItem>
149
- <NavItem>
150
- <div
151
- data-comment-controls
152
- style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', paddingRight: '1rem' }}
153
- >
154
- <span>Page info drawer</span>
155
- <Switch
156
- id="page-info-drawer-switch"
157
- isChecked={drawerPinnedOpen}
158
- onChange={(_event, checked) => setDrawerPinnedOpen(checked)}
159
- aria-label="Pin page info drawer open"
160
- />
161
- </div>
162
- </NavItem>
163
- <NavItem>
164
- <div
165
- data-comment-controls
166
- style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', paddingRight: '1rem' }}
167
- >
168
- {isAuthenticated ? (
169
- <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
170
- <span style={{ display: 'inline-flex', alignItems: 'center', gap: '6px' }}>
171
- <GithubIcon />
172
- {user?.login ? `@${user.login}` : 'Signed in'}
173
- </span>
174
- <Button variant="link" isInline onClick={logout}>
175
- Sign out
176
- </Button>
177
- </div>
178
- ) : (
179
- <Button variant="link" isInline icon={<GithubIcon />} onClick={login}>
180
- Sign in with GitHub
181
- </Button>
182
- )}
183
- </div>
184
- </NavItem>
185
- {group.routes.map((route, idx) => route.label && renderNavItem(route, idx))}
186
- </NavExpandable>
187
- );
188
- }
189
-
190
- // Default handling for other groups
191
- return (
192
- <NavExpandable
193
- key={`${group.label}-${groupIndex}`}
194
- id={`${group.label}-${groupIndex}`}
195
- title={group.label}
196
- isActive={group.routes.some((route) => route.path === location.pathname)}
197
- >
198
- {group.routes.map((route, idx) => route.label && renderNavItem(route, idx))}
199
- </NavExpandable>
200
- );
201
- };
202
-
203
- const Navigation = (
204
- <Nav id="nav-primary-simple">
205
- <NavList id="nav-list-simple">
206
- {routes.map(
207
- (route, idx) => route.label && (!route.routes ? renderNavItem(route, idx) : renderNavGroup(route, idx)),
208
- )}
209
- </NavList>
210
- </Nav>
211
- );
212
-
213
- const Sidebar = (
214
- <PageSidebar>
215
- <PageSidebarBody>{Navigation}</PageSidebarBody>
216
- </PageSidebar>
217
- );
218
-
219
- const pageId = 'primary-app-container';
220
-
221
- const PageSkipToContent = (
222
- <SkipToContent
223
- onClick={(event) => {
224
- event.preventDefault();
225
- const primaryContentContainer = document.getElementById(pageId);
226
- primaryContentContainer?.focus();
227
- }}
228
- href={`#${pageId}`}
229
- >
230
- Skip to Content
231
- </SkipToContent>
232
- );
233
- return (
234
- <Page
235
- mainContainerId={pageId}
236
- masthead={masthead}
237
- sidebar={sidebarOpen && Sidebar}
238
- skipToContent={PageSkipToContent}
239
- >
240
- <CommentPanel>
241
- <CommentOverlay />
242
- {children}
243
- </CommentPanel>
244
- </Page>
245
- );
246
- };
247
-
248
- export { AppLayout };