create-trellis-docs 1.0.0

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.
Files changed (148) hide show
  1. package/bin/index.js +29 -0
  2. package/lib/index.js +178 -0
  3. package/package.json +23 -0
  4. package/template/_gitignore +6 -0
  5. package/template/blog/2025-01-01-welcome.md +15 -0
  6. package/template/design-tokens.json +218 -0
  7. package/template/docs/faq/general.mdx +16 -0
  8. package/template/docs/faq/index.mdx +13 -0
  9. package/template/docs/getting-started.mdx +54 -0
  10. package/template/docs/guides/writing-docs.mdx +90 -0
  11. package/template/docusaurus.config.js.tpl +200 -0
  12. package/template/package.json.tpl +60 -0
  13. package/template/packages/faq-index-plugin/README.md +104 -0
  14. package/template/packages/faq-index-plugin/index.js +91 -0
  15. package/template/packages/faq-index-plugin/package.json +15 -0
  16. package/template/packages/redirects-plugin/README.md +186 -0
  17. package/template/packages/redirects-plugin/index.js +167 -0
  18. package/template/packages/redirects-plugin/package.json +15 -0
  19. package/template/packages/redirects-plugin/yarn.lock +31 -0
  20. package/template/redirects.json +1 -0
  21. package/template/scripts/build-tokens.js +34 -0
  22. package/template/sidebars.js +17 -0
  23. package/template/src/components/CustomSearch/CustomSearch.js +241 -0
  24. package/template/src/components/CustomSearch/CustomSearchContent.js +171 -0
  25. package/template/src/components/CustomSearch/NavbarSearch.js +211 -0
  26. package/template/src/components/CustomSearch/SearchContext.js +26 -0
  27. package/template/src/components/CustomSearch/styles.module.css +171 -0
  28. package/template/src/components/CustomSearch/wrapperInit.js +11 -0
  29. package/template/src/components/FaqTableOfContents/index.jsx +176 -0
  30. package/template/src/components/FaqTableOfContents/styles.module.css +167 -0
  31. package/template/src/components/Feedback/Feedback.js +310 -0
  32. package/template/src/components/Feedback/api.js +77 -0
  33. package/template/src/components/FlippingCard/FlippingCard.js +197 -0
  34. package/template/src/components/FlippingCard/styles.module.css +248 -0
  35. package/template/src/components/Glossary.js +57 -0
  36. package/template/src/css/custom.css +765 -0
  37. package/template/src/data/glossary.json +1 -0
  38. package/template/src/pages/index.js.tpl +38 -0
  39. package/template/src/theme/Admonition/Icon/Danger.js +11 -0
  40. package/template/src/theme/Admonition/Icon/Info.js +11 -0
  41. package/template/src/theme/Admonition/Icon/Note.js +11 -0
  42. package/template/src/theme/Admonition/Icon/Tip.js +11 -0
  43. package/template/src/theme/Admonition/Icon/Warning.js +11 -0
  44. package/template/src/theme/Admonition/Layout/index.js +39 -0
  45. package/template/src/theme/Admonition/Layout/styles.module.css +36 -0
  46. package/template/src/theme/Admonition/Type/Caution.js +28 -0
  47. package/template/src/theme/Admonition/Type/Danger.js +26 -0
  48. package/template/src/theme/Admonition/Type/Info.js +26 -0
  49. package/template/src/theme/Admonition/Type/Note.js +26 -0
  50. package/template/src/theme/Admonition/Type/Tip.js +26 -0
  51. package/template/src/theme/Admonition/Type/Warning.js +26 -0
  52. package/template/src/theme/Admonition/Types.js +27 -0
  53. package/template/src/theme/Admonition/index.js +18 -0
  54. package/template/src/theme/AnnouncementBar/CloseButton/index.js +20 -0
  55. package/template/src/theme/AnnouncementBar/CloseButton/styles.module.css +4 -0
  56. package/template/src/theme/AnnouncementBar/Content/index.js +17 -0
  57. package/template/src/theme/AnnouncementBar/Content/styles.module.css +10 -0
  58. package/template/src/theme/AnnouncementBar/index.js +33 -0
  59. package/template/src/theme/AnnouncementBar/styles.module.css +55 -0
  60. package/template/src/theme/BlogSidebar/Content/index.js +35 -0
  61. package/template/src/theme/BlogSidebar/Desktop/index.js +44 -0
  62. package/template/src/theme/BlogSidebar/Desktop/styles.module.css +60 -0
  63. package/template/src/theme/BlogSidebar/Mobile/index.js +38 -0
  64. package/template/src/theme/BlogSidebar/Mobile/styles.module.css +3 -0
  65. package/template/src/theme/BlogSidebar/index.js +15 -0
  66. package/template/src/theme/Details/index.js +23 -0
  67. package/template/src/theme/Details/styles.module.css +52 -0
  68. package/template/src/theme/DocBreadcrumbs/Items/Home/index.js +22 -0
  69. package/template/src/theme/DocBreadcrumbs/Items/Home/styles.module.css +7 -0
  70. package/template/src/theme/DocBreadcrumbs/StructuredData/index.js +15 -0
  71. package/template/src/theme/DocBreadcrumbs/index.js +75 -0
  72. package/template/src/theme/DocBreadcrumbs/styles.module.css +5 -0
  73. package/template/src/theme/DocCard/index.js +93 -0
  74. package/template/src/theme/DocCard/styles.module.css +53 -0
  75. package/template/src/theme/DocCardList/index.js +27 -0
  76. package/template/src/theme/DocCardList/styles.module.css +7 -0
  77. package/template/src/theme/DocItem/Content/index.js +121 -0
  78. package/template/src/theme/DocItem/Content/styles.module.css +96 -0
  79. package/template/src/theme/DocItem/Footer/index.js +43 -0
  80. package/template/src/theme/DocItem/Footer/styles.module.css +19 -0
  81. package/template/src/theme/DocItem/Layout/index.js +55 -0
  82. package/template/src/theme/DocItem/Layout/styles.module.css +14 -0
  83. package/template/src/theme/DocItem/Metadata/index.js +17 -0
  84. package/template/src/theme/DocItem/Paginator/index.js +17 -0
  85. package/template/src/theme/DocItem/TOC/Desktop/index.js +15 -0
  86. package/template/src/theme/DocItem/TOC/Mobile/index.js +17 -0
  87. package/template/src/theme/DocItem/TOC/Mobile/styles.module.css +12 -0
  88. package/template/src/theme/DocItem/index.js +19 -0
  89. package/template/src/theme/DocItem/styles.module.css +28 -0
  90. package/template/src/theme/DocRoot/Layout/Main/index.js +23 -0
  91. package/template/src/theme/DocRoot/Layout/Main/styles.module.css +31 -0
  92. package/template/src/theme/DocRoot/Layout/Sidebar/ExpandButton/index.js +28 -0
  93. package/template/src/theme/DocRoot/Layout/Sidebar/ExpandButton/styles.module.css +27 -0
  94. package/template/src/theme/DocRoot/Layout/Sidebar/index.js +70 -0
  95. package/template/src/theme/DocRoot/Layout/Sidebar/styles.module.css +32 -0
  96. package/template/src/theme/DocRoot/Layout/index.js +27 -0
  97. package/template/src/theme/DocRoot/Layout/styles.module.css +9 -0
  98. package/template/src/theme/DocRoot/index.js +25 -0
  99. package/template/src/theme/DocSidebar/Desktop/CollapseButton/index.js +28 -0
  100. package/template/src/theme/DocSidebar/Desktop/CollapseButton/styles.module.css +40 -0
  101. package/template/src/theme/DocSidebar/Desktop/Content/index.js +44 -0
  102. package/template/src/theme/DocSidebar/Desktop/Content/styles.module.css +16 -0
  103. package/template/src/theme/DocSidebar/Desktop/index.js +28 -0
  104. package/template/src/theme/DocSidebar/Desktop/styles.module.css +37 -0
  105. package/template/src/theme/DocSidebar/Mobile/index.js +39 -0
  106. package/template/src/theme/DocSidebar/index.js +18 -0
  107. package/template/src/theme/DocSidebarItem/Category/index.js +203 -0
  108. package/template/src/theme/DocSidebarItem/Html/index.js +20 -0
  109. package/template/src/theme/DocSidebarItem/Html/styles.module.css +6 -0
  110. package/template/src/theme/DocSidebarItem/Link/index.js +49 -0
  111. package/template/src/theme/DocSidebarItem/Link/styles.module.css +3 -0
  112. package/template/src/theme/DocSidebarItem/index.js +15 -0
  113. package/template/src/theme/EditMetaRow/index.js +25 -0
  114. package/template/src/theme/EditMetaRow/styles.module.css +11 -0
  115. package/template/src/theme/EditThisPage/index.js +29 -0
  116. package/template/src/theme/ErrorPageContent.js +34 -0
  117. package/template/src/theme/Footer/Copyright/index.js +11 -0
  118. package/template/src/theme/Footer/Layout/index.js +21 -0
  119. package/template/src/theme/Footer/LinkItem/index.js +26 -0
  120. package/template/src/theme/Footer/Links/MultiColumn/index.js +44 -0
  121. package/template/src/theme/Footer/Links/Simple/index.js +32 -0
  122. package/template/src/theme/Footer/Links/index.js +11 -0
  123. package/template/src/theme/Footer/Logo/index.js +35 -0
  124. package/template/src/theme/Footer/Logo/styles.module.css +9 -0
  125. package/template/src/theme/Footer/index.js +22 -0
  126. package/template/src/theme/MDXComponents/Heading.js +120 -0
  127. package/template/src/theme/MDXComponents/index.js +17 -0
  128. package/template/src/theme/MDXComponents/styles.module.css +110 -0
  129. package/template/src/theme/MDXContent/index.js +6 -0
  130. package/template/src/theme/NavbarItem/DropdownNavbarItem/Desktop/index.js +110 -0
  131. package/template/src/theme/NavbarItem/DropdownNavbarItem/Mobile/index.js +136 -0
  132. package/template/src/theme/NavbarItem/DropdownNavbarItem/Mobile/styles.module.css +3 -0
  133. package/template/src/theme/NavbarItem/DropdownNavbarItem/index.js +7 -0
  134. package/template/src/theme/NotFound/Content/index.js +46 -0
  135. package/template/src/theme/NotFound/index.js +19 -0
  136. package/template/src/theme/NotFound.js +49 -0
  137. package/template/src/theme/PaginatorNavLink/index.js +17 -0
  138. package/template/src/theme/TOC/index.js +19 -0
  139. package/template/src/theme/TOC/styles.module.css +16 -0
  140. package/template/src/theme/TOCItems/Tree.js +30 -0
  141. package/template/src/theme/TOCItems/index.js +47 -0
  142. package/template/src/theme/TabItem/index.js +15 -0
  143. package/template/src/theme/TabItem/styles.module.css +10 -0
  144. package/template/src/theme/Tabs/index.js +189 -0
  145. package/template/src/theme/Tabs/styles.module.css +74 -0
  146. package/template/static/img/favicon.svg +4 -0
  147. package/template/static/img/oops-404.svg +11 -0
  148. package/template/static/searchIndex.json +1 -0
