Skip to content

Fix Dynamic Routing & Visual Update for Leetcode tabs #66

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Apr 11, 2025
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9b4aa7d
css update: use simple animation, colors, etc
zubyj Apr 7, 2025
a66d66f
fix company tags and video/code containers not updating theme until p…
zubyj Apr 7, 2025
c8f3eaf
fix company tags not adding sometimes
zubyj Apr 7, 2025
827ddef
add hover effect to code language selector
zubyj Apr 7, 2025
a2ee98e
fix company tags getting added multiple times
zubyj Apr 7, 2025
1086f58
fix: when switching yt video, nav buttons readded into page
zubyj Apr 7, 2025
e4cc30f
fix: dynamically opening problem not updatint company tags, video, co…
zubyj Apr 7, 2025
4957083
fix company tags getting added multiple times
zubyj Apr 7, 2025
3f47d90
fix company tags not opening top problems page
zubyj Apr 7, 2025
c3800a6
rm moving popup buttons on hover
zubyj Apr 8, 2025
a85d4eb
on popup nav btn hover, slightly change bg color
zubyj Apr 8, 2025
21bd1b2
fix dynamic routing, but refreshing removes solution tab update
zubyj Apr 9, 2025
b5dc3d3
fix refreshing not updating solutions tab
zubyj Apr 9, 2025
a4c9d0c
fix page update spamming
zubyj Apr 9, 2025
e5c7dd8
fix switching videos causing container to reset
zubyj Apr 10, 2025
cfb77ae
fix prev/next triggering page refresh
zubyj Apr 10, 2025
b7c3f27
cleaner navbar implementation
zubyj Apr 11, 2025
edbaff2
omg i mighta fixed the stupid bugs on this tab
zubyj Apr 11, 2025
af563b2
fix solutions tab elements getting readded when switching tabs
zubyj Apr 11, 2025
60a9a01
fix dynamic routing not resetting solutions tab elements
zubyj Apr 11, 2025
bd02e02
fix solution to description tab not showing company tags
zubyj Apr 11, 2025
a19b620
fix video controls not changing color automatically when theme change…
zubyj Apr 11, 2025
3e8c970
preserve state when swtiching tabs on same page
zubyj Apr 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
cleaner navbar implementation
  • Loading branch information
zubyj committed Apr 11, 2025
commit b7c3f278b8610929caa998f5d598d954d87d8d44
174 changes: 107 additions & 67 deletions src/content-script/update-solutions-tab.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
const VIDEO_ASPECT_RATIO = 56.25; // 16:9 aspect ratio

// Create a wrapper for all our custom content
function createCustomContentWrapper() {
const wrapper = createStyledElement('div', {
width: '100%',
maxWidth: '800px',
margin: '0 auto 32px auto',
position: 'relative',
zIndex: '1'
});
wrapper.classList.add('leetcode-explained-wrapper');
return wrapper;
}

// Utility function to create a styled button
function createStyledButton(text: string, isActive: boolean = false): HTMLButtonElement {
const button = document.createElement('button');
button.textContent = text;
button.classList.add('nav-button');
if (isActive) button.classList.add('active');

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


// on hover just make the background a few shades darker or lighter
button.addEventListener('mouseenter', () => {
button.style.backgroundColor = isDark ? '#424242' : '#e6e6e6';
if (!button.classList.contains('active')) {
button.style.backgroundColor = isDark ? '#424242' : '#e6e6e6';
}
});
button.addEventListener('mouseleave', () => {
button.style.backgroundColor = isDark ? '#373737' : '#f3f4f5';
if (!button.classList.contains('active')) {
button.style.backgroundColor = isDark ? '#373737' : '#f3f4f5';
}
});
});

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

return button;
}
Expand All @@ -47,7 +65,7 @@ function createVideoContainer(problem: any) {
maxWidth: '800px',
margin: '0 auto',
});
container.classList.add('video-container');
container.classList.add('video-container', 'content-section');

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

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

Expand Down Expand Up @@ -153,17 +170,26 @@ function updateVideo(iframe: HTMLIFrameElement, videoUrl: string) {
}

function createCodeContainer() {
const container = createStyledElement('div', {
display: 'none',
width: '100%',
maxWidth: '800px',
margin: '0 auto',
position: 'relative'
});
container.classList.add('code-section', 'content-section');

const codeElement = document.createElement('pre');
codeElement.classList.add('code-container');
codeElement.style.display = 'none';
codeElement.style.display = 'block';
codeElement.style.borderRadius = '8px';
codeElement.style.padding = '16px';
codeElement.style.marginTop = '24px';
codeElement.style.width = '95%';
codeElement.style.width = '100%';
codeElement.style.fontSize = '14px';
codeElement.style.marginLeft = '2.5%';
codeElement.style.maxHeight = '500px';
codeElement.style.overflowY = 'auto';
codeElement.style.boxSizing = 'border-box';
codeElement.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';

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

return codeElement;
container.appendChild(codeElement);
return container;
}

