Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
yuriha-chan committed Aug 28, 2023
0 parents commit 9cb5dba
Show file tree
Hide file tree
Showing 29 changed files with 704 additions and 0 deletions.
46 changes: 46 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"private": true,
"name": "timer-app",
"version": "0.0.0",
"license": "MIT",
"scripts": {
"build": "cross-env NODE_OPTIONS=--openssl-legacy-provider preact build",
"serve": "sirv build --port 8080 --cors --single",
"dev": "cross-env NODE_OPTIONS=--openssl-legacy-provider preact watch",
"lint": "eslint src",
"test": "jest"
},
"eslintConfig": {
"extends": "preact",
"ignorePatterns": [
"build/"
]
},
"devDependencies": {
"cross-env": "^7.0.3",
"enzyme": "^3.11.0",
"enzyme-adapter-preact-pure": "^4.0.0",
"eslint": "^8.30.0",
"eslint-config-preact": "^1.3.0",
"jest": "^27.0.0",
"jest-preset-preact": "^4.0.5",
"preact-cli": "^3.4.2",
"sirv-cli": "^2.0.2"
},
"dependencies": {
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.6",
"@mui/material": "^5.14.6",
"preact": "^10.11.3",
"preact-render-to-string": "^5.2.6",
"preact-router": "^3.2.1"
},
"jest": {
"preset": "jest-preset-preact",
"setupFiles": [
"<rootDir>/tests/__mocks__/browserMocks.js",
"<rootDir>/tests/__mocks__/setupTests.js"
]
}
}
Binary file added src/assets/favicon.ico
Binary file not shown.
Binary file added src/assets/icons/android-chrome-192x192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/android-chrome-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/assets/icons/mstile-150x150.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/assets/preact-logo-inverse.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/assets/preact-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions src/components/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { h } from 'preact';
import { Router } from 'preact-router';

import Header from './header';

// Code-splitting is automated for `routes` directory
import Home from '../routes/home';
import Profile from '../routes/profile';

const App = () => (
<div id="app">
<Header />
<main>
<Router>
<Home path="/" />
<Profile path="/profile/" user="me" />
<Profile path="/profile/:user" />
</Router>
</main>
</div>
);

export default App;
104 changes: 104 additions & 0 deletions src/components/dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { h, Component } from 'preact';
import Dialog from '@mui/material/Dialog';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import DialogActions from '@mui/material/DialogActions';
import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField';
import Slider from '@mui/material/Slider';
import FormGroup from '@mui/material/FormGroup';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import ScheduleIcon from '@mui/icons-material/Schedule';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select, { SelectChangeEvent } from '@mui/material/Select';

import formatTime from './time-format'

const timeMarks = [
1,2,3,4,5,6,7,8,9,10,
15,20,25,30,35,40,45,50,55,60,
75,90,105,120,135,150,165, 180,
210,240,270,300,360,
420,480,540,600,
900,1200,1500,1800,2100,2400,2700,3000,3300,3600,
4500, 5400, 6300, 7200, 8100, 9000, 9900, 10800, 12600, 14400, 16200, 18000, 19800, 21600, 25200, 28800, 32400, 36000, 39600, 43200];

function mapSliderValue(x) {
return 1000 * (Math.round(Math.exp(x)) - 10);
}

