Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit b7c3f27

Browse files
committed
cleaner navbar implementation
1 parent cfb77ae commit b7c3f27

File tree

1 file changed

+107
-67
lines changed

1 file changed

+107
-67
lines changed

‎src/content-script/update-solutions-tab.ts

Lines changed: 107 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,40 @@
11
const VIDEO_ASPECT_RATIO = 56.25; // 16:9 aspect ratio
22

3+
// Create a wrapper for all our custom content
4+
function createCustomContentWrapper() {
5+
const wrapper = createStyledElement('div', {
6+
width: '100%',
7+
maxWidth: '800px',
8+
margin: '0 auto 32px auto',
9+
position: 'relative',
10+
zIndex: '1'
11+
});
12+
wrapper.classList.add('leetcode-explained-wrapper');
13+
return wrapper;
14+
}
15+
316
// Utility function to create a styled button
417
function createStyledButton(text: string, isActive: boolean = false): HTMLButtonElement {
518
const button = document.createElement('button');
619
button.textContent = text;
20+
button.classList.add('nav-button');
21+
if (isActive) button.classList.add('active');
722

823
chrome.storage.local.get(['isDarkTheme'], (result) => {
924
const isDark = result.isDarkTheme;
1025
button.style.backgroundColor = isDark ? '#373737' : '#f3f4f5';
1126
button.style.color = isDark ? '#fff' : '#1a1a1a';
1227
button.style.border = `1px solid ${isDark ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'}`;
1328

14-
15-
// on hover just make the background a few shades darker or lighter
1629
button.addEventListener('mouseenter', () => {
17-
button.style.backgroundColor = isDark ? '#424242' : '#e6e6e6';
30+
if (!button.classList.contains('active')) {
31+
button.style.backgroundColor = isDark ? '#424242' : '#e6e6e6';
32+
}
1833
});
1934
button.addEventListener('mouseleave', () => {
20-
button.style.backgroundColor = isDark ? '#373737' : '#f3f4f5';
35+
if (!button.classList.contains('active')) {
36+
button.style.backgroundColor = isDark ? '#373737' : '#f3f4f5';
37+
}
2138
});
2239
});
2340

@@ -28,6 +45,7 @@ function createStyledButton(text: string, isActive: boolean = false): HTMLButton
2845
button.style.fontSize = '11px';
2946
button.style.transition = 'all 0.2s ease';
3047
button.style.letterSpacing = '0.5px';
48+
button.style.cursor = 'pointer';
3149

3250
return button;
3351
}
@@ -47,7 +65,7 @@ function createVideoContainer(problem: any) {
4765
maxWidth: '800px',
4866
margin: '0 auto',
4967
});
50-
container.classList.add('video-container');
68+
container.classList.add('video-container','content-section');
5169