function hideContent() {
const elements = [
'.code-container',
'.language-buttons-container',
'.video-container'
].map(selector => document.querySelector(selector) as HTMLElement);
function showContent(type: 'Discussion' | 'Video' | 'Code') {
// Hide all content sections first
const contentSections = document.querySelectorAll('.content-section');
contentSections.forEach(section => {
(section as HTMLElement).style.display = 'none';
});

elements.forEach(element => {
if (element) {
if (element.classList.contains('video-container')) {
element.style.paddingBottom = '0';
// Show the selected content
switch (type) {
case 'Video':
const videoContainer = document.querySelector('.video-container') as HTMLElement;
if (videoContainer) {
videoContainer.style.display = 'flex';
videoContainer.style.paddingBottom = `${VIDEO_ASPECT_RATIO}%`;
}
element.style.display = 'none';
break;
case 'Code':
const codeSection = document.querySelector('.code-section') as HTMLElement;
const languageButtons = document.querySelector('.language-buttons-container') as HTMLElement;
if (codeSection) codeSection.style.display = 'block';
if (languageButtons) languageButtons.style.display = 'flex';
break;
case 'Discussion':
// No need to do anything as the discussion is the default content
break;
}

// Update button states
const buttons = document.querySelectorAll('.nav-button');
buttons.forEach(button => {
if (button.textContent === type) {
button.classList.add('active');
} else {
button.classList.remove('active');
}
});

// Show/hide the discussion section
const discussionSection = document.querySelector('.discuss-markdown') as HTMLElement;
if (discussionSection) {
discussionSection.style.display = type === 'Discussion' ? 'block' : 'none';
}
}

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

const activeButton = buttons[0];
buttons.forEach(({ text, show }) => {
buttons.forEach(({ text, show }, index) => {
if (!show) return;

const button = createStyledButton(text, text === activeButton.text);
const button = createStyledButton(text, index === 0);
button.addEventListener('click', () => {
hideContent();
if (text === 'Video') {
const videoContainer = document.querySelector('.video-container') as HTMLElement;
if (videoContainer) {
videoContainer.style.display = 'flex';
videoContainer.style.paddingBottom = `${VIDEO_ASPECT_RATIO}%`;
}
} else if (text === 'Code') {
const elements = ['.code-container', '.language-buttons-container']
.map(selector => document.querySelector(selector) as HTMLElement);
elements.forEach(el => el && (el.style.display = 'flex'));
}
showContent(text as 'Discussion' | 'Video' | 'Code');
});
navContainer.append(button);
});
Expand Down Expand Up @@ -530,55 +572,53 @@ function updateAllElements(isDark: boolean) {
}

chrome.runtime.onMessage.addListener((request) => {
// get discussion tab so we can insert the content before it
if (request.action === 'updateSolutions') {
chrome.storage.local.get(['leetcodeProblems'], (result) => {
const searchBar = document.querySelectorAll('input.block')[0].parentElement?.parentElement?.parentElement;
const searchBar = document.querySelectorAll('input.block')[0]?.parentElement?.parentElement?.parentElement;
if (!searchBar) return;

const title = request.title.split('-')[0].trim();
const problem = result.leetcodeProblems.questions.find((problem: { title: string }) => problem.title === title);

// If no solution code or videos exist, dont do anything.
// If no solution code or videos exist, don't do anything
if (!problem?.videos && !problem?.languages) return;
if (problem.videos?.length == 0 && problem.languages?.length == 0) {
return;
}
if (problem.videos?.length === 0 && problem.languages?.length === 0) return;

// Always remove existing containers when updating solutions
const existingContainers = [
'.nav-container',
'.video-container',
'.code-container',
'.language-buttons-container'
].forEach(selector => {
const element = document.querySelector(selector);
if (element) element.remove();
});
// Remove any existing containers
const existingWrapper = document.querySelector('.leetcode-explained-wrapper');
if (existingWrapper) existingWrapper.remove();

// Create new nav container
const newNavContainer = createNavContainer(problem);
searchBar?.insertBefore(newNavContainer, searchBar.firstChild);
// Create wrapper for all our custom content
const wrapper = createCustomContentWrapper();

// Create and add nav container
const navContainer = createNavContainer(problem);
wrapper.appendChild(navContainer);

// Add video container if videos exist
if (problem.videos?.length > 0) {
let videoContainer = createVideoContainer(problem);
if (searchBar) searchBar.insertBefore(videoContainer, searchBar.children[1]);
}

// Add code container if languages exist
if (problem.languages?.length > 0) {
let codeContainer = createCodeContainer();
if (searchBar) searchBar.insertBefore(codeContainer, searchBar.children[1]);
const videoContainer = createVideoContainer(problem);
wrapper.appendChild(videoContainer);
}

// Add language buttons container if languages exist
// Add code container and language buttons if languages exist
if (problem.languages?.length > 0) {
let languageButtonsContainer = createLanguageButtons(problem);
const codeContainer = createCodeContainer();
const languageButtonsContainer = createLanguageButtons(problem);
languageButtonsContainer.classList.add('language-buttons-container');
languageButtonsContainer.style.display = 'none';
if (searchBar) searchBar.insertBefore(languageButtonsContainer, searchBar.children[1]);

wrapper.appendChild(languageButtonsContainer);
wrapper.appendChild(codeContainer);
}

// Add theme change listener after creating containers
// Insert the wrapper at the top of the solutions tab
searchBar.insertBefore(wrapper, searchBar.firstChild);

// Show discussion by default
showContent('Discussion');

// Set up theme change listener
setupThemeChangeListener();
});
}
Expand Down