Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 0 additions & 4 deletions apps/remix-ide-e2e/src/helpers/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,6 @@ function initModules(browser: NightwatchBrowser, callback: VoidFunction) {
.click('*[data-id="github-configSwitch"]')
.setValue('[data-id="settingsTabgist-access-token"]', process.env.gist_token)
.click('[data-id="settingsTabSavegithub-config"]')
.waitForElementVisible('*[data-id="topbar-themeIcon-toggle"]')
.click('*[data-id="topbar-themeIcon-toggle"]')
.waitForElementVisible('*[data-id="topbar-themeIcon-light"]')
.click('*[data-id="topbar-themeIcon-light"]')
// .click('[data-id="settingsTabThemeLabelFlatly"]') // e2e tests were initially developed with Flatly. Some tests are failing with the default one (Dark), because the dark theme put uppercase everywhere.
.perform(() => { callback() })
}
77 changes: 44 additions & 33 deletions apps/remix-ide-e2e/src/tests/generalSettings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,48 +58,59 @@ module.exports = {
.pause(100)
.assert.containsText('[data-id="settingsTabgist-access-token"]', '')
},
// These e2e should be enabled after settings panel refactoring
// 'Should load dark theme ': function (browser: NightwatchBrowser) {
// browser.waitForElementVisible('*[data-id="verticalIconsKindsettings"]', 5000)
// .scrollAndClick('*[data-id="settingsTabThemeLabelDark"]')
// .pause(2000)
// .checkElementStyle(':root', '--primary', remixIdeThemes.dark.primary)
// .checkElementStyle(':root', '--secondary', remixIdeThemes.dark.secondary)
// .checkElementStyle(':root', '--success', remixIdeThemes.dark.success)
// .checkElementStyle(':root', '--info', remixIdeThemes.dark.info)
// .checkElementStyle(':root', '--warning', remixIdeThemes.dark.warning)
// .checkElementStyle(':root', '--danger', remixIdeThemes.dark.danger)
// },

// 'Should load light theme ': function (browser: NightwatchBrowser) {
// browser.waitForElementVisible('*[data-id="verticalIconsKindsettings"]', 5000)
// .scrollAndClick('*[data-id="settingsTabThemeLabelLight"]')
// .pause(2000)
// .checkElementStyle(':root', '--primary', remixIdeThemes.light.primary)
// .checkElementStyle(':root', '--secondary', remixIdeThemes.light.secondary)
// .checkElementStyle(':root', '--success', remixIdeThemes.light.success)
// .checkElementStyle(':root', '--info', remixIdeThemes.light.info)
// .checkElementStyle(':root', '--warning', remixIdeThemes.light.warning)
// .checkElementStyle(':root', '--danger', remixIdeThemes.light.danger)
// },
'Should switch to Dark theme from Appearance section': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="topbar-settingsIcon"]')
.click('*[data-id="topbar-settingsIcon"]')
.waitForElementVisible('*[data-id="settings-sidebar-general"]')
.click('*[data-id="settings-sidebar-general"]')
.waitForElementVisible('*[data-id="settingsTabthemeLabel"]')
.click('*[data-id="settingsTabDropdownToggletheme"]')
.waitForElementVisible('*[data-id="settingsTabDropdownItemDark"]')
.click('*[data-id="settingsTabDropdownItemDark"]')
.pause(2000)
.checkElementStyle(':root', '--bs-primary', remixIdeThemes.dark.primary)
.checkElementStyle(':root', '--bs-secondary', remixIdeThemes.dark.secondary)
.checkElementStyle(':root', '--bs-success', remixIdeThemes.dark.success)
.checkElementStyle(':root', '--bs-info', remixIdeThemes.dark.info)
.checkElementStyle(':root', '--bs-warning', remixIdeThemes.dark.warning)
.checkElementStyle(':root', '--bs-danger', remixIdeThemes.dark.danger)
},

'Should switch to Light theme from Appearance section': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="settingsTabthemeLabel"]')
.click('*[data-id="settingsTabDropdownToggletheme"]')
.waitForElementVisible('*[data-id="settingsTabDropdownItemLight"]')
.click('*[data-id="settingsTabDropdownItemLight"]')
.pause(2000)
.checkElementStyle(':root', '--bs-primary', remixIdeThemes.light.primary)
.checkElementStyle(':root', '--bs-secondary', remixIdeThemes.light.secondary)
.checkElementStyle(':root', '--bs-success', remixIdeThemes.light.success)
.checkElementStyle(':root', '--bs-info', remixIdeThemes.light.info)
.checkElementStyle(':root', '--bs-warning', remixIdeThemes.light.warning)
.checkElementStyle(':root', '--bs-danger', remixIdeThemes.light.danger)
.end()
},

}

const remixIdeThemes = {
dark: {
primary: '#007aa6',
secondary: '#595c76',
success: '#32ba89',
info: '#086CB5',
warning: '#c97539',
danger: '#b84040'
secondary: '#444',
success: '#00bc8c',
info: '#3498db',
warning: '#f39c12',
danger: '#e74c3c'
},
light: {
primary: '#007aa6',
secondary: '#b3bcc483',
success: '#32ba89',
info: '#007aa6',
warning: '#c97539',
danger: '#b84040'
secondary: '#a2a3bd',
success: '#18bc9c',
info: '#3498db',
warning: '#f39c12',
danger: '#e74c3c'
}
}
35 changes: 35 additions & 0 deletions libs/remix-ui/login/src/lib/login-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,27 @@ export const LoginButton: React.FC<LoginButtonProps> = ({
}) => {
const { isAuthenticated, user, credits, logout, login } = useAuth()
const [showModal, setShowModal] = useState(false)
const [themes, setThemes] = useState<Array<{ name: string; quality: string }>>([])
const [currentTheme, setCurrentTheme] = useState<string>('')

useEffect(() => {
if (plugin && typeof plugin.call === 'function') {
(async () => {
try {
const themeModule = await plugin.call('theme', 'getThemes')
if (themeModule) {
setThemes(themeModule)
}
const active = await plugin.call('theme', 'currentTheme')
if (active) {
setCurrentTheme(active.name)
}
} catch (err) {
console.log('[LoginButton] Theme module not available:', err)
}
})()
}
}, [plugin])

const handleLogout = async () => {
await logout()
Expand Down Expand Up @@ -70,6 +91,17 @@ export const LoginButton: React.FC<LoginButtonProps> = ({
return user.sub
}

const handleThemeChange = async (themeName: string) => {
if (plugin && typeof plugin.call === 'function') {
try {
await plugin.call('theme', 'switchTheme', themeName)
setCurrentTheme(themeName)
} catch (err) {
console.error('[LoginButton] Failed to switch theme:', err)
}
}
}

if (!isAuthenticated) {
return (
<>
Expand Down Expand Up @@ -111,6 +143,9 @@ export const LoginButton: React.FC<LoginButtonProps> = ({
onManageAccounts={handleManageAccounts}
getProviderDisplayName={getProviderDisplayName}
getUserDisplayName={getUserDisplayName}
themes={themes}
currentTheme={currentTheme}
onThemeChange={handleThemeChange}
/>
)
}
Expand Down
168 changes: 168 additions & 0 deletions libs/remix-ui/login/src/lib/user-menu-compact.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
.user-menu-compact-button {
gap: 8px;
}

.user-menu-compact-avatar {
width: 25px;
height: 25px;
border-radius: 50%;
object-fit: cover;
flex-shrink: 0;
}

.user-menu-compact-info {
display: flex;
flex-direction: column;
align-items: flex-start;
line-height: 1.2;
}

.user-menu-compact-name {
font-weight: 500;
}

.user-menu-dropdown {
position: absolute;
right: 0;
top: 100%;
min-width: 240px;
z-index: 2000;
background-color: var(--bs-secondary-bg, #333446);
border: 1px solid var(--bs-border-color, #444);
border-radius: 8px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
padding: 0;
}

.user-menu-dropdown-header {
background-color: var(--bs-primary, #007aa6);
color: white;
padding: 12px 16px;
border-radius: 8px 8px 0 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
gap: 12px;
}

.user-menu-dropdown-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
object-fit: cover;
border: 2px solid rgba(255, 255, 255, 0.3);
flex-shrink: 0;
}

.user-menu-dropdown-name {
font-weight: 600;
font-size: 0.95rem;
flex: 1;
}

.user-menu-provider {
padding: 8px 16px;
background-color: var(--bs-body-bg, #222336);
border-bottom: 1px solid var(--bs-border-color, #444);
}

.user-menu-items-container {
padding: 4px 0;
}

.user-menu-item {
padding: 8px 12px;
color: var(--bs-body-color, #a2a3bd);
display: flex;
align-items: center;
border: none;
background-color: transparent;
width: 100%;
text-align: left;
cursor: pointer;
transition: background-color 0.2s;
}

.user-menu-item:hover {
background-color: var(--bs-body-bg, #222336);
}

.user-menu-item-icon {
width: 16px;
text-align: center;
margin-right: 12px;
}

.user-menu-credits-item {
padding: 8px 12px;
color: var(--bs-body-color, #a2a3bd);
display: flex;
align-items: center;
justify-content: space-between;
cursor: default;
background-color: transparent;
transition: background-color 0.2s;
}

.user-menu-credits-item:hover {
background-color: var(--bs-body-bg, #222336);
}

.user-menu-credits-icon {
width: 16px;
text-align: center;
margin-right: 12px;
}

.user-menu-credits-balance {
font-size: 0.95rem;
font-weight: 600;
}

.user-menu-divider {
margin: 8px 0;
border-color: var(--bs-border-color, #444);
}

.user-menu-item-danger {
padding: 8px 12px;
color: var(--bs-danger, #e74c3c);
display: flex;
align-items: center;
border: none;
background-color: transparent;
width: 100%;
text-align: left;
cursor: pointer;
transition: background-color 0.2s;
font-weight: 500;
}

.user-menu-item-danger:hover {
background-color: var(--bs-body-bg, #222336);
}

.user-menu-theme-toggle {
display: flex;
align-items: center;
padding: 8px 12px;
}

.user-menu-theme-toggle .btn {
padding: 0;
border: none;
background: transparent;
}

.user-menu-theme-toggle .btn:hover {
background: transparent;
}

.user-menu-backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1999;
}
Loading