5270
const controlsContainer = createStyledElement('div', {
5371
display: 'flex',
@@ -101,7 +119,6 @@ function createVideoContainer(problem: any) {
101119

102120
chrome.storage.local.get(['isDarkTheme'], (result) => {
103121
const isDark = result.isDarkTheme;
104-
// channel element is white on dark mode and black on light mode
105122
channelElement.style.color = isDark ? '#fff' : '#1a1a1a';
106123
});
107124

@@ -153,17 +170,26 @@ function updateVideo(iframe: HTMLIFrameElement, videoUrl: string) {
153170
}
154171

155172
function createCodeContainer() {
173+
const container = createStyledElement('div', {
174+
display: 'none',
175+
width: '100%',
176+
maxWidth: '800px',
177+
margin: '0 auto',
178+
position: 'relative'
179+
});
180+
container.classList.add('code-section', 'content-section');
181+
156182
const codeElement = document.createElement('pre');
157183
codeElement.classList.add('code-container');
158-
codeElement.style.display = 'none';
184+
codeElement.style.display = 'block';
159185
codeElement.style.borderRadius = '8px';
160186
codeElement.style.padding = '16px';
161187
codeElement.style.marginTop = '24px';
162-
codeElement.style.width = '95%';
188+
codeElement.style.width = '100%';
163189
codeElement.style.fontSize = '14px';
164-
codeElement.style.marginLeft = '2.5%';
165190
codeElement.style.maxHeight = '500px';
166191
codeElement.style.overflowY = 'auto';
192+
codeElement.style.boxSizing = 'border-box';
167193
codeElement.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
168194

169195
chrome.storage.local.get(['isDarkTheme'], (result) => {
@@ -173,24 +199,52 @@ function createCodeContainer() {
173199
codeElement.style.color = isDark ? '#fff' : '#1a1a1a';
174200
});
175201

176-
return codeElement;
202+
container.appendChild(codeElement);
203+
return container;
177204
}
178205

179-
function hideContent() {
180-
constelements=[
181-
'.code-container',
182-
'.language-buttons-container',
183-
'.video-container'
184-
].map(selector=>document.querySelector(selector)asHTMLElement);
206+
function showContent(type: 'Discussion'|'Video'|'Code') {
207+
// Hide all content sections first
208+
constcontentSections=document.querySelectorAll('.content-section');
209+
contentSections.forEach(section=>{
210+
(sectionasHTMLElement).style.display='none';
211+
});
185212

186-
elements.forEach(element => {
187-
if (element) {
188-
if (element.classList.contains('video-container')) {
189-
element.style.paddingBottom = '0';
213+
// Show the selected content
214+
switch (type) {
215+
case 'Video':
216+
const videoContainer = document.querySelector('.video-container') as HTMLElement;
217+
if (videoContainer) {
218+
videoContainer.style.display = 'flex';
219+
videoContainer.style.paddingBottom = `${VIDEO_ASPECT_RATIO}%`;
190220
}
191-
element.style.display = 'none';
221+
break;
222+
case 'Code':
223+
const codeSection = document.querySelector('.code-section') as HTMLElement;
224+
const languageButtons = document.querySelector('.language-buttons-container') as HTMLElement;
225+
if (codeSection) codeSection.style.display = 'block';
226+
if (languageButtons) languageButtons.style.display = 'flex';
227+
break;
228+
case 'Discussion':
229+
// No need to do anything as the discussion is the default content
230+
break;
231+
}
232+
233+
// Update button states
234+
const buttons = document.querySelectorAll('.nav-button');
235+
buttons.forEach(button => {
236+
if (button.textContent === type) {
237+
button.classList.add('active');
238+
} else {
239+
button.classList.remove('active');
192240
}
193241
});
242+
243+
// Show/hide the discussion section
244+
const discussionSection = document.querySelector('.discuss-markdown') as HTMLElement;
245+
if (discussionSection) {
246+
discussionSection.style.display = type === 'Discussion' ? 'block' : 'none';
247+
}
194248
}
195249

196250
function createNavContainer(problem: any) {
@@ -212,24 +266,12 @@ function createNavContainer(problem: any) {
212266
{ text: 'Code', show: problem.languages?.length > 0 }
213267
];
214268

215-
const activeButton = buttons[0];
216-
buttons.forEach(({ text, show }) => {
269+
buttons.forEach(({ text, show }, index) => {
217270
if (!show) return;
218271

219-
const button = createStyledButton(text, text === activeButton.text);
272+
const button = createStyledButton(text, index === 0);
220273
button.addEventListener('click', () => {
221-
hideContent();
222-
if (text === 'Video') {
223-
const videoContainer = document.querySelector('.video-container') as HTMLElement;
224-
if (videoContainer) {
225-
videoContainer.style.display = 'flex';
226-
videoContainer.style.paddingBottom = `${VIDEO_ASPECT_RATIO}%`;
227-
}
228-
} else if (text === 'Code') {
229-
const elements = ['.code-container', '.language-buttons-container']
230-
.map(selector => document.querySelector(selector) as HTMLElement);
231-
elements.forEach(el => el && (el.style.display = 'flex'));
232-
}
274+
showContent(text as 'Discussion' | 'Video' | 'Code');
233275
});
234276
navContainer.append(button);
235277
});
@@ -530,55 +572,53 @@ function updateAllElements(isDark: boolean) {
530572
}
531573

532574
chrome.runtime.onMessage.addListener((request) => {
533-
// get discussion tab so we can insert the content before it
534575
if (request.action === 'updateSolutions') {
535576
chrome.storage.local.get(['leetcodeProblems'], (result) => {
536-
const searchBar = document.querySelectorAll('input.block')[0].parentElement?.parentElement?.parentElement;
577+
const searchBar = document.querySelectorAll('input.block')[0]?.parentElement?.parentElement?.parentElement;
578+
if (!searchBar) return;
579+
537580
const title = request.title.split('-')[0].trim();
538581
const problem = result.leetcodeProblems.questions.find((problem: { title: string }) => problem.title === title);
539582

540-
// If no solution code or videos exist, dont do anything.
583+
// If no solution code or videos exist, don't do anything
541584
if (!problem?.videos && !problem?.languages) return;
542-
if (problem.videos?.length == 0 && problem.languages?.length == 0) {
543-
return;
544-
}
585+
if (problem.videos?.length === 0 && problem.languages?.length === 0) return;
545586

546-
// Always remove existing containers when updating solutions
547-
const existingContainers = [
548-
'.nav-container',
549-
'.video-container',
550-
'.code-container',
551-
'.language-buttons-container'
552-
].forEach(selector => {
553-
const element = document.querySelector(selector);
554-
if (element) element.remove();
555-
});
587+
// Remove any existing containers
588+
const existingWrapper = document.querySelector('.leetcode-explained-wrapper');
589+
if (existingWrapper) existingWrapper.remove();
556590

557-
// Create new nav container
558-
const newNavContainer = createNavContainer(problem);
559-
searchBar?.insertBefore(newNavContainer, searchBar.firstChild);
591+
// Create wrapper for all our custom content
592+
const wrapper = createCustomContentWrapper();
593+
594+
// Create and add nav container
595+
const navContainer = createNavContainer(problem);
596+
wrapper.appendChild(navContainer);
560597

561598
// Add video container if videos exist
562599
if (problem.videos?.length > 0) {
563-
let videoContainer = createVideoContainer(problem);
564-
if (searchBar) searchBar.insertBefore(videoContainer, searchBar.children[1]);
565-
}
566-
567-
// Add code container if languages exist
568-
if (problem.languages?.length > 0) {
569-
let codeContainer = createCodeContainer();
570-
if (searchBar) searchBar.insertBefore(codeContainer, searchBar.children[1]);
600+
const videoContainer = createVideoContainer(problem);
601+
wrapper.appendChild(videoContainer);
571602
}
572603

573-
// Add language buttons container if languages exist
604+
// Add code container and language buttons if languages exist
574605
if (problem.languages?.length > 0) {
575-
let languageButtonsContainer = createLanguageButtons(problem);
606+
const codeContainer = createCodeContainer();
607+
const languageButtonsContainer = createLanguageButtons(problem);
576608
languageButtonsContainer.classList.add('language-buttons-container');
577609
languageButtonsContainer.style.display = 'none';
578-
if (searchBar) searchBar.insertBefore(languageButtonsContainer, searchBar.children[1]);
610+
611+
wrapper.appendChild(languageButtonsContainer);
612+
wrapper.appendChild(codeContainer);
579613
}
580614

581-
// Add theme change listener after creating containers
615+
// Insert the wrapper at the top of the solutions tab
616+
searchBar.insertBefore(wrapper, searchBar.firstChild);
617+
618+
// Show discussion by default
619+
showContent('Discussion');
620+
621+
// Set up theme change listener
582622
setupThemeChangeListener();
583623
});
584624
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /