Skip to content
Open
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
116 changes: 116 additions & 0 deletions src/assets/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -635,3 +635,119 @@ th {
.member-table tr:hover {
font-weight: bold;
}

/* Dark Theme Styles */
[data-theme='dark'] {
color-scheme: dark;
}

[data-theme='dark'] body {
background-color: #1a1a1a;
color: #e0e0e0;
}

[data-theme='dark'] .bg-gray-faint,
[data-theme='dark'] .bg-gray--faint {
background-color: #2a2a2a !important;
}

[data-theme='dark'] .bg-gray-dark {
background-color: #1f1f1f !important;
}

[data-theme='dark'] .bg-darken5,
[data-theme='dark'] .bg-darken10 {
background-color: #2a2a2a !important;
}

[data-theme='dark'] .color-gray {
color: #e0e0e0 !important;
}

[data-theme='dark'] .color-darken25 {
color: #b0b0b0 !important;
}

[data-theme='dark'] .color-darken50 {
color: #808080 !important;
}

[data-theme='dark'] .border--gray-light {
border-color: #404040 !important;
}

[data-theme='dark'] .border-b--1 {
border-bottom-color: #404040 !important;
}

[data-theme='dark'] .border-r {
border-right-color: #404040 !important;
}

[data-theme='dark'] .light-blue,
[data-theme='dark'] .light-blue-on-hover:hover {
background-color: #1e3a4a !important;
}

[data-theme='dark'] .dropdown-content {
background-color: #2a2a2a !important;
border-color: #404040 !important;
}

[data-theme='dark'] .dropdown-content-item {
color: #e0e0e0 !important;
}

[data-theme='dark'] .dropdown-content-item:hover {
background-color: #3a3a3a !important;
}

[data-theme='dark'] .tippy-tooltip.osmcha-theme {
background-color: #2a2a2a !important;
border-color: #404040 !important;
color: #e0e0e0 !important;
}

[data-theme='dark'] .element-info hr {
border-bottom-color: #404040 !important;
}

[data-theme='dark'] .element-info tr.create {
background-color: #0d3d2e !important;
}

[data-theme='dark'] .element-info tr.modify {
background-color: #3d2e0d !important;
}

[data-theme='dark'] .element-info tr.delete {
background-color: #3d0d15 !important;
}

[data-theme='dark'] input,
[data-theme='dark'] textarea,
[data-theme='dark'] select {
background-color: #2a2a2a !important;
color: #e0e0e0 !important;
border-color: #404040 !important;
}

[data-theme='dark'] ::-webkit-input-placeholder {
color: #808080 !important;
}

[data-theme='dark'] ::-moz-placeholder {
color: #808080 !important;
}

[data-theme='dark'] .scroll-styled::-webkit-scrollbar {
background-color: #2a2a2a;
}

[data-theme='dark'] .scroll-styled::-webkit-scrollbar-thumb {
background-color: #404040;
}

[data-theme='dark'] .scroll-styled::-webkit-scrollbar-thumb:hover {
background-color: #505050;
}
31 changes: 30 additions & 1 deletion src/components/changeset/discussions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import TranslateButton from './translate_button';
import { RelativeTime } from '../relative_time';
import { SignInButton } from './sign_in_button';
import { UserOSMLink } from './user_osm_link';
import { Button } from '../button';

class Discussions extends React.PureComponent {
props: {
Expand All @@ -19,8 +20,26 @@ class Discussions extends React.PureComponent {
changesetIsHarmful: boolean
};

state = {
displayCount: 10 // Start by showing 10 discussions
};

componentDidUpdate(prevProps) {
// Reset display count when discussions change
if (prevProps.discussions !== this.props.discussions) {
this.setState({ displayCount: 10 });
}
}

handleLoadMore = () => {
this.setState(prevState => ({
displayCount: prevState.displayCount + 10
}));
};

renderComments() {
const { discussions, changesetAuthor } = this.props;
const { displayCount } = this.state;

if (discussions.size === 0) {
return (
Expand All @@ -32,9 +51,12 @@ class Discussions extends React.PureComponent {
</div>
);
} else {
const displayedDiscussions = discussions.slice(0, displayCount);
const hasMore = displayCount < discussions.size;

return (
<div className="">
{discussions.map((comment, i) => (
{displayedDiscussions.map((comment, i) => (
<div
key={i}
className="flex-parent flex-parent--column justify--space-between border border--gray-light round p6 my6 mt12"
Expand Down Expand Up @@ -79,6 +101,13 @@ class Discussions extends React.PureComponent {
</div>
</div>
))}
{hasMore && (
<div className="flex-parent flex-parent--center-main mt12 mb6">
<Button onClick={this.handleLoadMore} className="wmin180">
Load More ({displayCount} of {discussions.size})
</Button>
</div>
)}
</div>
);
}
Expand Down
20 changes: 20 additions & 0 deletions src/components/theme_toggle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @flow
import React, { useContext } from 'react';
import { ThemeContext } from '../contexts/ThemeContext';
import { Button } from './button';

export function ThemeToggle() {
const { theme, toggleTheme } = useContext(ThemeContext);

return (
<Button
onClick={toggleTheme}
className="ml3"
title={
theme === 'dark' ? 'Switch to light theme' : 'Switch to dark theme'
}
>
{theme === 'dark' ? '☀️ Light' : '🌙 Dark'}
</Button>
);
}
38 changes: 38 additions & 0 deletions src/contexts/ThemeContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// @flow
import React, { createContext, useState, useEffect } from 'react';
import * as safeStorage from '../utils/safe_storage';

type ThemeContextType = {
theme: 'light' | 'dark',
toggleTheme: () => void
};

export const ThemeContext = createContext<ThemeContextType>({
theme: 'light',
toggleTheme: () => {}
});

export function ThemeProvider({ children }: { children: React.Node }) {
const [theme, setTheme] = useState<'light' | 'dark'>(() => {
const savedTheme = safeStorage.getItem('theme');
return savedTheme === 'dark' || savedTheme === 'light'
? savedTheme
: 'light';
});

useEffect(() => {
// Apply theme to document on mount and when theme changes
document.documentElement.setAttribute('data-theme', theme);
safeStorage.setItem('theme', theme);
}, [theme]);

const toggleTheme = () => {
setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light'));
};

return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
9 changes: 6 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Raven from 'raven-js';
import { history } from './store/history';
import { store } from './store';
import { isDev, appVersion } from './config';
import { ThemeProvider } from './contexts/ThemeContext';

import './assets/index.css';
import 'animate.css/animate.css';
Expand All @@ -26,9 +27,11 @@ if (process.env.NODE_ENV === 'production') {
// }
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
<ThemeProvider>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</ThemeProvider>
</Provider>,
document.getElementById('root')
);
26 changes: 16 additions & 10 deletions src/views/navbar_sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { push } from 'react-router-redux';
import { Button } from '../components/button';
import { Navbar } from '../components/navbar';
import { Dropdown } from '../components/dropdown';
import { ThemeToggle } from '../components/theme_toggle';

import { isMobile } from '../utils';
import { getAuthUrl } from '../network/auth';
Expand Down Expand Up @@ -133,9 +134,10 @@ class NavbarSidebar extends React.PureComponent {
</Link>
}
buttons={
<div className="flex-parent flex-parent--row">
<div className="flex-parent flex-parent--row align-items--center">
<ThemeToggle />
<Link
className="pr3 pointer"
className="pr3 pointer ml3"
to={{
search: window.location.search,
pathname: '/about'
Expand All @@ -146,15 +148,19 @@ class NavbarSidebar extends React.PureComponent {
</svg>
</Link>
{this.props.token ? (
<div className="pointer">{this.renderUserMenuOptions()}</div>
<div className="pointer ml3">
{this.renderUserMenuOptions()}
</div>
) : (
<Button
onClick={this.handleLoginClick}
disable={!this.props.oAuthToken}
iconName="osm"
>
Sign in
</Button>
<div className="ml3">
<Button
onClick={this.handleLoginClick}
disable={!this.props.oAuthToken}
iconName="osm"
>
Sign in
</Button>
</div>
)}
</div>
}
Expand Down