support toggling dark mode
This commit is contained in:
parent
9c54427b08
commit
073da66623
|
|
@ -347,4 +347,14 @@ class UserController extends Controller
|
|||
return json(trans('skinlib.non-existent'), 1);
|
||||
}
|
||||
}
|
||||
|
||||
public function toggleDarkMode()
|
||||
{
|
||||
/** @var User */
|
||||
$user = auth()->user();
|
||||
$user->is_dark_mode = !$user->is_dark_mode;
|
||||
$user->save();
|
||||
|
||||
return response()->noContent();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,6 +69,12 @@ class ViewServiceProvider extends ServiceProvider
|
|||
|
||||
View::composer('shared.foot', Composers\FootComposer::class);
|
||||
|
||||
View::composer('shared.dark-mode', function ($view) {
|
||||
$view->with([
|
||||
'dark_mode' => (bool) optional(auth()->user())->is_dark_mode,
|
||||
]);
|
||||
});
|
||||
|
||||
View::composer('assets.*', function ($view) {
|
||||
$view->with('cdn_base', option('cdn_address', ''));
|
||||
});
|
||||
|
|
|
|||
27
resources/assets/src/components/DarkModeButton.tsx
Normal file
27
resources/assets/src/components/DarkModeButton.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import React, { useState } from 'react'
|
||||
import * as fetch from '@/scripts/net'
|
||||
|
||||
interface Props {
|
||||
initMode: boolean
|
||||
}
|
||||
|
||||
const DarkModeButton: React.FC<Props> = ({ initMode }) => {
|
||||
const [darkMode, setDarkMode] = useState(initMode)
|
||||
|
||||
const icon = darkMode ? 'moon' : 'sun'
|
||||
|
||||
const handleClick = async () => {
|
||||
setDarkMode((value) => !value)
|
||||
|
||||
await fetch.put('/user/dark-mode')
|
||||
document.body.classList.toggle('dark-mode')
|
||||
}
|
||||
|
||||
return (
|
||||
<a className="nav-link" href="#" role="button" onClick={handleClick}>
|
||||
<i className={`fas fa-${icon}`}></i>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
export default DarkModeButton
|
||||
|
|
@ -6,6 +6,7 @@ import './event'
|
|||
import './notification'
|
||||
import './emailVerification'
|
||||
import './logout'
|
||||
import './darkMode'
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
|
|
|
|||
9
resources/assets/src/scripts/darkMode.tsx
Normal file
9
resources/assets/src/scripts/darkMode.tsx
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import * as React from 'react'
|
||||
import * as ReactDOM from 'react-dom'
|
||||
import DarkModeButton from '@/components/DarkModeButton'
|
||||
|
||||
const el = document.querySelector('#toggle-dark-mode')
|
||||
if (el) {
|
||||
const initMode = document.body.classList.contains('dark-mode')
|
||||
ReactDOM.render(<DarkModeButton initMode={initMode} />, el)
|
||||
}
|
||||
22
resources/assets/tests/components/DarkModeButton.test.tsx
Normal file
22
resources/assets/tests/components/DarkModeButton.test.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react'
|
||||
import { render, fireEvent, waitFor } from '@testing-library/react'
|
||||
import * as fetch from '@/scripts/net'
|
||||
import DarkModeButton from '@/components/DarkModeButton'
|
||||
|
||||
jest.mock('@/scripts/net')
|
||||
|
||||
test('click to toggle', async () => {
|
||||
const { getByRole } = render(<DarkModeButton initMode={false} />)
|
||||
const button = getByRole('button')
|
||||
|
||||
fireEvent.click(button)
|
||||
await waitFor(() => expect(fetch.put).toBeCalledWith('/user/dark-mode'))
|
||||
})
|
||||
|
||||
test('default is dark', async () => {
|
||||
const { getByRole } = render(<DarkModeButton initMode={true} />)
|
||||
const button = getByRole('button')
|
||||
|
||||
fireEvent.click(button)
|
||||
await waitFor(() => expect(fetch.put).toBeCalledWith('/user/dark-mode'))
|
||||
})
|
||||
7
resources/views/shared/dark-mode.twig
Normal file
7
resources/views/shared/dark-mode.twig
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{% if auth_check() %}
|
||||
<li class="nav-item" id="toggle-dark-mode">
|
||||
<a class="nav-link" href="#" role="button">
|
||||
<i class="fas fa-{{ dark_mode ? 'moon' : 'sun' }}"></i>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
</ul>
|
||||
|
||||
<ul class="navbar-nav ml-auto">
|
||||
{{ include('shared.dark-mode') }}
|
||||
{{ include('shared.notifications') }}
|
||||
{{ include('shared.languages') }}
|
||||
{{ include('shared.user-menu') }}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ Route::prefix('user')
|
|||
|
||||
Route::post('email-verification', 'UserController@sendVerificationEmail');
|
||||
|
||||
Route::put('dark-mode', 'UserController@toggleDarkMode');
|
||||
|
||||
Route::prefix('player')
|
||||
->name('player.')
|
||||
->middleware('verified')
|
||||
|
|
|
|||
|
|
@ -597,4 +597,14 @@ class UserControllerTest extends TestCase
|
|||
->postJson('/user/profile/avatar', ['tid' => $steve->tid])
|
||||
->assertJson(['code' => 1, 'message' => 'rejected']);
|
||||
}
|
||||
|
||||
public function testToggleDarkMode()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$this->actingAs($user)->putJson('/user/dark-mode')->assertNoContent();
|
||||
$this->assertTrue($user->fresh()->is_dark_mode);
|
||||
|
||||
$this->putJson('/user/dark-mode')->assertNoContent();
|
||||
$this->assertFalse($user->fresh()->is_dark_mode);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user