11'use client' ;
22
3- import styled from '@emotion/styled' ;
4- import { Checkbox } from '@radix-ui/themes' ;
53import { useState } from 'react' ;
4+ import { Checkbox } from '@radix-ui/themes' ;
5+ import { Clipboard } from 'react-feather' ;
6+
7+ // Import CodeBlock for reference, but we'll implement our own version
8+ // import {CodeBlock} from '../codeBlock';
69
710type DebugSymbolConfigProps = {
811 defaultOptions ?: string [ ] ;
912} ;
1013
14+ // Match the pattern used by the onboarding component
1115const options = [
1216 {
1317 id : 'dsym' ,
14- name : 'dSYM' ,
15- configLine : '' ,
16- comment : 'Debug symbols (dSYM) are uploaded by default. You can disable this by setting upload_debug_symbols: false' ,
18+ name : 'dSYM' ,
1719 required : true
1820 } ,
1921 {
2022 id : 'source-maps' ,
21- name : 'Source Maps' ,
22- configLine : ' upload_source_maps: true\n' ,
23- comment : 'Enabling this option allows Sentry to provide readable stack traces\n # for Flutter web apps.' ,
23+ name : 'Source Maps' ,
2424 required : false
2525 } ,
2626 {
2727 id : 'source-context' ,
28- name : 'Source Context' ,
29- configLine : ' upload_sources: true\n' ,
30- comment : 'Source context uploads your source files to Sentry, allowing you to see\n # the actual code around the location of errors. \n # This only uploads Dart/Flutter code, not native code.' ,
28+ name : 'Source Context' ,
3129 required : false
3230 } ,
3331] ;
@@ -38,6 +36,7 @@ export function DebugSymbolConfig({
3836 // Ensure dsym is always in the selected options
3937 const initialOptions = [ ...new Set ( [ ...defaultOptions , 'dsym' ] ) ] ;
4038 const [ selectedOptions , setSelectedOptions ] = useState < string [ ] > ( initialOptions ) ;
39+ const [ copied , setCopied ] = useState ( false ) ;
4140
4241 const handleOptionToggle = ( optionId : string ) => {
4342 // If it's dsym, don't allow toggling
@@ -53,208 +52,96 @@ export function DebugSymbolConfig({
5352 } ) ;
5453 } ;
5554
56- // Generate the config lines based on selected options
57- const getConfigSnippet = ( ) => {
58- const baseConfig = `sentry:
55+ // Generate YAML content that matches the format in the screenshot
56+ const getYamlContent = ( ) => {
57+ // Format the YAML content to match the screenshot with proper indentation and line breaks
58+ return `sentry:
5959 project: ___PROJECT_SLUG___
6060 org: ___ORG_SLUG___
61- auth_token: ___ORG_AUTH_TOKEN___\n` ;
62-
63- // Add other selected options with their comments
64- const additionalConfig = options
65- . filter ( option => option . id !== 'dsym' && selectedOptions . includes ( option . id ) )
66- . map ( option => `\n # ${ option . comment } \n${ option . configLine } ` )
67- . join ( '' ) ;
68-
69- return baseConfig + additionalConfig ;
61+ auth_token: sntrys_YOUR_TOKEN_HERE${ selectedOptions . includes ( 'source-maps' ) ? '\n upload_source_maps: true' : '' } ${ selectedOptions . includes ( 'source-context' ) ? '\n upload_sources: true' : '' } ` ;
7062 } ;
7163
72- const handleCopyCode = ( ) => {
73- navigator . clipboard . writeText ( getConfigSnippet ( ) ) ;
64+ // Handle copy to clipboard functionality
65+ const handleCopy = async ( ) => {
66+ try {
67+ await navigator . clipboard . writeText ( getYamlContent ( ) ) ;
68+ setCopied ( true ) ;
69+ setTimeout ( ( ) => setCopied ( false ) , 1200 ) ;
70+ } catch ( err ) {
71+ console . error ( 'Failed to copy: ' , err ) ;
72+ }
7473 } ;
7574
7675 return (
77- < Container >
78- < OptionsContainer >
76+ < div className = "mb-6" >
77+ < div className = "flex flex-wrap gap-3 mb-4" >
7978 { options . map ( option => (
80- < OptionButton
79+ < div
8180 key = { option . id }
82- isActive = { selectedOptions . includes ( option . id ) }
83- onClick = { ( ) => handleOptionToggle ( option . id ) }
84- isRequired = { option . required }
81+ className = { `flex items-center px-4 py-2 rounded-md text-sm ${
82+ selectedOptions . includes ( option . id )
83+ ? 'bg-[#6C5FC7] text-white font-semibold'
84+ : 'bg-[#f4f2f7] text-[#2b1d38]'
85+ } ${ option . required ? '' : 'cursor-pointer' } `}
86+ onClick = { ( ) => ! option . required && handleOptionToggle ( option . id ) }
87+ style = { {
88+ minWidth : '160px' ,
89+ justifyContent : 'flex-start' ,
90+ padding : '10px 16px' ,
91+ borderRadius : '6px'
92+ } }
93+ role = { option . required ? undefined : "button" }
94+ tabIndex = { option . required ? undefined : 0 }
95+ onKeyDown = { ( e ) => {
96+ if ( ! option . required && ( e . key === 'Enter' || e . key === ' ' ) ) {
97+ e . preventDefault ( ) ;
98+ handleOptionToggle ( option . id ) ;
99+ }
100+ } }
85101 >
86- < CheckboxWrapper >
102+ < span className = "mr-2 flex items-center" >
87103 < Checkbox
88104 checked = { selectedOptions . includes ( option . id ) }
89105 onCheckedChange = { ( ) => handleOptionToggle ( option . id ) }
90106 disabled = { option . required }
107+ style = { {
108+ color : selectedOptions . includes ( option . id ) ? 'white' : undefined
109+ } }
91110 />
92- </ CheckboxWrapper >
111+ </ span >
93112 { option . name }
94- </ OptionButton >
113+ </ div >
95114 ) ) }
96- </ OptionsContainer >
97- < Content >
98- < CodeBlockContainer >
99- < CodeBlockHeader >
100- < CodeLanguage > YAML</ CodeLanguage >
101- < HeaderRight >
102- < FileName > pubspec.yaml</ FileName >
103- < CopyButton onClick = { handleCopyCode } >
104- < CopyIcon viewBox = "0 0 24 24" xmlns = "http://www.w3.org/2000/svg" >
105- < path d = "M16 1H4C2.9 1 2 1.9 2 3V17H4V3H16V1ZM19 5H8C6.9 5 6 5.9 6 7V21C6 22.1 6.9 23 8 23H19C20.1 23 21 22.1 21 21V7C21 5.9 20.1 5 19 5ZM19 21H8V7H19V21Z" />
106- </ CopyIcon >
107- </ CopyButton >
108- </ HeaderRight >
109- </ CodeBlockHeader >
110- < CodeBlock >
111- { getConfigSnippet ( ) }
112- </ CodeBlock >
113- </ CodeBlockContainer >
114-
115- { selectedOptions . includes ( 'dsym' ) && (
116- < DescriptionSection >
117- < DescriptionTitle > Debug Symbols (dSYM)</ DescriptionTitle >
118- < Description >
119- Debug symbols (dSYM) are uploaded by default. You can disable this by setting the `upload_debug_symbols` option to `false`.
120- </ Description >
121- </ DescriptionSection >
115+ </ div >
116+
117+ { /* Custom Code Block Implementation */ }
118+ < div className = "relative mb-6" >
119+ { /* Code Block Header */ }
120+ < div className = "flex justify-between items-center bg-[#2b1d38] px-3 py-2 rounded-t-md" >
121+ < div className = "text-white text-xs font-medium" > YAML</ div >
122+ < div className = "flex items-center" >
123+ < span className = "text-white text-xs mr-3" > pubspec.yaml</ span >
124+ < button
125+ className = "text-white hover:bg-[rgba(255,255,255,0.2)] p-1 rounded"
126+ onClick = { handleCopy }
127+ >
128+ < Clipboard size = { 16 } />
129+ </ button >
130+ </ div >
131+ </ div >
132+
133+ { /* Code Block Content */ }
134+ < pre className = "bg-[#1e1225] text-white p-4 rounded-b-md m-0 overflow-auto font-mono text-sm" >
135+ { getYamlContent ( ) }
136+ </ pre >
137+
138+ { /* Copied Notification */ }
139+ { copied && (
140+ < div className = "absolute top-2 right-2 bg-[rgba(255,255,255,0.25)] text-white px-2 py-1 rounded text-xs" >
141+ Copied
142+ </ div >
122143 ) }
123- </ Content >
124- </ Container >
144+ </ div >
145+ </ div >
125146 ) ;
126- }
127-
128- const Container = styled ( 'div' ) `
129- margin: 20px 0;
130- ` ;
131-
132- const OptionsContainer = styled ( 'div' ) `
133- display: flex;
134- flex-wrap: wrap;
135- gap: 12px;
136- margin-bottom: 16px;
137- ` ;
138-
139- const CheckboxWrapper = styled ( 'span' ) `
140- margin-right: 8px;
141- display: flex;
142- align-items: center;
143- ` ;
144-
145- const OptionButton = styled ( 'button' ) < { isActive : boolean ; isRequired ?: boolean } > `
146- padding: 8px 16px;
147- background: ${ props => ( props . isActive ? '#6C5FC7' : '#f4f2f7' ) } ;
148- color: ${ props => ( props . isActive ? 'white' : '#2b1d38' ) } ;
149- border: none;
150- border-radius: 6px;
151- cursor: ${ props => ( props . isRequired ? 'default' : 'pointer' ) } ;
152- font-weight: ${ props => ( props . isActive ? 'bold' : 'normal' ) } ;
153- font-size: 14px;
154- display: flex;
155- align-items: center;
156-
157- &:hover {
158- background: ${ props => {
159- if ( props . isRequired ) return props . isActive ? '#6C5FC7' : '#f4f2f7' ;
160- return props . isActive ? '#6C5FC7' : '#e7e1ef' ;
161- } } ;
162- }
163-
164- &:focus {
165- outline: none;
166- box-shadow: ${ props => ( props . isRequired ? 'none' : '0 0 0 2px rgba(108, 95, 199, 0.3)' ) } ;
167- }
168- ` ;
169-
170- const Content = styled ( 'div' ) `
171- padding: 16px;
172- border: 1px solid #e2e2e2;
173- border-radius: 4px;
174- background: #f8f8f8;
175- ` ;
176-
177- const CodeBlockContainer = styled ( 'div' ) `
178- border-radius: 4px;
179- overflow: hidden;
180- margin-bottom: 16px;
181- font-family: monospace;
182- ` ;
183-
184- const CodeBlockHeader = styled ( 'div' ) `
185- display: flex;
186- justify-content: space-between;
187- align-items: center;
188- background: #211634;
189- padding: 8px 16px;
190- color: white;
191- border-bottom: 1px solid #362a45;
192- ` ;
193-
194- const CodeLanguage = styled ( 'div' ) `
195- font-size: 14px;
196- font-weight: bold;
197- ` ;
198-
199- const HeaderRight = styled ( 'div' ) `
200- display: flex;
201- align-items: center;
202- ` ;
203-
204- const FileName = styled ( 'div' ) `
205- font-size: 14px;
206- margin-right: 12px;
207- ` ;
208-
209- const CopyButton = styled ( 'button' ) `
210- background: transparent;
211- border: none;
212- cursor: pointer;
213- display: flex;
214- align-items: center;
215- justify-content: center;
216- padding: 4px;
217-
218- &:hover {
219- opacity: 0.8;
220- }
221-
222- &:focus {
223- outline: none;
224- }
225- ` ;
226-
227- const CopyIcon = styled ( 'svg' ) `
228- width: 18px;
229- height: 18px;
230- fill: white;
231- ` ;
232-
233- const CodeBlock = styled ( 'pre' ) `
234- padding: 16px;
235- background: #2b1d38;
236- color: white;
237- overflow-x: auto;
238- margin: 0;
239- ` ;
240-
241- const DescriptionSection = styled ( 'div' ) `
242- margin-bottom: 20px;
243- padding-bottom: 20px;
244- border-bottom: 1px solid #e2e2e2;
245-
246- &:last-child {
247- margin-bottom: 0;
248- padding-bottom: 0;
249- border-bottom: none;
250- }
251- ` ;
252-
253- const DescriptionTitle = styled ( 'h4' ) `
254- margin: 0 0 8px 0;
255- ` ;
256-
257- const Description = styled ( 'p' ) `
258- margin: 0 0 16px 0;
259- line-height: 1.5;
260- ` ;
147+ }
0 commit comments