Fonts & theme toggle component
This commit is contained in:
@ -6,7 +6,7 @@
|
||||
# https://redwoodjs.com/docs/app-configuration-redwood-toml
|
||||
|
||||
[web]
|
||||
title = "Redwood App"
|
||||
title = "Ahmed Al-Taiar"
|
||||
port = 8910
|
||||
apiUrl = "/.redwood/functions" # You can customize graphql and dbauth urls individually too: see https://redwoodjs.com/docs/app-configuration-redwood-toml#api-paths
|
||||
includeEnvironmentVariables = [
|
||||
|
@ -1,10 +1,13 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export const content = ['src/**/*.{js,jsx,ts,tsx}']
|
||||
|
||||
export const theme = {
|
||||
extend: {},
|
||||
extend: {
|
||||
fontFamily: {
|
||||
syne: ['Syne', 'sans-serif'],
|
||||
inter: ['Inter', 'sans-serif'],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export const plugins = [require('daisyui')]
|
||||
|
||||
export const daisyui = { themes: ['light', 'dark'] }
|
||||
|
@ -12,6 +12,7 @@ import { Router, Route } from '@redwoodjs/router'
|
||||
const Routes = () => {
|
||||
return (
|
||||
<Router>
|
||||
<Route path="/" page={HomePage} name="home" />
|
||||
<Route notfound page={NotFoundPage} />
|
||||
</Router>
|
||||
)
|
||||
|
26
web/src/components/ThemeToggle/ThemeToggle.stories.tsx
Normal file
26
web/src/components/ThemeToggle/ThemeToggle.stories.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
// Pass props to your component by passing an `args` object to your story
|
||||
//
|
||||
// ```tsx
|
||||
// export const Primary: Story = {
|
||||
// args: {
|
||||
// propName: propValue
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// See https://storybook.js.org/docs/react/writing-stories/args.
|
||||
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import ThemeToggle from './ThemeToggle'
|
||||
|
||||
const meta: Meta<typeof ThemeToggle> = {
|
||||
component: ThemeToggle,
|
||||
tags: ['autodocs'],
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof ThemeToggle>
|
||||
|
||||
export const Primary: Story = {}
|
14
web/src/components/ThemeToggle/ThemeToggle.test.tsx
Normal file
14
web/src/components/ThemeToggle/ThemeToggle.test.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import { render } from '@redwoodjs/testing/web'
|
||||
|
||||
import ThemeToggle from './ThemeToggle'
|
||||
|
||||
// Improve this test with help from the Redwood Testing Doc:
|
||||
// https://redwoodjs.com/docs/testing#testing-components
|
||||
|
||||
describe('ThemeToggle', () => {
|
||||
it('renders successfully', () => {
|
||||
expect(() => {
|
||||
render(<ThemeToggle />)
|
||||
}).not.toThrow()
|
||||
})
|
||||
})
|
47
web/src/components/ThemeToggle/ThemeToggle.tsx
Normal file
47
web/src/components/ThemeToggle/ThemeToggle.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
import { mdiWeatherSunny, mdiWeatherNight } from '@mdi/js'
|
||||
import Icon from '@mdi/react'
|
||||
|
||||
const ThemeToggle = () => {
|
||||
const [theme, setTheme] = useState(
|
||||
localStorage.getItem('theme') ? localStorage.getItem('theme') : 'light'
|
||||
)
|
||||
|
||||
const handleToggle = (e) => {
|
||||
if (e.target.checked) {
|
||||
setTheme('dark')
|
||||
} else {
|
||||
setTheme('light')
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('theme', theme)
|
||||
|
||||
document
|
||||
.querySelector('html')
|
||||
.setAttribute('data-theme', localStorage.getItem('theme'))
|
||||
}, [theme])
|
||||
|
||||
return (
|
||||
// eslint-disable-next-line jsx-a11y/label-has-associated-control
|
||||
<label className="btn btn-ghost swap swap-rotate w-12">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="theme-controller"
|
||||
checked={theme === 'dark'}
|
||||
onChange={handleToggle}
|
||||
/>
|
||||
|
||||
<Icon
|
||||
path={mdiWeatherSunny}
|
||||
className="swap-off h-8 w-8 text-yellow-500"
|
||||
/>
|
||||
|
||||
<Icon path={mdiWeatherNight} className="swap-on h-8 w-8 text-blue-500" />
|
||||
</label>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThemeToggle
|
@ -1,15 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
|
||||
<link
|
||||
href="https://fonts.googleapis.com/css2?family=Inter&family=Syne"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- Please keep this div empty -->
|
||||
<div id="redwood-app"></div>
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
13
web/src/pages/HomePage/HomePage.stories.tsx
Normal file
13
web/src/pages/HomePage/HomePage.stories.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react'
|
||||
|
||||
import HomePage from './HomePage'
|
||||
|
||||
const meta: Meta<typeof HomePage> = {
|
||||
component: HomePage,
|
||||
}
|
||||
|
||||
export default meta
|
||||
|
||||
type Story = StoryObj<typeof HomePage>
|
||||
|
||||
export const Primary: Story = {}
|
14
web/src/pages/HomePage/HomePage.test.tsx
Normal file
14
web/src/pages/HomePage/HomePage.test.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import { render } from '@redwoodjs/testing/web'
|
||||
|
||||
import HomePage from './HomePage'
|
||||
|
||||
// Improve this test with help from the Redwood Testing Doc:
|
||||
// https://redwoodjs.com/docs/testing#testing-pages-layouts
|
||||
|
||||
describe('HomePage', () => {
|
||||
it('renders successfully', () => {
|
||||
expect(() => {
|
||||
render(<HomePage />)
|
||||
}).not.toThrow()
|
||||
})
|
||||
})
|
21
web/src/pages/HomePage/HomePage.tsx
Normal file
21
web/src/pages/HomePage/HomePage.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { Link, routes } from '@redwoodjs/router'
|
||||
import { Metadata } from '@redwoodjs/web'
|
||||
|
||||
const HomePage = () => {
|
||||
return (
|
||||
<>
|
||||
<Metadata title="Home" description="Home page" />
|
||||
|
||||
<h1>HomePage</h1>
|
||||
<p>
|
||||
Find me in <code>./web/src/pages/HomePage/HomePage.tsx</code>
|
||||
</p>
|
||||
<p>
|
||||
My default route is named <code>home</code>, link to me with `
|
||||
<Link to={routes.home()}>Home</Link>`
|
||||
</p>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default HomePage
|
Reference in New Issue
Block a user