@@ -0,0 +1,167 @@
1
+ .faqToc {
2
+ margin: 1.5rem 0 2rem;
3
+ }
4
+
5
+ .title {
6
+ margin-bottom: 1rem;
7
+ }
8
+
9
+ /* ── Search ── */
10
+
11
+ .searchContainer {
12
+ position: relative;
13
+ display: flex;
14
+ align-items: center;
15
+ margin-bottom: 1rem;
16
+ }
17
+
18
+ .searchIcon {
19
+ position: absolute;
20
+ left: 0.75rem;
21
+ color: var(--ifm-color-emphasis-500);
22
+ pointer-events: none;
23
+ }
24
+
25
+ .searchInput {
26
+ width: 100%;
27
+ padding: 0.625rem 2.25rem 0.625rem 2.5rem;
28
+ font-size: 0.9375rem;
29
+ border: 1px solid var(--ifm-color-emphasis-300);
30
+ border-radius: var(--ifm-global-radius, 0.375rem);
31
+ background: var(--ifm-background-surface-color, var(--ifm-background-color));
32
+ color: var(--ifm-font-color-base);
33
+ transition: border-color 0.2s, box-shadow 0.2s;
34
+ }
35
+
36
+ .searchInput::placeholder {
37
+ color: var(--ifm-color-emphasis-500);
38
+ }
39
+
40
+ .searchInput:focus {
41
+ outline: none;
42
+ border-color: var(--ifm-color-primary);
43
+ box-shadow: 0 0 0 2px var(--ifm-color-primary-lightest, rgba(37, 194, 160, 0.15));
44
+ }
45
+
46
+ .clearButton {
47
+ position: absolute;
48
+ right: 0.5rem;
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ width: 1.5rem;
53
+ height: 1.5rem;
54
+ padding: 0;
55
+ border: none;
56
+ border-radius: 50%;
57
+ background: var(--ifm-color-emphasis-200);
58
+ color: var(--ifm-color-emphasis-700);
59
+ font-size: 0.75rem;
60
+ cursor: pointer;
61
+ transition: background 0.15s;
62
+ }
63
+
64
+ .clearButton:hover {
65
+ background: var(--ifm-color-emphasis-300);
66
+ }
67
+
68
+ /* ── Results ── */
69
+
70
+ .resultCount {
71
+ margin: 0 0 0.75rem;
72
+ font-size: 0.8125rem;
73
+ color: var(--ifm-color-emphasis-600);
74
+ }
75
+
76
+ .noResults {
77
+ padding: 1rem;
78
+ text-align: center;
79
+ color: var(--ifm-color-emphasis-600);
80
+ border: 1px dashed var(--ifm-color-emphasis-300);
81
+ border-radius: var(--ifm-global-radius, 0.375rem);
82
+ }
83
+
84
+ .emptyState {
85
+ padding: 1.5rem;
86
+ text-align: center;
87
+ color: var(--ifm-color-emphasis-600);
88
+ background: var(--ifm-color-emphasis-100);
89
+ border-radius: var(--ifm-global-radius, 0.375rem);
90
+ }
91
+
92
+ /* ── Topic groups ── */
93
+
94
+ .topicGroup {
95
+ margin-bottom: 1.5rem;
96
+ }
97
+
98
+ .topicHeading {
99
+ display: flex;
100
+ align-items: center;
101
+ gap: 0.5rem;
102
+ margin: 0 0 0.25rem;
103
+ padding: 0.875rem 0 0.375rem 0;
104
+ font-size: 1.1rem;
105
+ font-weight: 600;
106
+ border-bottom: 1px solid var(--ifm-color-emphasis-200);
107
+ }
108
+
109
+ .topicLink {
110
+ color: var(--ifm-font-color-base);
111
+ text-decoration: none;
112
+ }
113
+
114
+ .topicLink:hover {
115
+ color: var(--ifm-color-primary);
116
+ text-decoration: underline;
117
+ }
118
+
119
+ .questionCount {
120
+ display: inline-flex;
121
+ align-items: center;
122
+ justify-content: center;
123
+ min-width: 1.375rem;
124
+ height: 1.375rem;
125
+ padding: 0 0.375rem;
126
+ font-size: 0.6875rem;
127
+ font-weight: 600;
128
+ line-height: 1;
129
+ color: var(--ifm-color-emphasis-700);
130
+ background: var(--ifm-color-emphasis-200);
131
+ border-radius: 999px;
132
+ }
133
+
134
+ .topicDescription {
135
+ margin: 0 0 0.375rem;
136
+ font-size: 0.7125rem;
137
+ color: var(--ifm-color-emphasis-600);
138
+ line-height: 1.4;
139
+ }
140
+
141
+ /* ── Question list ── */
142
+
143
+ .questionList {
144
+ list-style: none;
145
+ margin: 0;
146
+ padding: 0;
147
+ line-height: 1;
148
+ }
149
+
150
+ .questionItem {
151
+ margin: 0;
152
+ }
153
+
154
+ .questionLink {
155
+ display: block;
156
+ padding: 0 0 0 1rem;
157
+ font-size: 1rem;
158
+ color: var(--ifm-color-primary);
159
+ text-decoration: none;
160
+ border-left: 2px solid transparent;
161
+ transition: border-color 0.15s, background 0.15s;
162
+ }
163
+
164
+ .questionLink:hover {
165
+ text-decoration: underline;
166
+ border-left-color: var(--ifm-color-primary);
167
+ }
@@ -0,0 +1,310 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import {
3
+ Modal,
4
+ IconButton,
5
+ FormControl,
6
+ FormGroup,
7
+ FormControlLabel,
8
+ Checkbox,
9
+ Button,
10
+ Typography,
11
+ Box,
12
+ TextField,
13
+ useMediaQuery,
14
+ } from '@mui/material';
15
+ import ThumbUpIcon from '@mui/icons-material/ThumbUp';
16
+ import ThumbDownIcon from '@mui/icons-material/ThumbDown';
17
+ import { createTheme } from '@mui/material/styles';
18
+ import { DislikeOptions, LikeOptions, submitFeedback } from './api';
19
+ import { FeedbackType } from './api';
20
+ import { useDoc } from '@docusaurus/theme-common/internal';
21
+ import CloseIcon from '@mui/icons-material/Close';
22
+ import { ThemeClassNames } from '@docusaurus/theme-common';
23
+ import Translate from '@docusaurus/Translate';
24
+ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
25
+
26
+ const theme = createTheme({
27
+ palette: {
28
+ primary: {
29
+ main: '#7c3aed',
30
+ },
31
+ secondary: {
32
+ main: '#2dd4bf',
33
+ light: '#5eead4',
34
+ contrastText: '#f8fafc',
35
+ },
36
+ },
37
+ });
38
+
39
+ // Component for the "Report the Issue" link
40
+ const ReportIssueUrl = ({ onClose }) => {
41
+ const { siteConfig } = useDocusaurusContext();
42
+ const repoUrl = siteConfig?.customFields?.repoUrl || '#';
43
+ const reportIssueUrl = `${repoUrl}/issues/new?title=Issue submitting feedback`;
44
+ return (
45
+ <a
46
+ href={reportIssueUrl}
47
+ target="_blank"
48
+ rel="noreferrer noopener"
49
+ className={ThemeClassNames.common.editThisPage}
50
+ onClick={onClose}
51
+ >
52
+ <Translate
53
+ id="theme.common.openDocIssue"
54
+ description="The link label to report an issue with submitting feedback"
55
+ >
56
+ Report the issue
57
+ </Translate>
58
+ </a>
59
+ );
60
+ };
61
+
62
+ // Modal to thank users for feedback
63
+ const ThankYouModal = ({ open, onClose }) => (
64
+ <Modal open={open} onClose={onClose} aria-labelledby="thank-you-modal-title">
65
+ <Box
66
+ sx={{
67
+ position: 'absolute',
68
+ top: '50%',
69
+ left: '50%',
70
+ transform: 'translate(-50%, -50%)',
71
+ width: '300px',
72
+ bgcolor: 'background.paper',
73
+ color: 'text.primary',
74
+ boxShadow: 24,
75
+ p: 4,
76
+ textAlign: 'center',
77
+ }}
78
+ >
79
+ <IconButton
80
+ sx={{ position: 'absolute', top: 8, right: 8 }}
81
+ onClick={onClose}
82
+ >
83
+ <CloseIcon />
84
+ </IconButton>
85
+ <Typography
86
+ id="thank-you-modal-title"
87
+ variant="h4"
88
+ component="h2"
89
+ sx={{ marginBottom: '0.5em' }}
90
+ >
91
+ Thank you for your feedback!
92
+ </Typography>
93
+ <Typography variant="body1" sx={{ marginBottom: '1em' }}>
94
+ It helps us improve our technical content and user experience.
95
+ </Typography>
96
+ </Box>
97
+ </Modal>
98
+ );
99
+
100
+ // Modal to show an error message for feedback submission
101
+ const OopsModal = ({ open, onClose }) => (
102
+ <Modal open={open} onClose={onClose} aria-labelledby="oops-modal-title">
103
+ <Box
104
+ sx={{
105
+ position: 'absolute',
106
+ top: '50%',
107
+ left: '50%',
108
+ transform: 'translate(-50%, -50%)',
109
+ width: '300px',
110
+ bgcolor: 'background.paper',
111
+ boxShadow: 24,
112
+ p: 4,
113
+ textAlign: 'center',
114
+ color: 'text.primary',
115
+ }}
116
+ >
117
+ <IconButton
118
+ sx={{ position: 'absolute', top: 8, right: 8 }}
119
+ onClick={onClose}
120
+ >
121
+ <CloseIcon />
122
+ </IconButton>
123
+ <Typography
124
+ id="oops-modal-title"
125
+ variant="h4"
126
+ component="h2"
127
+ sx={{ marginBottom: '0.5em' }}
128
+ >
129
+ Oops!
130
+ </Typography>
131
+ <Typography variant="body1" sx={{ marginBottom: '1em' }}>
132
+ It seems there was an issue with submitting your feedback.
133
+ </Typography>
134
+ <Typography variant="body1" sx={{ marginBottom: '1em' }}>
135
+ Try again or <ReportIssueUrl onClose={onClose} />.
136
+ </Typography>
137
+ </Box>
138
+ </Modal>
139
+ );
140
+
141
+ const Feedback = () => {
142
+ const [feedbackType, setFeedbackType] = useState(null);
143
+ const [feedbackOptions, setFeedbackOptions] = useState([]);
144
+ const [textData, setTextData] = useState('');
145
+ const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
146
+ const [thankYouModalOpen, setThankYouModalOpen] = useState(false);
147
+ const [oopsModalOpen, setOopsModalOpen] = useState(false);
148
+ const { metadata } = useDoc();
149
+
150
+ const handleFeedbackChange = (feedback, checked) => {
151
+ if (checked) {
152
+ setFeedbackOptions((prev) => [...prev, feedback]);
153
+ } else {
154
+ setFeedbackOptions((prev) => prev.filter((e) => e !== feedback));
155
+ }
156
+ };
157
+
158
+ const submitModal = async () => {
159
+ try {
160
+ await submitFeedback({
161
+ page: metadata.slug,
162
+ type: feedbackType,
163
+ options: feedbackOptions,
164
+ comment: textData.trim(),
165
+ });
166
+ setFeedbackType(null);
167
+ setFeedbackOptions([]);
168
+ setTextData('');
169
+ setThankYouModalOpen(true);
170
+ } catch (error) {
171
+ setFeedbackType(null);
172
+ setOopsModalOpen(true);
173
+ console.error('Error submitting feedback:', error?.toString?.() || error);
174
+ }
175
+ };
176
+
177
+ const options = useMemo(() => {
178
+ if (feedbackType === FeedbackType.LIKE) return LikeOptions;
179
+ if (feedbackType === FeedbackType.DISLIKE) return DislikeOptions;
180
+ return {};
181
+ }, [feedbackType]);
182
+
183
+ return (
184
+ <div className="container">
185
+ <div className="row">
186
+ <div className="col">
187
+ <div className="col-demo">
188
+ <h4>Was this page helpful?</h4>
189
+ <IconButton
190
+ aria-label="yes"
191
+ onClick={() => setFeedbackType(FeedbackType.LIKE)}
192
+ >
193
+ <ThumbUpIcon color="success" />
194
+ </IconButton>
195
+ <IconButton
196
+ aria-label="no"
197
+ onClick={() => setFeedbackType(FeedbackType.DISLIKE)}
198
+ >
199
+ <ThumbDownIcon color="error" />
200
+ </IconButton>
201
+ </div>
202
+ </div>
203
+ </div>
204
+ <Modal
205
+ open={!!feedbackType}
206
+ onClose={() => setFeedbackType(null)}
207
+ aria-labelledby="modal-title"
208
+ >
209
+ <Box
210
+ sx={{
211
+ position: 'absolute',
212
+ top: '50%',
213
+ left: '50%',
214
+ transform: 'translate(-50%, -50%)',
215
+ width: isSmallScreen ? '90%' : 'auto',
216
+ bgcolor: 'background.paper',
217
+ boxShadow: 24,
218
+ p: 4,
219
+ maxHeight: '90vh',
220
+ overflowY: 'auto',
221
+ }}
222
+ >
223
+ <Typography
224
+ id="modal-title"
225
+ variant="h6"
226
+ component="h2"
227
+ sx={{
228
+ color: 'text.primary',
229
+ fontWeight: 700,
230
+ marginBottom: '0.5em',
231
+ textAlign: 'center',
232
+ }}
233
+ >
234
+ {feedbackType === FeedbackType.LIKE
235
+ ? `What did you like?`
236
+ : `What went wrong?`}
237
+ </Typography>
238
+ <FormControl
239
+ component="fieldset"
240
+ variant="standard"
241
+ sx={{ width: '100%' }}
242
+ >
243
+ <FormGroup>
244
+ {Object.entries(options).map(([value, label]) => (
245
+ <FormControlLabel
246
+ key={value}
247
+ control={
248
+ <Checkbox
249
+ checked={feedbackOptions.includes(value)}
250
+ onChange={(e) =>
251
+ handleFeedbackChange(value, e.target.checked)
252
+ }
253
+ theme={theme}
254
+ color="primary"
255
+ />
256
+ }
257
+ label={
258
+ <Typography sx={{ fontSize: '14px', color: 'text.primary' }}>
259
+ {label}
260
+ </Typography>
261
+ }
262
+ sx={{ alignItems: 'center' }}
263
+ />
264
+ ))}
265
+ {feedbackOptions.find((o) => o.endsWith('ANOTHER_REASON')) && (
266
+ <TextField
267
+ sx={{ fontSize: '12px', marginTop: '1em' }}
268
+ fullWidth
269
+ id="standard-multiline-static"
270
+ size="small"
271
+ multiline
272
+ rows={5}
273
+ variant="filled"
274
+ value={textData}
275
+ onChange={(e) => setTextData(e.target.value)}
276
+ placeholder="Please provide details"
277
+ />
278
+ )}
279
+ </FormGroup>
280
+ <Box
281
+ sx={{
282
+ display: 'flex',
283
+ justifyContent: 'center',
284
+ marginTop: '2em',
285
+ }}
286
+ >
287
+ <Button
288
+ theme={theme}
289
+ color="primary"
290
+ size="small"
291
+ variant="contained"
292
+ onClick={submitModal}
293
+ sx={{ borderRadius: '12px' }}
294
+ >
295
+ Submit
296
+ </Button>
297
+ </Box>
298
+ </FormControl>
299
+ </Box>
300
+ </Modal>
301
+ <ThankYouModal
302
+ open={thankYouModalOpen}
303
+ onClose={() => setThankYouModalOpen(false)}
304
+ />
305
+ <OopsModal open={oopsModalOpen} onClose={() => setOopsModalOpen(false)} />
306
+ </div>
307
+ );
308
+ };
309
+
310
+ export default Feedback;
@@ -0,0 +1,77 @@
1
+ // src/components/Feedback/api.js
2
+
3
+ const getBaseUrl = () => {
4
+ // Only use window.location when in browser context
5
+ if (typeof window === 'undefined') {
6
+ return '/api/feedback';
7
+ }
8
+
9
+ const hostname = window.location.hostname;
10
+
11
+ // Local development - Docusaurus on 3000, feedback server on 3002
12
+ if (hostname === 'localhost' || hostname === '127.0.0.1') {
13
+ return 'http://localhost:3002/api/feedback';
14
+ }
15
+
16
+ // Production - both services behind same domain
17
+ return '/api/feedback';
18
+ }
19
+
20
+ export const FeedbackType = {
21
+ LIKE: 'like',
22
+ DISLIKE: 'dislike'
23
+ }
24
+
25
+ export const LikeOptions = {
26
+ ACCURATE: 'Accurately describes the platform',
27
+ RESOLVE_ISSUE: 'Helped me resolve an issue',
28
+ EASY_TO_FOLLOW: 'Easy to follow and comprehend',
29
+ CLEAR_CODE_SAMPLES: 'Code samples were clear',
30
+ ADOPT_PLATFORM: 'Convinced me to adopt the platform',
31
+ POSITIVE_ANOTHER_REASON: 'Provide details'
32
+ };
33
+
34
+ export const DislikeOptions = {
35
+ INACCURATE: 'Doesn\'t accurately describe the platform',
36
+ NOT_FOUND: 'Couldn\'t find what I was looking for',
37
+ MISSING_INFO: 'Missing important information',
38
+ HARD_TO_UNDERSTAND: 'Hard to understand',
39
+ COMPLICATED: 'Too complicated or unclear',
40
+ CODE_ERRORS: 'Code sample errors',
41
+ NEGATIVE_ANOTHER_REASON: 'Provide details'
42
+ };
43
+
44
+ export const submitFeedback = async (payload) => {
45
+ const url = `${getBaseUrl()}/submit`;
46
+ console.log('Submitting feedback to:', url);
47
+ console.log('Payload:', payload);
48
+
49
+ try {
50
+ const response = await fetch(url, {
51
+ method: 'POST',
52
+ body: JSON.stringify(payload),
53
+ headers: {
54
+ 'Content-Type': 'application/json'
55
+ }
56
+ });
57
+
58
+ if (!response.ok) {
59
+ const errorText = await response.text();
60
+ console.error('Server error:', errorText);
61
+ throw new Error(`Server responded with ${response.status}`);
62
+ }
63
+
64
+ const result = await response.json();
65
+ console.log('Submit success:', result);
66
+ return result;
67
+ } catch (error) {
68
+ console.error('Submit error:', error);
69
+ throw error;
70
+ }
71
+ }
72
+
73
+ export const getFeedbackData = async () => {
74
+ const response = await fetch(getBaseUrl());
75
+ if (!response.ok) throw response;
76
+ return response.json();
77
+ }