-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2a9b797
commit 51bafb6
Showing
14 changed files
with
617 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"extends": ["../.eslintrc.json"], | ||
"ignorePatterns": ["!**/*"], | ||
"overrides": [ | ||
{ | ||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.ts", "*.tsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.js", "*.jsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.json"], | ||
"parser": "jsonc-eslint-parser", | ||
"rules": { | ||
"@nx/dependency-checks": "error" | ||
} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
UI reducers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/* eslint-disable */ | ||
export default { | ||
displayName: 'ui', | ||
preset: '../jest.preset.js', | ||
testEnvironment: 'node', | ||
transform: { | ||
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }], | ||
}, | ||
moduleFileExtensions: ['ts', 'js', 'html'], | ||
coverageDirectory: '../coverage/ui', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"name": "@jikan0/ui", | ||
"version": "0.0.1", | ||
"dependencies": { | ||
"tslib": "^2.3.0" | ||
}, | ||
"type": "commonjs", | ||
"main": "./src/index.js", | ||
"typings": "./src/index.d.ts" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "ui", | ||
"$schema": "../node_modules/nx/schemas/project-schema.json", | ||
"sourceRoot": "ui/src", | ||
"projectType": "library", | ||
"targets": { | ||
"build": { | ||
"executor": "@nx/js:tsc", | ||
"outputs": ["{options.outputPath}"], | ||
"options": { | ||
"outputPath": "dist/ui", | ||
"main": "ui/src/index.ts", | ||
"tsConfig": "ui/tsconfig.lib.json", | ||
"assets": ["ui/*.md"] | ||
} | ||
}, | ||
"lint": { | ||
"executor": "@nx/eslint:lint", | ||
"outputs": ["{options.outputFile}"] | ||
}, | ||
"test": { | ||
"executor": "@nx/jest:jest", | ||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"], | ||
"options": { | ||
"jestConfig": "ui/jest.config.ts" | ||
} | ||
} | ||
}, | ||
"tags": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './lib/ui'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
describe('ui', () => { | ||
it('should work', () => { | ||
// TODO | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
import { Program, State as FsmState, reset, push } from '@jikan0/fsm'; | ||
import { pipe } from '@jikan0/utils'; | ||
|
||
// TODO program library | ||
// TODO program settings | ||
// TODO fp eslint | ||
|
||
export type StartClickedEvent = { | ||
_tag: 'StartClicked'; | ||
} | ||
|
||
export type StopClickedEvent = { | ||
_tag: 'StopClicked'; | ||
} | ||
|
||
export type PauseClickedEvent = { | ||
_tag: 'PauseClicked'; | ||
} | ||
|
||
export type ContinueClickedEvent = { | ||
_tag: 'ContinueClicked'; | ||
} | ||
|
||
export type TimePassedEvent = { | ||
_tag: 'TimePassed'; | ||
timeMs: BigInt; | ||
} | ||
|
||
export const DEFAULT_MODE = 'simple' as const satisfies Mode; | ||
export const DEFAULT_EXERCISE_TIME_MS = BigInt(30000); | ||
export const DEFAULT_REST_TIME_MS = BigInt(10000); | ||
export const DEFAULT_ROUNDS = BigInt(10); | ||
|
||
export type ModeSelected = { | ||
_tag: 'ModeSelected'; | ||
} | ||
|
||
export type Event = StartClickedEvent | StopClickedEvent | PauseClickedEvent | ContinueClickedEvent; | ||
|
||
export type Action = Event; | ||
|
||
type RunningState = 'running' | 'paused' | 'stopped'; | ||
type Button<E> = { | ||
active: true, | ||
onClick: E, | ||
} | { | ||
active: false, | ||
} | ||
type ActiveButton<E> = Button<E> & { | ||
active: true, | ||
} | ||
type InactiveButton<E = never> = Button<E> & { | ||
active: false, | ||
} | ||
|
||
|
||
type ViewActiveValue = { | ||
startButton: Button<StartClickedEvent>, | ||
stopButton: Button<StopClickedEvent>, | ||
pauseButton: Button<PauseClickedEvent>, | ||
continueButton: Button<ContinueClickedEvent>, | ||
} | ||
|
||
type ViewQueryValue = { | ||
running: RunningState, | ||
program: Program, // can be empty | ||
fsmState: FsmState, // can be empty | ||
} | ||
|
||
type State = ViewQueryValue & { | ||
mode: ModeSelectorState | ||
}; | ||
|
||
const SIMPLE_MODE = 'simple' as const; | ||
|
||
type SimpleMode = typeof SIMPLE_MODE; | ||
|
||
const MODES = [SIMPLE_MODE] as const; | ||
|
||
type Mode = typeof MODES[number]; | ||
|
||
export type ModeSelectorSettingsValue = { | ||
mode: Mode, | ||
} & ({ | ||
mode: SimpleMode, | ||
exerciseTimeMs: BigInt, // TODO positive... | ||
restTimeMs: BigInt, // TODO positive... | ||
rounds: BigInt, // TODO positive... | ||
}) | ||
|
||
export type ModeSelectorSettings = Readonly<{ | ||
[k in Mode]: Readonly<Omit<ModeSelectorSettingsValue & { | ||
mode: k | ||
}, 'mode'>> | ||
}> | ||
|
||
export type ModeSelectorState = Readonly<{ | ||
selected: Mode, | ||
settings: ModeSelectorSettings, | ||
}>; | ||
|
||
export const modeSelectorState0: ModeSelectorState = Object.freeze({ | ||
selected: DEFAULT_MODE, | ||
settings: Object.freeze({ | ||
simple: Object.freeze({ | ||
exerciseTimeMs: DEFAULT_EXERCISE_TIME_MS, | ||
restTimeMs: DEFAULT_REST_TIME_MS, | ||
rounds: DEFAULT_ROUNDS, | ||
}) | ||
}) | ||
}); | ||
|
||
const PREPARATION_STEP = 'preparation' as const; | ||
const EXERCISE_STEP = 'exercise' as const; | ||
const REST_STEP = 'rest' as const; | ||
|
||
const SIMPLE_PROGRAM_STEPS = [ | ||
PREPARATION_STEP, | ||
EXERCISE_STEP, | ||
REST_STEP, | ||
] as const; | ||
|
||
type SimpleProgramStep = typeof SIMPLE_PROGRAM_STEPS[number]; | ||
|
||
type ProgramPerMode = { | ||
[k in Mode]: Program<string> | ||
} & ({ | ||
simple: Program<SimpleProgramStep> | ||
}); | ||
|
||
const simpleModeSelectorToProgram = (settings: Omit<ModeSelectorSettingsValue & {mode: SimpleMode}, 'mode'>): ProgramPerMode[SimpleMode] => | ||
Object.freeze([...Array(settings.rounds).keys()].flatMap(i => [ | ||
...(i === 0 ? [{kind: PREPARATION_STEP, duration: 3000/*TODO make configurable*/}] : []), | ||
{ kind: EXERCISE_STEP, duration: Number(settings.exerciseTimeMs) }, | ||
...(Number(settings.rounds) === i + 1 ? [] : [{ kind: REST_STEP, duration: Number(settings.restTimeMs) }]), | ||
])) | ||
|
||
|
||
const selectorToProgram = (selector: ModeSelectorState): ProgramPerMode[typeof selector.selected] => { | ||
const settings = selector.settings[selector.selected]; | ||
switch (selector.selected) { | ||
case SIMPLE_MODE: { | ||
return simpleModeSelectorToProgram(settings) | ||
} | ||
} | ||
} | ||
|
||
export type ModeSelectorSettingsViewValue = ModeSelectorSettingsValue; | ||
|
||
export type ViewValue = ViewActiveValue & ViewQueryValue & ({ | ||
running: 'running', | ||
startButton: InactiveButton, | ||
stopButton: InactiveButton, | ||
pauseButton: ActiveButton<PauseClickedEvent>, | ||
continueButton: InactiveButton, | ||
} | { | ||
running: 'paused', | ||
startButton: InactiveButton, | ||
stopButton: ActiveButton<StopClickedEvent>, | ||
pauseButton: InactiveButton, | ||
continueButton: ActiveButton<ContinueClickedEvent>, | ||
} | { | ||
running: 'stopped', | ||
startButton: ActiveButton<StartClickedEvent>, | ||
stopButton: InactiveButton, | ||
pauseButton: InactiveButton, | ||
continueButton: InactiveButton, | ||
modeSelector: ModeSelectorSettingsViewValue | ||
// todo program queries | ||
}); | ||
type View_<S, R> = (state: S) => R; | ||
export type View = View_<State, ViewValue>; | ||
|
||
export const reduce = (state: State, action: Action): State => { | ||
switch (action._tag) { | ||
case 'StartClicked': { | ||
if (state.running === 'running' || state.running === 'paused') return state; | ||
const program = selectorToProgram(state.mode); | ||
return { | ||
...state, | ||
running: 'running', | ||
program, | ||
fsmState: pipe(state.fsmState, reset, push(program)) | ||
}; | ||
} | ||
case 'StopClicked': { | ||
if (state.running === 'stopped' || state.running === 'running'/*pause before stopping*/) return state; | ||
const program = selectorToProgram(state.mode); | ||
return { | ||
...state, | ||
running: 'stopped', | ||
program, | ||
fsmState: pipe(state.fsmState, reset), | ||
}; | ||
} | ||
case 'PauseClicked': { | ||
if (state.running === 'stopped' || state.running === 'paused') return state; | ||
return { | ||
...state, | ||
running: 'paused', | ||
}; | ||
} | ||
case 'ContinueClicked': { | ||
if (state.running === 'stopped' || state.running === 'running') return state; | ||
return { | ||
...state, | ||
running: 'running', | ||
}; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"extends": "../tsconfig.base.json", | ||
"compilerOptions": { | ||
"module": "commonjs", | ||
"forceConsistentCasingInFileNames": true, | ||
"strict": true, | ||
"noImplicitOverride": true, | ||
"noPropertyAccessFromIndexSignature": true, | ||
"noImplicitReturns": true, | ||
"noFallthroughCasesInSwitch": true | ||
}, | ||
"files": [], | ||
"include": [], | ||
"references": [ | ||
{ | ||
"path": "./tsconfig.lib.json" | ||
}, | ||
{ | ||
"path": "./tsconfig.spec.json" | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"extends": "./tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "../dist/out-tsc", | ||
"declaration": true, | ||
"types": ["node"] | ||
}, | ||
"include": ["src/**/*.ts"], | ||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"extends": "./tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "../dist/out-tsc", | ||
"module": "commonjs", | ||
"types": ["jest", "node"] | ||
}, | ||
"include": [ | ||
"jest.config.ts", | ||
"src/**/*.test.ts", | ||
"src/**/*.spec.ts", | ||
"src/**/*.d.ts" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export * from './lib/utils'; | ||
export * from './lib/pipe'; |
Oops, something went wrong.