class SettingsDialog extends Component {
constructor(props) {
super(props);
this.state = { title: this.props.title, maxTime: this.props.maxTime, countDown: this.props.countDown, sound: this.props.sound};
}

save = () => {
const { title, maxTime, countDown, sound } = this.state;
this.props.onSave({title, maxTime, countDown, sound});
this.props.onClose();
};
changeSound = (ev) => {
this.setState({sound: '' + ev.target.value});
};
changeCountDown = (ev) => {
this.setState({countDown: !this.state.countDown });
}
changeMaxTime = (ev) => {
this.setState({maxTime: mapSliderValue(ev.target.value)});
}

render() {
const { title, maxTime } = this.state;
return (
<Dialog open={this.props.open} onClose={this.close} maxWidth='sm' fullWidth>
<DialogTitle ><ScheduleIcon /> タイマーの設定</DialogTitle>
<DialogContent style={{overflow: 'hidden'}}>
<div class="settings-entry">
<TextField
label="Title"
value={title}
onChange={event => this.setState({ title: event.target.value })}
fullWidth
margin="normal"
/>
</div>
<div class="settings-entry">
タイマーの長さ
<Slider
color={this.props.color}
value={Math.log(10 + this.state.maxTime / 1000)}
onChange={this.changeMaxTime}
step={null}
valueLabelDisplay="auto"
marks={timeMarks.map(x=>({value: Math.log(10 + x), label: ''}))}
max={Math.log(10 + 43200)} min={Math.log(10)} scale={(x) => 1000 * (Math.round(Math.exp(x)) - 10)}
getAriaValueText={formatTime} valueLabelFormat={formatTime} />
</div>
<div class="settings-entry">
<FormGroup>
<FormControlLabel control={<Checkbox onChange={this.changeCountDown} checked={this.state.countDown} />} label="カウントダウン" />
</FormGroup>
</div>
<div class="settings-entry">
<FormControl fullWidth>
<InputLabel id="select-label-sound"></InputLabel>
<Select labelId="select-label-sound" id="select-sound" value={this.state.sound} label="Sound" onChange={this.changeSound} >
<MenuItem value={'none'}>なし</MenuItem>
</Select>
</FormControl>
</div>
</DialogContent>
<DialogActions>
<Button onClick={this.props.onClose}>キャンセル</Button>
<Button onClick={this.save}>保存</Button>
</DialogActions>
</Dialog>
);
}
}

export default SettingsDialog;
25 changes: 25 additions & 0 deletions src/components/header/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { h } from 'preact';
import { Link } from 'preact-router/match';
import style from './style.css';

const Header = () => (
<header class={style.header}>
<a href="/" class={style.logo}>
<img src="../../assets/preact-logo-inverse.svg" alt="Preact Logo" height="32" width="32" />
<h1>Preact CLI</h1>
</a>
<nav>
<Link activeClassName={style.active} href="/">
Home
</Link>
<Link activeClassName={style.active} href="/profile">
Me
</Link>
<Link activeClassName={style.active} href="/profile/john">
John
</Link>
</nav>
</header>
);

export default Header;
51 changes: 51 additions & 0 deletions src/components/header/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.header {
position: fixed;
left: 0;
top: 0;

display: flex;
justify-content: space-between;

width: 100%;
height: 3.5rem;

background: #673ab8;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
z-index: 50;
}

.header a {
display: inline-block;
padding: 0 1rem;
color: #fff;
text-decoration: none;
line-height: 3.5rem;
}

.header a:hover,
.header a:active {
background: rgba(0, 0, 0, 0.2);
}

.header a.logo {
display: flex;
align-items: center;
padding: 0.5rem 1rem;
}

.logo h1 {
padding: 0 0.5rem;
font-size: 1.5rem;
line-height: 2rem;
font-weight: 400;
}

@media (max-width: 639px) {
.logo h1 {
display: none;
}
}

.header nav a.active {
background: rgba(0, 0, 0, 0.4);
}
8 changes: 8 additions & 0 deletions src/components/time-format.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function formatTime(ms) {
const h = Math.floor(ms/3600/1000);
const mmss = new Date(ms).toISOString().slice(14, 19);
return (h == 0) ? mmss : h + ":" + mmss;
}

export default formatTime;

23 changes: 23 additions & 0 deletions src/components/timer-app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { h, Component } from 'preact';
import Timer from './timer';

class App extends Component {
constructor(props) {
super(props);
}


render() {
return (
<div style={{ textAlign: 'center' }}>
<p><strong>Tap to start/stop, Double-tap to reset</strong></p>
<Timer name="#1" color="teal"/>
<Timer name="#2" color="red"/>
<Timer name="#3" color="yellow"/>
</div>
);
}
}

export default App;

Loading

0 comments on commit 9cb5dba

Please sign in to comment.