polen 0.10.0-next.16 → 0.10.0-next.18

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 (37) hide show
  1. package/build/api/config/configurator.d.ts +13 -1
  2. package/build/api/config/configurator.d.ts.map +1 -1
  3. package/build/api/config/configurator.js +10 -1
  4. package/build/api/config/configurator.js.map +1 -1
  5. package/build/lib/graphql-document/components/GraphQLDocument.d.ts +0 -2
  6. package/build/lib/graphql-document/components/GraphQLDocument.d.ts.map +1 -1
  7. package/build/lib/graphql-document/components/GraphQLDocument.js +5 -5
  8. package/build/lib/graphql-document/components/GraphQLDocument.js.map +1 -1
  9. package/build/lib/graphql-document/components/GraphQLDocumentWithSchema.d.ts +1 -1
  10. package/build/lib/graphql-document/components/GraphQLDocumentWithSchema.d.ts.map +1 -1
  11. package/build/lib/graphql-document/components/GraphQLDocumentWithSchema.js +1 -3
  12. package/build/lib/graphql-document/components/GraphQLDocumentWithSchema.js.map +1 -1
  13. package/build/lib/graphql-document/positioning-simple.d.ts +1 -1
  14. package/build/lib/graphql-document/positioning-simple.js +1 -1
  15. package/build/template/entry.client.d.ts +0 -1
  16. package/build/template/entry.client.d.ts.map +1 -1
  17. package/build/template/entry.client.js +0 -1
  18. package/build/template/entry.client.js.map +1 -1
  19. package/build/template/routes/root.d.ts.map +1 -1
  20. package/build/template/routes/root.js +2 -3
  21. package/build/template/routes/root.js.map +1 -1
  22. package/package.json +2 -3
  23. package/src/api/config/configurator.ts +25 -2
  24. package/src/lib/graphql-document/components/GraphQLDocument.tsx +7 -12
  25. package/src/lib/graphql-document/components/GraphQLDocumentWithSchema.tsx +1 -6
  26. package/src/lib/graphql-document/demo.md +1 -1
  27. package/src/lib/graphql-document/positioning-simple.test.ts +5 -5
  28. package/src/lib/graphql-document/positioning-simple.ts +1 -1
  29. package/src/template/entry.client.tsx +0 -1
  30. package/src/template/routes/root.tsx +0 -2
  31. package/build/template/components/CodeBlockEnhancer.d.ts +0 -2
  32. package/build/template/components/CodeBlockEnhancer.d.ts.map +0 -1
  33. package/build/template/components/CodeBlockEnhancer.js +0 -175
  34. package/build/template/components/CodeBlockEnhancer.js.map +0 -1
  35. package/build/template/styles/code-block.css +0 -218
  36. package/src/template/components/CodeBlockEnhancer.tsx +0 -192
  37. package/src/template/styles/code-block.css +0 -218
