-
-
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
Showing
31 changed files
with
3,376 additions
and
470 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
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 |
---|---|---|
@@ -1,18 +1,16 @@ | ||
/// <reference types="vite/client" /> | ||
|
||
|
||
export type ArrayElement<A> = A extends readonly (infer T)[] ? T : never; | ||
type DeepWriteable<T> = { -readonly [P in keyof T]: DeepWriteable<T[P]> }; | ||
export type ArrayElement<A> = A extends readonly (infer T)[] ? T : never | ||
type DeepWriteable<T> = { -readonly [P in keyof T]: DeepWriteable<T[P]> } | ||
type Cast<X, Y> = X extends Y ? X : Y | ||
type FromEntries<T> = T extends [infer Key, any][] | ||
? { [K in Cast<Key, string>]: Extract<ArrayElement<T>, [K, any]>[1]} | ||
? { [K in Cast<Key, string>]: Extract<ArrayElement<T>, [K, any]>[1] } | ||
: { [key in string]: any } | ||
|
||
export type FromEntriesWithReadOnly<T> = FromEntries<DeepWriteable<T>> | ||
|
||
|
||
declare global { | ||
interface ObjectConstructor { | ||
fromEntries<T>(obj: T): FromEntriesWithReadOnly<T> | ||
} | ||
} | ||
} |
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 |
---|---|---|
|
@@ -18,4 +18,4 @@ export const EXAMPLE_RECIPE = ` | |
Морковь 1 cup | ||
Редис 2 cup | ||
Зеленый лук 8 шт | ||
`; | ||
` |
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,5 +1,3 @@ | ||
import RecipeCalculator from './RecipeCalculator.vue' | ||
|
||
export { | ||
RecipeCalculator | ||
} | ||
export { RecipeCalculator } |
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,97 +1,99 @@ | ||
import {EXAMPLE_RECIPE} from './constants'; | ||
import { EXAMPLE_RECIPE } from './constants' | ||
|
||
export interface RecipeState { | ||
rawRecipe: string, | ||
scale: number, | ||
newScale: number, | ||
rawRecipe: string | ||
scale: number | ||
newScale: number | ||
} | ||
|
||
const RecipeStateDefaults: RecipeState = { | ||
rawRecipe: EXAMPLE_RECIPE, | ||
scale: 1, | ||
newScale: 1, | ||
}; | ||
newScale: 1 | ||
} | ||
|
||
const RECIPE_STATE_KEYS = Object.keys(RecipeStateDefaults) as (keyof RecipeState)[]; | ||
const RECIPE_STATE_KEYS = Object.keys(RecipeStateDefaults) as (keyof RecipeState)[] | ||
|
||
// From https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem. | ||
export function base64ToBytes(base64: string): string { | ||
const binString = atob(base64); | ||
const binString = atob(base64) | ||
// @ts-ignore | ||
const buffer = Uint8Array.from(binString, (m) => m.codePointAt(0)); | ||
return new TextDecoder().decode(buffer); | ||
const buffer = Uint8Array.from(binString, (m) => m.codePointAt(0)) | ||
return new TextDecoder().decode(buffer) | ||
} | ||
|
||
// From https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem. | ||
export function bytesToBase64(bytes: string): string { | ||
const binString = String.fromCodePoint(...new TextEncoder().encode(bytes)); | ||
return btoa(binString); | ||
const binString = String.fromCodePoint(...new TextEncoder().encode(bytes)) | ||
return btoa(binString) | ||
} | ||
|
||
const removeUndefinedValuesFromObject = <T extends object>(obj: T): T => { | ||
// @ts-ignore | ||
Object.keys(obj).forEach((key) => obj[key] === undefined && delete obj[key]); | ||
return obj; | ||
}; | ||
Object.keys(obj).forEach((key) => obj[key] === undefined && delete obj[key]) | ||
return obj | ||
} | ||
|
||
type PartialRecipeState = Record<keyof RecipeState, string | undefined> | ||
|
||
export function loadStateFromUrl(url: URL): PartialRecipeState { | ||
const obj = Object.fromEntries(RECIPE_STATE_KEYS.map(key => [key, url.searchParams.get(key) || undefined])); | ||
const obj = Object.fromEntries( | ||
RECIPE_STATE_KEYS.map((key) => [key, url.searchParams.get(key) || undefined]) | ||
) | ||
if (obj['rawRecipe']) { | ||
obj.rawRecipe = base64ToBytes(obj.rawRecipe); | ||
obj.rawRecipe = base64ToBytes(obj.rawRecipe) | ||
} | ||
return obj as PartialRecipeState; | ||
return obj as PartialRecipeState | ||
} | ||
|
||
export function loadStateFromLocalStorage(): PartialRecipeState { | ||
return Object.fromEntries( | ||
RECIPE_STATE_KEYS.map(key => [key, localStorage.getItem(key) || undefined]), | ||
) as PartialRecipeState; | ||
RECIPE_STATE_KEYS.map((key) => [key, localStorage.getItem(key) || undefined]) | ||
) as PartialRecipeState | ||
} | ||
|
||
|
||
export function loadState(): RecipeState { | ||
const urlState = removeUndefinedValuesFromObject(loadStateFromUrl(new URL(window.location.toString()))); | ||
const storageState = removeUndefinedValuesFromObject(loadStateFromLocalStorage()); | ||
const urlState = removeUndefinedValuesFromObject( | ||
loadStateFromUrl(new URL(window.location.toString())) | ||
) | ||
const storageState = removeUndefinedValuesFromObject(loadStateFromLocalStorage()) | ||
|
||
const state = {...RecipeStateDefaults, ...storageState, ...urlState}; | ||
const state = { ...RecipeStateDefaults, ...storageState, ...urlState } | ||
|
||
return { | ||
rawRecipe: state.rawRecipe || RecipeStateDefaults.rawRecipe, | ||
scale: Number.parseInt((state.scale || RecipeStateDefaults.scale).toString()), | ||
newScale: Number.parseInt((state.newScale || RecipeStateDefaults.newScale).toString()) | ||
|
||
} | ||
} | ||
|
||
export function saveStateToUrl(url: URL, state: RecipeState): URL { | ||
const _url = new URL(url.toString()); | ||
RECIPE_STATE_KEYS.map(key => { | ||
let v = state[key]; | ||
const _url = new URL(url.toString()) | ||
RECIPE_STATE_KEYS.map((key) => { | ||
let v = state[key] | ||
if (v) { | ||
if (key == 'rawRecipe') { | ||
v = bytesToBase64(v.toString()); | ||
v = bytesToBase64(v.toString()) | ||
} else { | ||
v = v.toString(); | ||
v = v.toString() | ||
} | ||
_url.searchParams.set(key, v); | ||
_url.searchParams.set(key, v) | ||
} | ||
}); | ||
return _url; | ||
}) | ||
return _url | ||
} | ||
|
||
export function saveStateLocalStorage(state: RecipeState): void { | ||
RECIPE_STATE_KEYS.map(key => { | ||
const v = state[key]; | ||
RECIPE_STATE_KEYS.map((key) => { | ||
const v = state[key] | ||
if (v) { | ||
localStorage.setItem(key, v.toString()); | ||
localStorage.setItem(key, v.toString()) | ||
} | ||
}); | ||
}) | ||
} | ||
|
||
export function saveState(state: RecipeState): void { | ||
const url = saveStateToUrl(new URL(window.location.toString()), state); | ||
window.history.replaceState('', '', url.toString()); | ||
saveStateLocalStorage(state); | ||
} | ||
const url = saveStateToUrl(new URL(window.location.toString()), state) | ||
window.history.replaceState('', '', url.toString()) | ||
saveStateLocalStorage(state) | ||
} |
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,10 +1,10 @@ | ||
export function valueDisplay(value?: number | number[]): string { | ||
let v = ''; | ||
let v = '' | ||
if (value) { | ||
v = value.toString(); | ||
v = value.toString() | ||
if (Array.isArray(value)) { | ||
v = value.join(' - '); | ||
v = value.join(' - ') | ||
} | ||
} | ||
return v; | ||
return v | ||
} |
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
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
Oops, something went wrong.