@@ -1,175 +0,0 @@
1
- import { useEffect } from 'react';
2
- import { useLocation } from 'react-router';
3
- import { useTheme } from '../contexts/ThemeContext.js';
4
- export const CodeBlockEnhancer = () => {
5
- const { appearance } = useTheme();
6
- const location = useLocation();
7
- useEffect(() => {
8
- // Add styles for code block enhancements
9
- const styleId = `code-block-enhancer-styles`;
10
- let styleElement = document.getElementById(styleId);
11
- if (!styleElement) {
12
- styleElement = document.createElement(`style`);
13
- styleElement.id = styleId;
14
- document.head.appendChild(styleElement);
15
- }
16
- styleElement.textContent = `
17
- /* Enhanced code block styles */
18
- pre.shiki {
19
- position: relative;
20
- }
21
-
22
- pre.shiki[data-title] {
23
- margin-top: 0;
24
- border-radius: 0 0 8px 8px !important;
25
- }
26
-
27
- pre.shiki[data-title]::before {
28
- content: attr(data-title);
29
- display: block;
30
- position: absolute;
31
- top: -2.5rem;
32
- left: -1px;
33
- right: -1px;
34
- background-color: ${appearance === `dark` ? `#2a2b3d` : `#f3f4f6`};
35
- border: 1px solid var(--gray-4);
36
- border-bottom: 1px solid ${appearance === `dark` ? `#3a3b4d` : `#e5e7eb`};
37
- border-radius: 8px 8px 0 0;
38
- padding: 0.5rem 1rem;
39
- font-size: 0.875rem;
40
- font-weight: 500;
41
- color: var(--gray-11);
42
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
43
- }
44
-
45
- pre.shiki[data-title][data-language]::after {
46
- content: attr(data-language);
47
- position: absolute;
48
- top: -2rem;
49
- right: 1rem;
50
- font-size: 0.75rem;
51
- color: var(--gray-9);
52
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
53
- }
54
-
55
- .code-block-copy {
56
- position: absolute;
57
- top: 0.5rem;
58
- right: 0.5rem;
59
- padding: 0.25rem 0.5rem;
60
- font-size: 0.75rem;
61
- cursor: pointer;
62
- border: none;
63
- border-radius: 4px;
64
- transition: all 0.2s;
65
- background-color: ${appearance === `dark` ? `rgba(0, 0, 0, 0.5)` : `rgba(255, 255, 255, 0.8)`};
66
- backdrop-filter: blur(4px);
67
- color: ${appearance === `dark` ? `#fff` : `#000`};
68
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
69
- }
70
-
71
- pre.shiki[data-title] .code-block-copy {
72
- top: -2rem;
73
- right: 6rem;
74
- background-color: transparent;
75
- color: var(--gray-11);
76
- }
77
-
78
- .code-block-copy:hover {
79
- background-color: var(--accent-9) !important;
80
- color: white !important;
81
- }
82
-
83
- .code-block-copy[data-copied="true"] {
84
- background-color: var(--green-9) !important;
85
- color: white !important;
86
- }
87
- `;
88
- return () => {
89
- if (styleElement && styleElement.parentNode) {
90
- styleElement.parentNode.removeChild(styleElement);
91
- }
92
- };
93
- }, [appearance]);
94
- useEffect(() => {
95
- const enhanceCodeBlocks = () => {
96
- const codeBlocks = document.querySelectorAll(`pre.shiki:not([data-enhanced])`);
97
- codeBlocks.forEach((block) => {
98
- const preElement = block;
99
- preElement.setAttribute(`data-enhanced`, `true`);
100
- // Get language from class name
101
- const classes = preElement.className.split(` `);
102
- const language = classes.find(c => c !== `shiki` && c !== `shiki-light` && c !== `shiki-dark`) || `text`;
103
- // Check for title in first line
104
- const codeElement = preElement.querySelector(`code`);
105
- if (!codeElement)
106
- return;
107
- const firstLine = codeElement.textContent?.split(`\n`)[0] || ``;
108
- let title = ``;
109
- const titleMatch = /^\/\/\s*title:\s*(.+)$/i.exec(firstLine);
110
- if (titleMatch?.[1]) {
111
- title = titleMatch[1];
112
- // Remove title line from display
113
- const firstLineElement = codeElement.querySelector(`span.line`);
114
- if (firstLineElement) {
115
- firstLineElement.style.display = `none`;
116
- }
117
- // Set data attributes for CSS
118
- preElement.setAttribute(`data-title`, title);
119
- preElement.setAttribute(`data-language`, language);
120
- preElement.style.marginTop = `3rem`;
121
- }
122
- // Create copy button
123
- const copyButton = document.createElement(`button`);
124
- copyButton.className = `code-block-copy`;
125
- copyButton.textContent = `Copy`;
126
- copyButton.setAttribute(`data-copied`, `false`);
127
- copyButton.onclick = async (e) => {
128
- e.preventDefault();
129
- e.stopPropagation();
130
- // Get clean code without the title line
131
- const code = codeElement.textContent || ``;
132
- const cleanCode = title ? code.split(`\n`).slice(1).join(`\n`) : code;
133
- try {
134
- await navigator.clipboard.writeText(cleanCode);
135
- copyButton.textContent = `Copied!`;
136
- copyButton.setAttribute(`data-copied`, `true`);
137
- setTimeout(() => {
138
- copyButton.textContent = `Copy`;
139
- copyButton.setAttribute(`data-copied`, `false`);
140
- }, 2000);
141
- }
142
- catch (err) {
143
- console.error(`Failed to copy:`, err);
144
- }
145
- };
146
- // Append copy button directly to pre element
147
- preElement.appendChild(copyButton);
148
- });
149
- };
150
- // Small delay to ensure DOM is ready
151
- const timeoutId = setTimeout(enhanceCodeBlocks, 100);
152
- return () => {
153
- clearTimeout(timeoutId);
154
- // Clean up enhanced code blocks
155
- document.querySelectorAll(`pre.shiki[data-enhanced]`).forEach(block => {
156
- block.removeAttribute(`data-enhanced`);
157
- block.removeAttribute(`data-title`);
158
- block.removeAttribute(`data-language`);
159
- const copyButton = block.querySelector(`.code-block-copy`);
160
- if (copyButton) {
161
- copyButton.remove();
162
- }
163
- // Restore hidden title lines
164
- const firstLine = block.querySelector(`span.line`);
165
- if (firstLine && firstLine.style.display === `none`) {
166
- firstLine.style.display = ``;
167
- } // Reset margin
168
- ;
169
- block.style.marginTop = ``;
170
- });
171
- };
172
- }, [location.pathname]); // Re-run when route changes
173
- return null;
174
- };
175
- //# sourceMappingURL=CodeBlockEnhancer.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CodeBlockEnhancer.js","sourceRoot":"","sources":["../../../src/template/components/CodeBlockEnhancer.tsx"],"names":[],"mappings":"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"}
@@ -1,218 +0,0 @@
1
- /* Code Block Styles */
2
-
3
- /* Base code block container */
4
- .code-block {
5
- position: relative;
6
- margin: 1rem 0;
7
- border-radius: 8px;
8
- overflow: hidden;
9
- font-size: 14px;
10
- line-height: 1.6;
11
- }
12
-
13
- .code-block pre {
14
- margin: 0;
15
- padding: 1rem;
16
- overflow-x: auto;
17
- background: inherit;
18
- }
19
-
20
- .code-block code {
21
- font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', Consolas, 'Liberation Mono', Menlo, monospace;
22
- font-variant-ligatures: contextual;
23
- }
24
-
25
- /* Shiki theme switching with CSS variables */
26
- /* Default to light theme */
27
- :root {
28
- color-scheme: light;
29
- }
30
-
31
- /* When dark mode is active */
32
- .dark {
33
- color-scheme: dark;
34
- }
35
-
36
- /* Shiki token colors for light theme (github-light) */
37
- :root {
38
- --shiki-color-text: #24292e;
39
- --shiki-color-background: #f6f8fa;
40
- --shiki-token-constant: #005cc5;
41
- --shiki-token-string: #032f62;
42
- --shiki-token-comment: #6a737d;
43
- --shiki-token-keyword: #d73a49;
44
- --shiki-token-parameter: #e36209;
45
- --shiki-token-function: #6f42c1;
46
- --shiki-token-string-expression: #032f62;
47
- --shiki-token-punctuation: #24292e;
48
- --shiki-token-link: #032f62;
49
- }
50
-
51
- /* Shiki token colors for dark theme (tokyo-night) */
52
- .dark {
53
- --shiki-color-text: #c0caf5;
54
- --shiki-color-background: #1a1b26;
55
- --shiki-token-constant: #ff9e64;
56
- --shiki-token-string: #9ece6a;
57
- --shiki-token-comment: #565f89;
58
- --shiki-token-keyword: #bb9af7;
59
- --shiki-token-parameter: #e0af68;
60
- --shiki-token-function: #7aa2f7;
61
- --shiki-token-string-expression: #9ece6a;
62
- --shiki-token-punctuation: #c0caf5;
63
- --shiki-token-link: #9ece6a;
64
- }
65
-
66
- /* Shiki code blocks */
67
- pre.shiki {
68
- margin: 1rem 0;
69
- padding: 1rem;
70
- border-radius: 8px;
71
- overflow-x: auto;
72
- font-size: 14px;
73
- line-height: 1.6;
74
- background-color: var(--shiki-color-background);
75
- color: var(--shiki-color-text);
76
- }
77
-
78
- pre.shiki code {
79
- font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', Consolas, 'Liberation Mono', Menlo, monospace;
80
- font-variant-ligatures: contextual;
81
- }
82
-
83
- /* Line numbers */
84
- .code-block[data-line-numbers="true"] pre {
85
- padding-left: 3.5rem;
86
- position: relative;
87
- }
88
-
89
- .code-block[data-line-numbers="true"] .line {
90
- position: relative;
91
- }
92
-
93
- .code-block[data-line-numbers="true"] .line::before {
94
- content: attr(data-line);
95
- position: absolute;
96
- left: -3rem;
97
- width: 2.5rem;
98
- text-align: right;
99
- color: var(--gray-a6);
100
- user-select: none;
101
- }
102
-
103
- /* Line highlighting */
104
- .code-block .line[data-highlighted="true"] {
105
- background-color: var(--amber-a3);
106
- display: block;
107
- margin: 0 -1rem;
108
- padding: 0 1rem;
109
- }
110
-
111
- /* Diff lines */
112
- .code-block .line[data-diff="+"] {
113
- background-color: var(--green-a3);
114
- display: block;
115
- margin: 0 -1rem;
116
- padding: 0 1rem;
117
- }
118
-
119
- .code-block .line[data-diff="-"] {
120
- background-color: var(--red-a3);
121
- display: block;
122
- margin: 0 -1rem;
123
- padding: 0 1rem;
124
- }
125
-
126
- .code-block .line[data-diff="+"]::before {
127
- content: "+ ";
128
- color: var(--green-11);
129
- font-weight: bold;
130
- }
131
-
132
- .code-block .line[data-diff="-"]::before {
133
- content: "- ";
134
- color: var(--red-11);
135
- font-weight: bold;
136
- }
137
-
138
- /* Focus lines */
139
- .code-block .line:not([data-focus="true"]) {
140
- opacity: 0.5;
141
- filter: grayscale(100%);
142
- transition: opacity 0.2s, filter 0.2s;
143
- }
144
-
145
- .code-block:hover .line:not([data-focus="true"]) {
146
- opacity: 0.8;
147
- filter: grayscale(0%);
148
- }
149
-
150
- /* Copy button */
151
- .code-block-copy {
152
- position: absolute;
153
- top: 0.5rem;
154
- right: 0.5rem;
155
- padding: 0.25rem 0.5rem;
156
- border-radius: 4px;
157
- background: var(--gray-a3);
158
- color: var(--gray-12);
159
- border: 1px solid var(--gray-a5);
160
- cursor: pointer;
161
- font-size: 12px;
162
- transition: all 0.2s;
163
- }
164
-
165
- .code-block-copy:hover {
166
- background: var(--gray-a4);
167
- border-color: var(--gray-a6);
168
- }
169
-
170
- .code-block-copy.copied {
171
- background: var(--green-a3);
172
- border-color: var(--green-a5);
173
- color: var(--green-11);
174
- }
175
-
176
- /* Language badge */
177
- .code-block-lang {
178
- position: absolute;
179
- top: 0;
180
- right: 0;
181
- padding: 0.25rem 0.75rem;
182
- background: var(--gray-a3);
183
- color: var(--gray-11);
184
- font-size: 12px;
185
- font-weight: 500;
186
- border-bottom-left-radius: 4px;
187
- user-select: none;
188
- }
189
-
190
- /* Scrollbar styling */
191
- .code-block pre::-webkit-scrollbar {
192
- height: 8px;
193
- width: 8px;
194
- }
195
-
196
- .code-block pre::-webkit-scrollbar-track {
197
- background: var(--gray-a3);
198
- border-radius: 4px;
199
- }
200
-
201
- .code-block pre::-webkit-scrollbar-thumb {
202
- background: var(--gray-a6);
203
- border-radius: 4px;
204
- }
205
-
206
- .code-block pre::-webkit-scrollbar-thumb:hover {
207
- background: var(--gray-a7);
208
- }
209
-
210
- /* Inline code */
211
- code:not(.code-block code) {
212
- padding: 0.2em 0.4em;
213
- margin: 0;
214
- font-size: 0.85em;
215
- background-color: var(--gray-a3);
216
- border-radius: 4px;
217
- font-family: 'JetBrains Mono', 'Fira Code', 'SF Mono', Consolas, 'Liberation Mono', Menlo, monospace;
218
- }
@@ -1,192 +0,0 @@
1
- import { useEffect } from 'react'
2
- import { useLocation } from 'react-router'
3
- import { useTheme } from '../contexts/ThemeContext.js'
4
-
5
- export const CodeBlockEnhancer = () => {
6
- const { appearance } = useTheme()
7
- const location = useLocation()
8
-
9
- useEffect(() => {
10
- // Add styles for code block enhancements
11
- const styleId = `code-block-enhancer-styles`
12
- let styleElement = document.getElementById(styleId) as HTMLStyleElement
13
-
14
- if (!styleElement) {
15
- styleElement = document.createElement(`style`)
16
- styleElement.id = styleId
17
- document.head.appendChild(styleElement)
18
- }
19
-
20
- styleElement.textContent = `
21
- /* Enhanced code block styles */
22
- pre.shiki {
23
- position: relative;
24
- }
25
-
26
- pre.shiki[data-title] {
27
- margin-top: 0;
28
- border-radius: 0 0 8px 8px !important;
29
- }
30
-
31
- pre.shiki[data-title]::before {
32
- content: attr(data-title);
33
- display: block;
34
- position: absolute;
35
- top: -2.5rem;
36
- left: -1px;
37
- right: -1px;
38
- background-color: ${appearance === `dark` ? `#2a2b3d` : `#f3f4f6`};
39
- border: 1px solid var(--gray-4);
40
- border-bottom: 1px solid ${appearance === `dark` ? `#3a3b4d` : `#e5e7eb`};
41
- border-radius: 8px 8px 0 0;
42
- padding: 0.5rem 1rem;
43
- font-size: 0.875rem;
44
- font-weight: 500;
45
- color: var(--gray-11);
46
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
47
- }
48
-
49
- pre.shiki[data-title][data-language]::after {
50
- content: attr(data-language);
51
- position: absolute;
52
- top: -2rem;
53
- right: 1rem;
54
- font-size: 0.75rem;
55
- color: var(--gray-9);
56
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
57
- }
58
-
59
- .code-block-copy {
60
- position: absolute;
61
- top: 0.5rem;
62
- right: 0.5rem;
63
- padding: 0.25rem 0.5rem;
64
- font-size: 0.75rem;
65
- cursor: pointer;
66
- border: none;
67
- border-radius: 4px;
68
- transition: all 0.2s;
69
- background-color: ${appearance === `dark` ? `rgba(0, 0, 0, 0.5)` : `rgba(255, 255, 255, 0.8)`};
70
- backdrop-filter: blur(4px);
71
- color: ${appearance === `dark` ? `#fff` : `#000`};
72
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
73
- }
74
-
75
- pre.shiki[data-title] .code-block-copy {
76
- top: -2rem;
77
- right: 6rem;
78
- background-color: transparent;
79
- color: var(--gray-11);
80
- }
81
-
82
- .code-block-copy:hover {
83
- background-color: var(--accent-9) !important;
84
- color: white !important;
85
- }
86
-
87
- .code-block-copy[data-copied="true"] {
88
- background-color: var(--green-9) !important;
89
- color: white !important;
90
- }
91
- `
92
-
93
- return () => {
94
- if (styleElement && styleElement.parentNode) {
95
- styleElement.parentNode.removeChild(styleElement)
96
- }
97
- }
98
- }, [appearance])
99
-
100
- useEffect(() => {
101
- const enhanceCodeBlocks = () => {
102
- const codeBlocks = document.querySelectorAll(`pre.shiki:not([data-enhanced])`)
103
-
104
- codeBlocks.forEach((block) => {
105
- const preElement = block as HTMLPreElement
106
- preElement.setAttribute(`data-enhanced`, `true`)
107
-
108
- // Get language from class name
109
- const classes = preElement.className.split(` `)
110
- const language = classes.find(c => c !== `shiki` && c !== `shiki-light` && c !== `shiki-dark`) || `text`
111
-
112
- // Check for title in first line
113
- const codeElement = preElement.querySelector(`code`)
114
- if (!codeElement) return
115
-
116
- const firstLine = codeElement.textContent?.split(`\n`)[0] || ``
117
- let title = ``
118
-
119
- const titleMatch = /^\/\/\s*title:\s*(.+)$/i.exec(firstLine)
120
- if (titleMatch?.[1]) {
121
- title = titleMatch[1]
122
- // Remove title line from display
123
- const firstLineElement = codeElement.querySelector(`span.line`) as HTMLElement | null
124
- if (firstLineElement) {
125
- firstLineElement.style.display = `none`
126
- }
127
-
128
- // Set data attributes for CSS
129
- preElement.setAttribute(`data-title`, title)
130
- preElement.setAttribute(`data-language`, language)
131
- preElement.style.marginTop = `3rem`
132
- }
133
-
134
- // Create copy button
135
- const copyButton = document.createElement(`button`)
136
- copyButton.className = `code-block-copy`
137
- copyButton.textContent = `Copy`
138
- copyButton.setAttribute(`data-copied`, `false`)
139
-
140
- copyButton.onclick = async (e) => {
141
- e.preventDefault()
142
- e.stopPropagation()
143
-
144
- // Get clean code without the title line
145
- const code = codeElement.textContent || ``
146
- const cleanCode = title ? code.split(`\n`).slice(1).join(`\n`) : code
147
-
148
- try {
149
- await navigator.clipboard.writeText(cleanCode)
150
- copyButton.textContent = `Copied!`
151
- copyButton.setAttribute(`data-copied`, `true`)
152
- setTimeout(() => {
153
- copyButton.textContent = `Copy`
154
- copyButton.setAttribute(`data-copied`, `false`)
155
- }, 2000)
156
- } catch (err) {
157
- console.error(`Failed to copy:`, err)
158
- }
159
- }
160
-
161
- // Append copy button directly to pre element
162
- preElement.appendChild(copyButton)
163
- })
164
- }
165
-
166
- // Small delay to ensure DOM is ready
167
- const timeoutId = setTimeout(enhanceCodeBlocks, 100)
168
-
169
- return () => {
170
- clearTimeout(timeoutId)
171
- // Clean up enhanced code blocks
172
- document.querySelectorAll(`pre.shiki[data-enhanced]`).forEach(block => {
173
- block.removeAttribute(`data-enhanced`)
174
- block.removeAttribute(`data-title`)
175
- block.removeAttribute(`data-language`)
176
- const copyButton = block.querySelector(`.code-block-copy`)
177
- if (copyButton) {
178
- copyButton.remove()
179
- }
180
- // Restore hidden title lines
181
- const firstLine = block.querySelector(`span.line`) as HTMLElement | null
182
- if (firstLine && firstLine.style.display === `none`) {
183
- firstLine.style.display = ``
184
- } // Reset margin
185
-
186
- ;(block as HTMLElement).style.marginTop = ``
187
- })
188
- }
189
- }, [location.pathname]) // Re-run when route changes
190
-
191
- return null
192
- }