[ini]
This commit is contained in:
commit
2ec442c086
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
.geany
|
||||
build/
|
||||
5
source/data/conf.json
Normal file
5
source/data/conf.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"baseurl": "https://api.nextbike.net/api/api.php",
|
||||
"apikey": "xEsFhYZR5jpO1Ug1"
|
||||
}
|
||||
|
||||
13
source/data/localization/de.json
Normal file
13
source/data/localization/de.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"username": "Telefon-Nummer",
|
||||
"password": "Passwort",
|
||||
"bikename": "Rad-Nummer",
|
||||
"login": "Anmelden",
|
||||
"logout": "Abmelden",
|
||||
"rent": "Leihe hinzufügen",
|
||||
"start": "starten",
|
||||
"open": "Schloss öffnen",
|
||||
"pause": "unterbrechen",
|
||||
"finish": "beenden"
|
||||
}
|
||||
|
||||
13
source/data/localization/en.json
Normal file
13
source/data/localization/en.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"username": "phone number",
|
||||
"password": "password",
|
||||
"bikename": "bike number",
|
||||
"login": "login",
|
||||
"logout": "logout",
|
||||
"rent": "add rental",
|
||||
"start": "start",
|
||||
"open": "open lock",
|
||||
"pause": "break",
|
||||
"finish": "finish"
|
||||
}
|
||||
|
||||
13
source/data/localization/eo.json
Normal file
13
source/data/localization/eo.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"username": "telefon-nombro",
|
||||
"password": "pasvorto",
|
||||
"bikename": "biciklo-nombro",
|
||||
"login": "ensaluti",
|
||||
"logout": "elsaluti",
|
||||
"rent": "aldoni pruntajxon",
|
||||
"start": "komenci",
|
||||
"open": "malfermi sxlosilon",
|
||||
"pause": "halti",
|
||||
"finish": "finigi"
|
||||
}
|
||||
|
||||
BIN
source/fonts/strogg.ttf
Normal file
BIN
source/fonts/strogg.ttf
Normal file
Binary file not shown.
BIN
source/fonts/strogg.woff
Normal file
BIN
source/fonts/strogg.woff
Normal file
Binary file not shown.
BIN
source/fonts/strogg.woff2
Normal file
BIN
source/fonts/strogg.woff2
Normal file
Binary file not shown.
1
source/logic/base.ts
Normal file
1
source/logic/base.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
type int = number;
|
||||
53
source/logic/control/app.ts
Normal file
53
source/logic/control/app.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
namespace mod_control.app
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function setup
|
||||
(
|
||||
platform : lib_mvc.type_model<mod_platform.app.web.type_state>
|
||||
) : Promise<void>
|
||||
{
|
||||
let context_dom : HTMLElement = platform.state.element_dom;
|
||||
context_dom.querySelector(".app_login > button").addEventListener
|
||||
(
|
||||
"click",
|
||||
(event) =>
|
||||
{
|
||||
const username : string = ((document.querySelector(".app_username > input") as HTMLInputElement)).value;
|
||||
const password : string = ((document.querySelector(".app_password > input") as HTMLInputElement)).value;
|
||||
mod_model.app.login(platform.state.model, username, password);
|
||||
}
|
||||
);
|
||||
context_dom.querySelector(".app_logout > button").addEventListener
|
||||
(
|
||||
"click",
|
||||
(event) =>
|
||||
{
|
||||
mod_model.app.logout(platform.state.model);
|
||||
}
|
||||
);
|
||||
context_dom.querySelector(".app_rent > button").addEventListener
|
||||
(
|
||||
"click",
|
||||
(event) =>
|
||||
{
|
||||
mod_model.app.prepare_rental(platform.state.model);
|
||||
}
|
||||
);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function implementation_control
|
||||
(
|
||||
) : lib_mvc.type_control<mod_platform.app.web.type_state>
|
||||
{
|
||||
return {
|
||||
"setup": (model) => setup(model),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
68
source/logic/control/rental.ts
Normal file
68
source/logic/control/rental.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
namespace mod_control.rental
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function setup
|
||||
(
|
||||
platform : lib_mvc.type_model<mod_platform.rental.web.type_state>
|
||||
) : Promise<void>
|
||||
{
|
||||
let context_dom : HTMLElement = platform.state.element_dom;
|
||||
context_dom.querySelector(".rental_start").addEventListener
|
||||
(
|
||||
"click",
|
||||
(event) =>
|
||||
{
|
||||
const bike_name : string = lib_call.convey
|
||||
(
|
||||
platform.state.model.state.id,
|
||||
[
|
||||
x => lib_string.coin(".rental[rel=\"{{rel}}\"] > .rental_bike > input", {"rel": x}),
|
||||
x => (document.querySelector(x) as HTMLInputElement),
|
||||
x => x.value,
|
||||
]
|
||||
);
|
||||
mod_model.rental.start(platform.state.model, bike_name);
|
||||
}
|
||||
);
|
||||
context_dom.querySelector(".rental_open > button").addEventListener
|
||||
(
|
||||
"click",
|
||||
(event) =>
|
||||
{
|
||||
mod_model.rental.open(platform.state.model);
|
||||
}
|
||||
);
|
||||
context_dom.querySelector(".rental_pause > button").addEventListener
|
||||
(
|
||||
"click",
|
||||
(event) =>
|
||||
{
|
||||
mod_model.rental.pause(platform.state.model);
|
||||
}
|
||||
);
|
||||
context_dom.querySelector(".rental_finish > button").addEventListener
|
||||
(
|
||||
"click",
|
||||
(event) =>
|
||||
{
|
||||
mod_model.rental.end(platform.state.model);
|
||||
}
|
||||
);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function implementation_control
|
||||
(
|
||||
) : lib_mvc.type_control<mod_platform.rental.web.type_state>
|
||||
{
|
||||
return {
|
||||
"setup": (model) => setup(model),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
24
source/logic/helpers/call.ts
Normal file
24
source/logic/helpers/call.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
namespace lib_call
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function convey
|
||||
(
|
||||
value : any,
|
||||
functions : Array<Function>
|
||||
) : any
|
||||
{
|
||||
let result : any = value;
|
||||
functions.forEach
|
||||
(
|
||||
function_ =>
|
||||
{
|
||||
result = function_(result);
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
32
source/logic/helpers/conf.ts
Normal file
32
source/logic/helpers/conf.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
namespace lib_conf
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
var _data : any;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function load
|
||||
(
|
||||
path : string
|
||||
) : Promise<void>
|
||||
{
|
||||
_data = await fetch(path, {"method": "GET"}).then(x => x.json())
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function get
|
||||
(
|
||||
key : string
|
||||
) : any
|
||||
{
|
||||
return _data[key];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
68
source/logic/helpers/dom.ts
Normal file
68
source/logic/helpers/dom.ts
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
namespace lib_dom
|
||||
{
|
||||
|
||||
/**
|
||||
* @author fenris
|
||||
*/
|
||||
export function clone(
|
||||
element : Element,
|
||||
options : {
|
||||
context ?: Document;
|
||||
} = {}
|
||||
) : Node
|
||||
{
|
||||
options = Object.assign(
|
||||
{
|
||||
"context": document,
|
||||
},
|
||||
options
|
||||
);
|
||||
return options.context.importNode(element, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @author fenris
|
||||
*/
|
||||
export function request(
|
||||
id : string,
|
||||
options : {
|
||||
context ?: Document;
|
||||
arguments ?: (null | Record<string, any>);
|
||||
} = {}
|
||||
) : DocumentFragment
|
||||
{
|
||||
options = Object.assign(
|
||||
{
|
||||
"context": document,
|
||||
"arguments": null,
|
||||
},
|
||||
options
|
||||
);
|
||||
const template : (null | Element) = document.querySelector("template#" + id);
|
||||
if (template === null) {
|
||||
throw (new Error("template not found: " + id));
|
||||
}
|
||||
else {
|
||||
const fragment : DocumentFragment = (
|
||||
clone(
|
||||
template["content"],
|
||||
{
|
||||
"context": options.context,
|
||||
}
|
||||
) as DocumentFragment
|
||||
);
|
||||
if (options.arguments === null) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
for (let index : int = 0; index < fragment.children.length; index += 1) {
|
||||
const element : Element = fragment.children[index];
|
||||
element.innerHTML = lib_string.coin(element.innerHTML, options.arguments);
|
||||
}
|
||||
}
|
||||
return fragment;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
168
source/logic/helpers/loc.ts
Normal file
168
source/logic/helpers/loc.ts
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
namespace lib_loc
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
var _data : Record<string, Record<string, string>> = {};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
var _language_order : Array<string> = [];
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
var _resolve_path : ((language : string) => string);
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function load
|
||||
(
|
||||
language : string
|
||||
) : Promise<void>
|
||||
{
|
||||
if (_data.hasOwnProperty(language))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
_data[language] = ((await fetch(_resolve_path(language), {"method": "GET"}).then(x => x.json())) as Record<string, string>);
|
||||
}
|
||||
catch (error)
|
||||
{
|
||||
console.warn
|
||||
(
|
||||
lib_string.coin
|
||||
(
|
||||
"could not load localization data for language '{{language}}': {{error}}",
|
||||
{
|
||||
"language": language,
|
||||
"error": String(error),
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
// return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function get
|
||||
(
|
||||
key : string,
|
||||
options :
|
||||
{
|
||||
language ?: (null | string);
|
||||
} = {}
|
||||
) : string
|
||||
{
|
||||
options = Object.assign
|
||||
(
|
||||
{
|
||||
"language": null,
|
||||
},
|
||||
options
|
||||
);
|
||||
const language_list : Array<string> = (
|
||||
[]
|
||||
.concat((options.language === null) ? [] : [options.language])
|
||||
.concat(_language_order)
|
||||
);
|
||||
for (const language of language_list)
|
||||
{
|
||||
if (_data.hasOwnProperty(language) && _data[language].hasOwnProperty(key))
|
||||
{
|
||||
return _data[language][key];
|
||||
}
|
||||
else
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
return ("{" + key + "}");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function translate_item
|
||||
(
|
||||
selector : string,
|
||||
key : string,
|
||||
options :
|
||||
{
|
||||
kind ?: string;
|
||||
parameters ?: Record<string, any>;
|
||||
language ?: (null | string);
|
||||
context ?: (HTMLElement | DocumentFragment);
|
||||
} = {}
|
||||
) : void
|
||||
{
|
||||
options = Object.assign
|
||||
(
|
||||
{
|
||||
"kind": "textcontent",
|
||||
"parameters": {},
|
||||
"language": null,
|
||||
"context": document,
|
||||
},
|
||||
options
|
||||
);
|
||||
const dom_element : Element = options.context.querySelector(selector);
|
||||
const value : string = get(key, {"language": options.language});
|
||||
switch (options.kind)
|
||||
{
|
||||
default:
|
||||
{
|
||||
console.warn("unhandeld kind");
|
||||
break;
|
||||
}
|
||||
case "textcontent":
|
||||
{
|
||||
dom_element.textContent = value;
|
||||
break;
|
||||
}
|
||||
case "attribute":
|
||||
{
|
||||
dom_element.setAttribute(options.parameters["key"], value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function setup
|
||||
(
|
||||
language_order : Array<string>,
|
||||
options :
|
||||
{
|
||||
resolve_path ?: ((language : string) => string),
|
||||
} = {}
|
||||
) : Promise<void>
|
||||
{
|
||||
options = Object.assign
|
||||
(
|
||||
{
|
||||
"resolve_path": (language => lib_string.coin("localization/{{language}}.json", {"language": language})),
|
||||
},
|
||||
options
|
||||
);
|
||||
_resolve_path = options.resolve_path;
|
||||
_language_order = language_order;
|
||||
for await (const language of _language_order)
|
||||
{
|
||||
await load(language);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
166
source/logic/helpers/mvc.ts
Normal file
166
source/logic/helpers/mvc.ts
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
namespace lib_mvc
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_event<type_data> = {
|
||||
type : string;
|
||||
data : type_data;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_model<type_state> =
|
||||
{
|
||||
listeners : Array<((event : type_event<any>) => Promise<void>)>;
|
||||
state : type_state;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_view<type_state> =
|
||||
{
|
||||
setup : ((model : type_model<type_state>) => Promise<void>);
|
||||
update : ((model : type_model<type_state>, event : type_event<any>) => Promise<void>);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_control<type_state> =
|
||||
{
|
||||
setup : ((model : type_model<type_state>) => Promise<void>);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_complex<type_state> =
|
||||
{
|
||||
model : type_model<type_state>;
|
||||
views : Array<type_view<type_state>>;
|
||||
controls : Array<type_control<type_state>>;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function model_make<type_state>
|
||||
(
|
||||
state : type_state
|
||||
) : type_model<type_state>
|
||||
{
|
||||
return {
|
||||
"listeners": [],
|
||||
"state": state,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function model_listen<type_state, type_data>
|
||||
(
|
||||
model : type_model<type_state>,
|
||||
action : ((event : type_event<type_data>) => Promise<void>)
|
||||
) : void
|
||||
{
|
||||
model.listeners.push(action);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function model_notify<type_state, type_data>
|
||||
(
|
||||
model : type_model<type_state>,
|
||||
event : type_event<type_data>
|
||||
) : Promise<void>
|
||||
{
|
||||
for await (const action of model.listeners)
|
||||
{
|
||||
action(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function view_setup<type_state>
|
||||
(
|
||||
view : type_view<type_state>,
|
||||
model : type_model<type_state>,
|
||||
options :
|
||||
{
|
||||
blocking ?: boolean;
|
||||
} = {}
|
||||
) : Promise<void>
|
||||
{
|
||||
options = Object.assign
|
||||
(
|
||||
{
|
||||
"blocking": true,
|
||||
},
|
||||
options
|
||||
);
|
||||
await view.setup(model);
|
||||
model_listen
|
||||
(
|
||||
model,
|
||||
(info) =>
|
||||
{
|
||||
if (options.blocking)
|
||||
{
|
||||
return view.update(model, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
view.update(model, info);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function control_setup<type_state>
|
||||
(
|
||||
control : type_control<type_state>,
|
||||
model : type_model<type_state>,
|
||||
options :
|
||||
{
|
||||
} = {}
|
||||
) : Promise<void>
|
||||
{
|
||||
options = Object.assign
|
||||
(
|
||||
{
|
||||
},
|
||||
options
|
||||
);
|
||||
await control.setup(model);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function complex_setup<type_state>
|
||||
(
|
||||
complex : type_complex<type_state>
|
||||
) : Promise<void>
|
||||
{
|
||||
for await (const view of complex.views)
|
||||
{
|
||||
await view_setup<type_state>(view, complex.model);
|
||||
}
|
||||
for await (const control of complex.controls)
|
||||
{
|
||||
await control_setup<type_state>(control, complex.model);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
211
source/logic/helpers/nextbike.ts
Normal file
211
source/logic/helpers/nextbike.ts
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
namespace lib_nextbike
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
let _baseurl : (null | string) = null;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
let _apikey : (null | string) = null;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
let _testmode : boolean = false;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function setup
|
||||
(
|
||||
baseurl : string,
|
||||
apikey : string,
|
||||
options :
|
||||
{
|
||||
testmode ?: boolean;
|
||||
} = {}
|
||||
) : void
|
||||
{
|
||||
options = Object.assign
|
||||
(
|
||||
{
|
||||
"testmode": false,
|
||||
},
|
||||
options
|
||||
);
|
||||
_baseurl = baseurl;
|
||||
_apikey = apikey;
|
||||
_testmode = options.testmode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function api_call
|
||||
(
|
||||
action : string,
|
||||
loginkey : (null | string),
|
||||
input : Record<string, string>
|
||||
) : Promise<any>
|
||||
{
|
||||
if ((_baseurl === null) || (_apikey === null))
|
||||
{
|
||||
throw (new Error("API not set up yet; execute 'setup' function"));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_testmode)
|
||||
{
|
||||
return {
|
||||
"user": {
|
||||
"loginkey": "",
|
||||
},
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return (
|
||||
fetch
|
||||
(
|
||||
lib_string.coin
|
||||
(
|
||||
"{{baseurl}}?{{query}}",
|
||||
{
|
||||
"baseurl": _baseurl,
|
||||
"query": lib_call.convey
|
||||
(
|
||||
{
|
||||
"version": "v2",
|
||||
"format": "json",
|
||||
"apikey": _apikey,
|
||||
"action": action,
|
||||
"loginkey": loginkey,
|
||||
},
|
||||
[
|
||||
Object.entries,
|
||||
x => x.filter(([key, value]) => (value !== null)),
|
||||
x => x.map(([key, value]) => lib_string.coin("{{key}}={{value}}", {"key": key, "value": value})),
|
||||
x => x.join("&")
|
||||
]
|
||||
),
|
||||
}
|
||||
),
|
||||
{
|
||||
"method": "POST",
|
||||
"body": JSON.stringify(input),
|
||||
}
|
||||
)
|
||||
.then
|
||||
(
|
||||
response => response.json()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function login
|
||||
(
|
||||
mobile : string,
|
||||
pin : string
|
||||
) : Promise<any>
|
||||
{
|
||||
return api_call
|
||||
(
|
||||
"login",
|
||||
null,
|
||||
{"mobile": mobile, "pin": pin}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function logout
|
||||
(
|
||||
loginkey : string
|
||||
) : Promise<any>
|
||||
{
|
||||
return api_call
|
||||
(
|
||||
"logout",
|
||||
loginkey,
|
||||
{}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function open_lock
|
||||
(
|
||||
loginkey : string,
|
||||
bike : string
|
||||
) : Promise<any>
|
||||
{
|
||||
return api_call
|
||||
(
|
||||
"openLock",
|
||||
loginkey,
|
||||
{"bike": bike}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function rental_begin
|
||||
(
|
||||
loginkey : string,
|
||||
bike : string
|
||||
) : Promise<any>
|
||||
{
|
||||
return api_call
|
||||
(
|
||||
"rent",
|
||||
loginkey,
|
||||
{"bike": bike}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function rental_break
|
||||
(
|
||||
loginkey : string,
|
||||
bike : string
|
||||
) : Promise<any>
|
||||
{
|
||||
return api_call
|
||||
(
|
||||
"rentalBreak",
|
||||
loginkey,
|
||||
{"bike": bike}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function rental_end
|
||||
(
|
||||
loginkey : string,
|
||||
bike : string
|
||||
) : Promise<any>
|
||||
{
|
||||
return api_call
|
||||
(
|
||||
"return",
|
||||
loginkey,
|
||||
{"bike": bike}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
39
source/logic/helpers/storage.ts
Normal file
39
source/logic/helpers/storage.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
namespace lib_storage
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function write
|
||||
(
|
||||
key : string,
|
||||
value : any
|
||||
) : void
|
||||
{
|
||||
window.localStorage.setItem(key, JSON.stringify(value));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function read
|
||||
(
|
||||
key : string
|
||||
) : any
|
||||
{
|
||||
return JSON.parse(window.localStorage.getItem(key));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function kill
|
||||
(
|
||||
key : string
|
||||
) : any
|
||||
{
|
||||
return window.localStorage.removeItem(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
29
source/logic/helpers/string.ts
Normal file
29
source/logic/helpers/string.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
namespace lib_string
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function coin
|
||||
(
|
||||
template : string,
|
||||
arguments_ : Record<string, string>
|
||||
) : string
|
||||
{
|
||||
let result : string = template;
|
||||
Object.entries(arguments_).forEach
|
||||
(
|
||||
([key, value]) =>
|
||||
{
|
||||
result = result.replace
|
||||
(
|
||||
new RegExp("{{" + key + "}}", "g"),
|
||||
value
|
||||
);
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
179
source/logic/main.ts
Normal file
179
source/logic/main.ts
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
/**
|
||||
*/
|
||||
async function do_rental
|
||||
(
|
||||
rental_model : lib_mvc.type_model<mod_model.rental.type_subject>,
|
||||
target_dom : HTMLElement
|
||||
) : Promise<{complex : lib_mvc.type_complex<mod_platform.rental.web.type_state>; element : HTMLElement;}>
|
||||
{
|
||||
const platform : lib_mvc.type_model<mod_platform.rental.web.type_state> = lib_mvc.model_make<mod_platform.rental.web.type_state>
|
||||
(
|
||||
mod_platform.rental.web.make(rental_model)
|
||||
);
|
||||
|
||||
const rental_complex : lib_mvc.type_complex<mod_platform.rental.web.type_state> =
|
||||
{
|
||||
"model": platform,
|
||||
"views":
|
||||
[
|
||||
mod_view.rental.console_.implementation_view(),
|
||||
mod_view.rental.web.implementation_view(),
|
||||
],
|
||||
"controls":
|
||||
[
|
||||
mod_control.rental.implementation_control(),
|
||||
],
|
||||
};
|
||||
await mod_platform.rental.web.setup(platform, target_dom);
|
||||
await lib_mvc.complex_setup<mod_platform.rental.web.type_state>(rental_complex);
|
||||
|
||||
return Promise.resolve<{complex : lib_mvc.type_complex<mod_platform.rental.web.type_state>; element : HTMLElement;}>
|
||||
(
|
||||
{
|
||||
"complex": rental_complex,
|
||||
"element": platform.state.element_dom,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function do_app
|
||||
(
|
||||
app_model : lib_mvc.type_model<mod_model.app.type_subject>,
|
||||
target_dom : HTMLElement
|
||||
) : Promise<{complex : lib_mvc.type_complex<mod_platform.app.web.type_state>; element : HTMLElement;}>
|
||||
{
|
||||
const platform : lib_mvc.type_model<mod_platform.app.web.type_state> = lib_mvc.model_make<mod_platform.app.web.type_state>
|
||||
(
|
||||
mod_platform.app.web.make(app_model)
|
||||
);
|
||||
const app_complex : lib_mvc.type_complex<mod_platform.app.web.type_state> =
|
||||
{
|
||||
"model": platform,
|
||||
"views":
|
||||
[
|
||||
mod_view.app.console_.implementation_view(),
|
||||
mod_view.app.web.implementation_view(),
|
||||
],
|
||||
"controls":
|
||||
[
|
||||
mod_control.app.implementation_control(),
|
||||
],
|
||||
};
|
||||
await mod_platform.app.web.setup(platform, target_dom);
|
||||
await lib_mvc.complex_setup<mod_platform.app.web.type_state>(app_complex);
|
||||
|
||||
return Promise.resolve<{complex : lib_mvc.type_complex<mod_platform.app.web.type_state>; element : HTMLElement;}>
|
||||
(
|
||||
{
|
||||
"complex": app_complex,
|
||||
"element": platform.state.element_dom,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function main
|
||||
(
|
||||
) : Promise<void>
|
||||
{
|
||||
// consts
|
||||
const styles : Record<string, mod_view.app.web.type_style> =
|
||||
{
|
||||
"default": {"sheet_name": "style/default.css", "force_language": null},
|
||||
"strogg": {"sheet_name": "style/strogg.css", "force_language": "en"},
|
||||
};
|
||||
|
||||
// args
|
||||
const url : URL = new URL(window.location.href);
|
||||
let parameters : Record<string, string> = {};
|
||||
url.searchParams.forEach((value, key) => {parameters[key] = value;});
|
||||
const style_name : string = (
|
||||
(! ("style" in parameters))
|
||||
? "default"
|
||||
: ((! (parameters["style"] in styles)) ? "default" : parameters["style"])
|
||||
);
|
||||
const language : (null | string) = (parameters["language"] ?? null);
|
||||
|
||||
// vars
|
||||
const style : mod_view.app.web.type_style = styles[style_name];
|
||||
|
||||
// load conf
|
||||
await lib_conf.load("conf.json");
|
||||
|
||||
// setup localization
|
||||
await lib_loc.setup
|
||||
(
|
||||
(
|
||||
[
|
||||
style.force_language,
|
||||
language,
|
||||
navigator.language,
|
||||
]
|
||||
.filter(x => (x !== null))
|
||||
),
|
||||
{
|
||||
"resolve_path": (language => lib_string.coin("localization/{{language}}.json", {"language": language})),
|
||||
}
|
||||
);
|
||||
|
||||
// setup nextbike api
|
||||
lib_nextbike.setup(lib_conf.get("baseurl"), lib_conf.get("apikey"), {"testmode": true});
|
||||
|
||||
// place stylesheet
|
||||
{
|
||||
let link_dom : HTMLElement = document.createElement("link");
|
||||
link_dom.setAttribute("type", "text/css");
|
||||
link_dom.setAttribute("rel", "stylesheet");
|
||||
link_dom.setAttribute("href", style.sheet_name);
|
||||
document.querySelector("head").appendChild(link_dom);
|
||||
}
|
||||
|
||||
// exec
|
||||
const loginkey : (null | string) = lib_storage.read("nextbike_loginkey");
|
||||
|
||||
let app_model : lib_mvc.type_model<mod_model.app.type_subject> = lib_mvc.model_make<mod_model.app.type_subject>(mod_model.app.inital(loginkey));
|
||||
const app_deed = await do_app(app_model, document.querySelector("body"));
|
||||
|
||||
// sub:rentals
|
||||
{
|
||||
lib_mvc.model_listen<mod_model.app.type_subject, any>
|
||||
(
|
||||
app_model,
|
||||
async (event) =>
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
default:
|
||||
{
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
case "new_rental":
|
||||
{
|
||||
let rental_model : lib_mvc.type_model<mod_model.rental.type_subject> = event.data["rental_model"];
|
||||
let rentals_dom : HTMLElement = app_deed.element.querySelector(".app_rentals");
|
||||
const rental_deed = await do_rental(rental_model, rentals_dom);
|
||||
return Promise.resolve<void>(undefined);
|
||||
break;
|
||||
}
|
||||
case "end_rental":
|
||||
{
|
||||
let rentals_dom : HTMLElement = app_deed.element.querySelector(".app_rentals");
|
||||
let rental_dom : HTMLElement = document.querySelector
|
||||
(
|
||||
lib_string.coin(".rental[rel=\"{{rel}}\"]", {"rel": event.data["id"]})
|
||||
);
|
||||
rentals_dom.removeChild(rental_dom);
|
||||
return Promise.resolve<void>(undefined);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
231
source/logic/model/app.ts
Normal file
231
source/logic/model/app.ts
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
namespace mod_model.app
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export enum enum_condition
|
||||
{
|
||||
logged_out,
|
||||
logged_in,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_subject =
|
||||
{
|
||||
condition : (null | enum_condition);
|
||||
loginkey : (null | string);
|
||||
rental_counter : int;
|
||||
rentals :
|
||||
{
|
||||
offer : Record<mod_model.rental.type_id, lib_mvc.type_model<mod_model.rental.type_subject>>;
|
||||
order : Array<mod_model.rental.type_id>;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function inital
|
||||
(
|
||||
loginkey : (null | string)
|
||||
) : type_subject
|
||||
{
|
||||
return {
|
||||
"condition": ((loginkey === null) ? enum_condition.logged_out : enum_condition.logged_in),
|
||||
"loginkey": loginkey,
|
||||
"rental_counter": 0,
|
||||
"rentals": {"offer": {}, "order": []},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function login
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>,
|
||||
username : string,
|
||||
password : string
|
||||
) : Promise<void>
|
||||
{
|
||||
const result : any = await lib_nextbike.login(username, password);
|
||||
model.state.loginkey = result["user"]["loginkey"];
|
||||
model.state.condition = enum_condition.logged_in;
|
||||
lib_storage.write("nextbike_loginkey", model.state.loginkey);
|
||||
lib_mvc.model_notify<type_subject, {}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "login",
|
||||
"data": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo end rentals?
|
||||
*/
|
||||
export async function logout
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>
|
||||
) : Promise<void>
|
||||
{
|
||||
const result : any = await lib_nextbike.logout(model.state.loginkey);
|
||||
lib_storage.kill("nextbike_loginkey");
|
||||
model.state.condition = enum_condition.logged_out;
|
||||
model.state.rentals = {"offer": {}, "order": []};
|
||||
lib_mvc.model_notify<type_subject, {}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "logout",
|
||||
"data": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function prepare_rental
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>
|
||||
) : Promise<void>
|
||||
{
|
||||
model.state.rental_counter += 1;
|
||||
const rental_id : mod_model.rental.type_id = model.state.rental_counter.toFixed(0);
|
||||
const rental_subject : mod_model.rental.type_subject = mod_model.rental.initial(rental_id);
|
||||
const rental_model : lib_mvc.type_model<mod_model.rental.type_subject> = lib_mvc.model_make(rental_subject);
|
||||
lib_mvc.model_listen<mod_model.rental.type_subject, any>
|
||||
(
|
||||
rental_model,
|
||||
async (event) =>
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
default:
|
||||
{
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
case "start":
|
||||
{
|
||||
await start_rental(model, rental_subject.bike_name);
|
||||
break;
|
||||
}
|
||||
case "pause":
|
||||
{
|
||||
await pause_rental(model, rental_subject.bike_name);
|
||||
break;
|
||||
}
|
||||
case "open":
|
||||
{
|
||||
await open_lock(model, rental_subject.bike_name);
|
||||
break;
|
||||
}
|
||||
case "end":
|
||||
{
|
||||
await end_rental(model, rental_subject.id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
model.state.rentals.offer[rental_id] = lib_mvc.model_make<mod_model.rental.type_subject>(rental_subject);
|
||||
model.state.rentals.order.push(rental_id);
|
||||
lib_mvc.model_notify<type_subject, {rental_model : lib_mvc.type_model<mod_model.rental.type_subject>}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "new_rental",
|
||||
"data": {"rental_model": rental_model}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function start_rental
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>,
|
||||
bike_name : string
|
||||
) : Promise<void>
|
||||
{
|
||||
const result : any = await lib_nextbike.rental_begin(model.state.loginkey, bike_name);
|
||||
lib_mvc.model_notify<type_subject, {}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "start_rental",
|
||||
"data": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function pause_rental
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>,
|
||||
bike_name : string
|
||||
) : Promise<void>
|
||||
{
|
||||
const result : any = await lib_nextbike.rental_break(model.state.loginkey, bike_name);
|
||||
lib_mvc.model_notify<type_subject, {}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "pause_rental",
|
||||
"data": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
async function open_lock
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>,
|
||||
bike_name : string
|
||||
) : Promise<void>
|
||||
{
|
||||
const result : any = await lib_nextbike.open_lock(model.state.loginkey, bike_name);
|
||||
lib_mvc.model_notify<type_subject, {}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "open_lock",
|
||||
"data": {}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function end_rental
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>,
|
||||
rental_id : mod_model.rental.type_id
|
||||
) : Promise<void>
|
||||
{
|
||||
lib_mvc.model_notify<type_subject, {}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "end_rental",
|
||||
"data": {"id": rental_id}
|
||||
}
|
||||
);
|
||||
model.state.rentals.order = model.state.rentals.order.filter(x => (x !== rental_id));
|
||||
delete model.state.rentals.offer[rental_id];
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
120
source/logic/model/rental.ts
Normal file
120
source/logic/model/rental.ts
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
namespace mod_model.rental
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_id = string;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export enum enum_condition
|
||||
{
|
||||
prior,
|
||||
running,
|
||||
paused,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_subject =
|
||||
{
|
||||
id : type_id;
|
||||
condition : enum_condition;
|
||||
bike_name : (null | string);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function initial
|
||||
(
|
||||
id : type_id
|
||||
) : type_subject
|
||||
{
|
||||
return {
|
||||
"id": id,
|
||||
"condition": enum_condition.prior,
|
||||
"bike_name": null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function start
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>,
|
||||
bike_name : string
|
||||
) : Promise<void>
|
||||
{
|
||||
model.state.condition = enum_condition.running;
|
||||
model.state.bike_name = bike_name;
|
||||
await lib_mvc.model_notify<type_subject, {id : type_id}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "start",
|
||||
"data": {"id": model.state.id}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function pause
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>
|
||||
) : Promise<void>
|
||||
{
|
||||
model.state.condition = enum_condition.paused;
|
||||
await lib_mvc.model_notify<type_subject, {id : type_id}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "pause",
|
||||
"data": {"id": model.state.id}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function open
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>
|
||||
) : Promise<void>
|
||||
{
|
||||
model.state.condition = enum_condition.running;
|
||||
await lib_mvc.model_notify<type_subject, {id : type_id}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "open",
|
||||
"data": {"id": model.state.id}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export async function end
|
||||
(
|
||||
model : lib_mvc.type_model<type_subject>
|
||||
) : Promise<void>
|
||||
{
|
||||
await lib_mvc.model_notify<type_subject, {id : type_id}>
|
||||
(
|
||||
model,
|
||||
{
|
||||
"type": "end",
|
||||
"data": {"id": model.state.id}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
66
source/logic/platform/web/app.ts
Normal file
66
source/logic/platform/web/app.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
namespace mod_platform.app.web
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_state =
|
||||
{
|
||||
model : lib_mvc.type_model<mod_model.app.type_subject>;
|
||||
element_dom : (null | HTMLElement);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function make
|
||||
(
|
||||
model : lib_mvc.type_model<mod_model.app.type_subject>
|
||||
) : type_state
|
||||
{
|
||||
return {
|
||||
"model": model,
|
||||
"element_dom": null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function setup
|
||||
(
|
||||
platform : lib_mvc.type_model<type_state>,
|
||||
target_dom : HTMLElement
|
||||
) : Promise<void>
|
||||
{
|
||||
let fragment : DocumentFragment = lib_dom.request("app");
|
||||
let app_dom : HTMLElement = fragment.querySelector(".app");
|
||||
target_dom.appendChild(fragment);
|
||||
|
||||
app_dom.classList.add("empty");
|
||||
|
||||
platform.state.element_dom = app_dom;
|
||||
|
||||
// propagate events from the model
|
||||
lib_mvc.model_listen<mod_model.app.type_subject, any>
|
||||
(
|
||||
platform.state.model,
|
||||
(event) =>
|
||||
{
|
||||
return lib_mvc.model_notify<type_state, any>(platform, event);
|
||||
}
|
||||
);
|
||||
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
// imitate interface of model
|
||||
// export function login(platform : lib_mvc.type_model<type_state>, username : string, password : string) : Promise<void> {return mod_model.app.login(platform.state.model, username, password);}
|
||||
// export function logout(platform : lib_mvc.type_model<type_state>) : Promise<void> {return mod_model.app.logout(platform.state.model);}
|
||||
// export function prepare_rental(platform : lib_mvc.type_model<type_state>) : Promise<void> {return mod_model.app.prepare_rental(platform.state.model);}
|
||||
// function start_rental(platform : lib_mvc.type_model<type_state>, bike_name : string) : Promise<void> {return mod_model.app.start_rental(platform.model, bike_name);}
|
||||
// function pause_rental(platform : lib_mvc.type_model<type_state>, bike_name : string) : Promise<void> {return mod_model.app.pause_rental(platform.model, bike_name);}
|
||||
// function open_lock(platform : lib_mvc.type_model<type_state>, bike_name : string) : Promise<void> {return mod_model.app.open_lock(platform.model, bike_name);}
|
||||
// function end_rental(platform : lib_mvc.type_model<type_state>, rental_id : mod_model.rental.type_id) : Promise<void> {return mod_model.app.end_rental(platform.model, rental_id);}
|
||||
|
||||
}
|
||||
54
source/logic/platform/web/rental.ts
Normal file
54
source/logic/platform/web/rental.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
namespace mod_platform.rental.web
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_state =
|
||||
{
|
||||
model : lib_mvc.type_model<mod_model.rental.type_subject>;
|
||||
element_dom : (null | HTMLElement);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function make
|
||||
(
|
||||
model : lib_mvc.type_model<mod_model.rental.type_subject>
|
||||
) : type_state
|
||||
{
|
||||
return {
|
||||
"model": model,
|
||||
"element_dom": null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function setup
|
||||
(
|
||||
platform : lib_mvc.type_model<type_state>,
|
||||
target_dom : HTMLElement
|
||||
) : Promise<void>
|
||||
{
|
||||
let fragment : DocumentFragment = lib_dom.request("rental");
|
||||
let rental_dom : HTMLElement = fragment.querySelector(".rental");
|
||||
target_dom.appendChild(fragment);
|
||||
|
||||
platform.state.element_dom = rental_dom;
|
||||
|
||||
// propagate events from the model
|
||||
lib_mvc.model_listen<mod_model.rental.type_subject, any>
|
||||
(
|
||||
platform.state.model,
|
||||
(event) =>
|
||||
{
|
||||
return lib_mvc.model_notify<type_state, any>(platform, event);
|
||||
}
|
||||
);
|
||||
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
}
|
||||
40
source/logic/view/console/app.ts
Normal file
40
source/logic/view/console/app.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
namespace mod_view.app.console_
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function setup
|
||||
(
|
||||
platform : lib_mvc.type_model<mod_platform.app.web.type_state>,
|
||||
) : Promise<void>
|
||||
{
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function update
|
||||
(
|
||||
platform : lib_mvc.type_model<mod_platform.app.web.type_state>,
|
||||
event : lib_mvc.type_event<any>
|
||||
) : Promise<void>
|
||||
{
|
||||
console.info("app", event.type, platform.state.model, event.data);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function implementation_view
|
||||
(
|
||||
) : lib_mvc.type_view<mod_platform.app.web.type_state>
|
||||
{
|
||||
return {
|
||||
"setup": (model) => setup(model),
|
||||
"update": (model, event) => update(model, event),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
40
source/logic/view/console/rental.ts
Normal file
40
source/logic/view/console/rental.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
namespace mod_view.rental.console_
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function setup
|
||||
(
|
||||
platform : lib_mvc.type_model<mod_platform.rental.web.type_state>
|
||||
) : Promise<void>
|
||||
{
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function update
|
||||
(
|
||||
platform : lib_mvc.type_model<mod_platform.rental.web.type_state>,
|
||||
event : lib_mvc.type_event<any>
|
||||
) : Promise<void>
|
||||
{
|
||||
console.info("rental", event.type, platform.state.model, event.data);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function implementation_view
|
||||
(
|
||||
) : lib_mvc.type_view<mod_platform.rental.web.type_state>
|
||||
{
|
||||
return {
|
||||
"setup": (model) => setup(model),
|
||||
"update": (model, event) => update(model, event),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
123
source/logic/view/web/app.ts
Normal file
123
source/logic/view/web/app.ts
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
namespace mod_view.app.web
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_style =
|
||||
{
|
||||
sheet_name : string;
|
||||
force_language : (null | string);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export type type_state =
|
||||
{
|
||||
context_dom : (null | HTMLElement);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function set_condition
|
||||
(
|
||||
state : type_state,
|
||||
condition : mod_model.app.enum_condition
|
||||
) : void
|
||||
{
|
||||
state.context_dom.classList.toggle("empty", false);
|
||||
state.context_dom.classList.toggle("logged_in", (condition === mod_model.app.enum_condition.logged_in));
|
||||
state.context_dom.classList.toggle("logged_out", (condition === mod_model.app.enum_condition.logged_out));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function make
|
||||
(
|
||||
) : type_state
|
||||
{
|
||||
return {
|
||||
"context_dom": null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function setup
|
||||
(
|
||||
state : type_state,
|
||||
platform : lib_mvc.type_model<mod_platform.app.web.type_state>,
|
||||
) : Promise<void>
|
||||
{
|
||||
let context_dom : HTMLElement = platform.state.element_dom;
|
||||
state.context_dom = context_dom;
|
||||
// translate stuff
|
||||
{
|
||||
lib_loc.translate_item(".app_username > input", "username", {"context": context_dom, "kind": "attribute", "parameters": {"key": "placeholder"}});
|
||||
lib_loc.translate_item(".app_password > input", "password", {"context": context_dom, "kind": "attribute", "parameters": {"key": "placeholder"}});
|
||||
lib_loc.translate_item(".app_login > button", "login", {"context": context_dom});
|
||||
lib_loc.translate_item(".app_logout > button", "logout", {"context": context_dom});
|
||||
lib_loc.translate_item(".app_rent > button", "rent", {"context": context_dom});
|
||||
}
|
||||
// list rentals
|
||||
{
|
||||
/*
|
||||
let rentals_dom : HTMLElement = document.querySelector("#rentals");
|
||||
rentals_dom.innerHTML = "";
|
||||
model.rentals.order.forEach
|
||||
(
|
||||
(rental_id) =>
|
||||
{
|
||||
}
|
||||
);
|
||||
*/
|
||||
}
|
||||
set_condition(state, platform.state.model.state.condition);
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function update
|
||||
(
|
||||
state : type_state,
|
||||
platform : lib_mvc.type_model<mod_platform.app.web.type_state>,
|
||||
event : lib_mvc.type_event<any>
|
||||
) : Promise<void>
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
default:
|
||||
{
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
case "login":
|
||||
case "logout":
|
||||
{
|
||||
set_condition(state, platform.state.model.state.condition);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function implementation_view
|
||||
(
|
||||
) : lib_mvc.type_view<mod_platform.app.web.type_state>
|
||||
{
|
||||
let state : type_state = make();
|
||||
return {
|
||||
"setup": (model) => setup(state, model),
|
||||
"update": (model, event) => update(state, model, event),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
151
source/logic/view/web/rental.ts
Normal file
151
source/logic/view/web/rental.ts
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
namespace mod_view.rental.web
|
||||
{
|
||||
|
||||
/**
|
||||
*/
|
||||
export function setup
|
||||
(
|
||||
platform : lib_mvc.type_model<mod_platform.rental.web.type_state>
|
||||
) : Promise<void>
|
||||
{
|
||||
let context_dom : HTMLElement = platform.state.element_dom;
|
||||
// container
|
||||
{
|
||||
context_dom.setAttribute("rel", platform.state.model.state.id);
|
||||
context_dom.classList.add
|
||||
(
|
||||
(
|
||||
(rental_state) =>
|
||||
{
|
||||
switch (rental_state)
|
||||
{
|
||||
case mod_model.rental.enum_condition.prior: return "prior";
|
||||
case mod_model.rental.enum_condition.running: return "running";
|
||||
case mod_model.rental.enum_condition.paused: return "paused";
|
||||
}
|
||||
}
|
||||
) (platform.state.model.state.condition),
|
||||
);
|
||||
}
|
||||
// bike
|
||||
{
|
||||
let bike_dom : HTMLInputElement = (context_dom.querySelector(".rental_bike > input") as HTMLInputElement)
|
||||
lib_loc.translate_item
|
||||
(
|
||||
".rental_bike > input",
|
||||
"bikename",
|
||||
{
|
||||
"context": context_dom,
|
||||
"kind": "attribute",
|
||||
"parameters": {"key": "placeholder"},
|
||||
}
|
||||
);
|
||||
bike_dom.value = (platform.state.model.state.bike_name ?? "");
|
||||
const disabled : boolean = (
|
||||
(
|
||||
(rental_state) =>
|
||||
{
|
||||
switch (rental_state)
|
||||
{
|
||||
case mod_model.rental.enum_condition.prior: return false;
|
||||
case mod_model.rental.enum_condition.running: return true;
|
||||
case mod_model.rental.enum_condition.paused: return true;
|
||||
}
|
||||
}
|
||||
) (platform.state.model.state.condition)
|
||||
);
|
||||
if (! disabled)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
bike_dom.setAttribute("disabled", "disabled");
|
||||
}
|
||||
}
|
||||
// start
|
||||
{
|
||||
lib_loc.translate_item(".rental_start > button", "start", {"context": context_dom});
|
||||
}
|
||||
// open
|
||||
{
|
||||
lib_loc.translate_item(".rental_open > button", "open", {"context": context_dom});
|
||||
}
|
||||
// pause
|
||||
{
|
||||
lib_loc.translate_item(".rental_pause > button", "pause", {"context": context_dom});
|
||||
}
|
||||
// finish
|
||||
{
|
||||
lib_loc.translate_item(".rental_finish > button", "finish", {"context": context_dom});
|
||||
}
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
function update
|
||||
(
|
||||
platform : lib_mvc.type_model<mod_platform.rental.web.type_state>,
|
||||
event : lib_mvc.type_event<any>
|
||||
) : Promise<void>
|
||||
{
|
||||
switch (event.type)
|
||||
{
|
||||
default:
|
||||
{
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
case "start":
|
||||
{
|
||||
let container_dom : HTMLElement = document.querySelector
|
||||
(
|
||||
lib_string.coin(".rental[rel=\"{{rel}}\"]", {"rel": event.data["id"]})
|
||||
);
|
||||
container_dom.classList.remove("prior");
|
||||
container_dom.classList.remove("paused");
|
||||
container_dom.classList.add("running");
|
||||
break;
|
||||
}
|
||||
case "pause":
|
||||
{
|
||||
let container_dom : HTMLElement = document.querySelector
|
||||
(
|
||||
lib_string.coin(".rental[rel=\"{{rel}}\"]", {"rel": event.data["id"]})
|
||||
);
|
||||
container_dom.classList.remove("prior");
|
||||
container_dom.classList.remove("running");
|
||||
container_dom.classList.add("paused");
|
||||
break;
|
||||
}
|
||||
case "open":
|
||||
{
|
||||
let container_dom : HTMLElement = document.querySelector
|
||||
(
|
||||
lib_string.coin(".rental[rel=\"{{rel}}\"]", {"rel": event.data["id"]})
|
||||
);
|
||||
container_dom.classList.remove("prior");
|
||||
container_dom.classList.remove("paused");
|
||||
container_dom.classList.add("running");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Promise.resolve<void>(undefined);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
export function implementation_view
|
||||
(
|
||||
) : lib_mvc.type_view<mod_platform.rental.web.type_state>
|
||||
{
|
||||
return {
|
||||
"setup": (model) => setup(model),
|
||||
"update": (model, event) => update(model, event),
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
74
source/media/logo.svg
Normal file
74
source/media/logo.svg
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg:svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
height="56.408779"
|
||||
width="100.46931"
|
||||
sodipodi:docname="Nextbike_Logo.svg"
|
||||
id="svg14"
|
||||
enable-background="new 0 0 392.2 56.5"
|
||||
viewBox="0 0 100.4693 56.408779"
|
||||
version="1.1">
|
||||
<svg:metadata
|
||||
id="metadata20">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</svg:metadata>
|
||||
<svg:defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
inkscape:current-layer="svg14"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-x="0"
|
||||
inkscape:cy="9.7905717"
|
||||
inkscape:cx="58.217152"
|
||||
inkscape:zoom="5.8898519"
|
||||
fit-margin-bottom="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-top="0"
|
||||
showgrid="false"
|
||||
id="namedview16"
|
||||
inkscape:window-height="1056"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff" />
|
||||
<svg:g
|
||||
transform="translate(-291.73069,-0.09122245)"
|
||||
id="g12"
|
||||
fill="#0154a6">
|
||||
<svg:path
|
||||
id="path10"
|
||||
d="m 301.2,15.8 c 0.7,1.7 -1.1,1.4 0.1,4.1 0.8,1.7 5.1,9 19.6,11.8 1.4,0.3 9.2,1.2 14.8,-2 1.9,-1.1 -2.6,-1 -4.9,-9.6 C 330,17 329.8,12.4 324.9,8.2 319.8,3.8 311.8,1.8 303.7,2 c -3.9,0.1 -11.3,0.6 -11.9,1.6 -0.7,1.4 4.1,3.2 5.5,4.9 1.1,1.3 -0.4,2 -0.1,3 0.5,2 3.7,3.6 4,4.3 z m 71.1,0.3 c -11.2,0 -19.9,9.1 -19.9,20.3 0,11.1 8.7,20 19.9,20 11.3,0 19.9,-9 19.9,-20 0,-11.2 -8.6,-20.3 -19.9,-20.3 z m 0,34.5 C 365,50.6 359,44.2 359,36.4 c 0,-8 6,-14.5 13.3,-14.5 7.4,0 13.4,6.5 13.4,14.5 0,7.9 -6,14.2 -13.4,14.2 z M 358.7,16.7 c 4.6,-2.4 11.2,-3.9 11.2,-8.6 0,-4 -5.2,-6.8 -7.4,-7.7 -1.7,-0.7 -3.6,-0.2 -4.3,1.4 -0.7,1.4 0.4,3.1 2.3,3.8 2,0.7 2.9,1.7 2.6,2.5 -0.3,0.9 -2.7,1.2 -7.1,3.4 -2.3,1.1 -4.3,2.9 -6.2,5 -2,2.1 -4,5.9 -5.1,8.2 -4.2,8 -12.2,10.4 -13.5,10.6 v 1.2 c 0,7.8 -6,14.2 -13.4,14.2 -7.3,0 -13.3,-6.4 -13.3,-14.2 0,-2.4 0.6,-4.7 1.5,-6.7 -1.4,-1 -4,-3.3 -5.3,-4.7 -1.2,2 -2.9,6.1 -2.9,11.4 0,11.1 8.7,20 19.9,20 10,0 17.8,-6.9 19.6,-16.1 7.3,-3 10.3,-7.4 12.5,-12 1.9,-4.3 4.3,-9.3 8.9,-11.7 z" />
|
||||
</svg:g>
|
||||
<link
|
||||
id="dark-mode-general-link"
|
||||
rel="stylesheet"
|
||||
type="text/css" />
|
||||
<link
|
||||
id="dark-mode-custom-link"
|
||||
rel="stylesheet"
|
||||
type="text/css" />
|
||||
<style
|
||||
id="dark-mode-custom-style"
|
||||
type="text/css" />
|
||||
</svg:svg>
|
||||
|
After Width: | Height: | Size: 3 KiB |
57
source/structure/index.html
Normal file
57
source/structure/index.html
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<template id="app">
|
||||
<div class="app">
|
||||
<div class="formfield app_username">
|
||||
<input type="text" placeholder="Telefon-Nummer"/>
|
||||
</div>
|
||||
<div class="formfield app_password">
|
||||
<input type="password" placeholder="Passwort"/>
|
||||
</div>
|
||||
<div class="formfield app_login">
|
||||
<button></button>
|
||||
</div>
|
||||
<ol class="app_rentals">
|
||||
</ol>
|
||||
<div class="formfield app_rent">
|
||||
<button></button>
|
||||
</div>
|
||||
<div class="formfield app_logout">
|
||||
<button></button>
|
||||
</div>
|
||||
<div class="app_logo">
|
||||
<img src="logo.svg"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template id="rental">
|
||||
<li class="rental">
|
||||
<div class="formfield rental_bike">
|
||||
<input type="text" placeholder="Rad-Nummer" pattern="[0-9]{5,6}"/>
|
||||
</div>
|
||||
<div class="formfield rental_start">
|
||||
<button></button>
|
||||
</div>
|
||||
<div class="formfield rental_open">
|
||||
<button></button>
|
||||
</div>
|
||||
<div class="formfield rental_pause">
|
||||
<button></button>
|
||||
</div>
|
||||
<div class="formfield rental_finish">
|
||||
<button></button>
|
||||
</div>
|
||||
<hr/>
|
||||
</li>
|
||||
</template>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script type="text/javascript" src="logic.js"></script>
|
||||
<script type="text/javascript">document.addEventListener("DOMContentLoaded", function (event) {main();})</script>
|
||||
<link rel="stylesheet" type="text/css" href="style/base.css"/>
|
||||
<title>ryde</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
154
source/style/base.less
Normal file
154
source/style/base.less
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
@font-face
|
||||
{
|
||||
font-family: 'strogg';
|
||||
src: url('../fonts/strogg.ttf') format('ttf'), url('../fonts/strogg.woff') format('woff'), url('../fonts/strogg.woff2') format('woff2');
|
||||
}
|
||||
|
||||
html
|
||||
{
|
||||
font-size: 2.5em;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
margin: 8px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.formfield
|
||||
{
|
||||
margin-bottom: 4px;
|
||||
|
||||
& > input,
|
||||
& > button
|
||||
{
|
||||
margin: 8px;
|
||||
padding: 8px;
|
||||
width: 93.75%;
|
||||
min-height: 64px;
|
||||
font-weight: bold;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
& > button
|
||||
{
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
& > input
|
||||
{
|
||||
border: none;
|
||||
}
|
||||
|
||||
& > button
|
||||
{
|
||||
border: none;
|
||||
}
|
||||
|
||||
& > label
|
||||
{
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
}
|
||||
|
||||
.app
|
||||
{
|
||||
&.empty
|
||||
{
|
||||
& > .app_username {display: none;}
|
||||
& > .app_password {display: none;}
|
||||
& > .app_bikename {display: none;}
|
||||
& > .app_login {display: none;}
|
||||
& > .app_logout {display: none;}
|
||||
& > .app_rentals {display: none;}
|
||||
& > .app_rent {display: none;}
|
||||
& > .app_pause {display: none;}
|
||||
& > .app_finish {display: none;}
|
||||
& > .app_open {display: none;}
|
||||
}
|
||||
|
||||
&.logged_out
|
||||
{
|
||||
& > .app_username {}
|
||||
& > .app_password {}
|
||||
& > .app_bikename {display: none;}
|
||||
& > .app_login {}
|
||||
& > .app_logout {display: none;}
|
||||
& > .app_rentals {display: none;}
|
||||
& > .app_rent {display: none;}
|
||||
& > .app_pause {display: none;}
|
||||
& > .app_finish {display: none;}
|
||||
& > .app_open {display: none;}
|
||||
}
|
||||
|
||||
&.logged_in
|
||||
{
|
||||
& > .app_username {display: none;}
|
||||
& > .app_password {display: none;}
|
||||
& > .app_bikename {}
|
||||
& > .app_login {display: none;}
|
||||
& > .app_logout {}
|
||||
& > .app_rentals {}
|
||||
& > .app_rent {}
|
||||
& > .app_pause {display: none;}
|
||||
& > .app_finish {display: none;}
|
||||
& > .app_open {display: none;}
|
||||
}
|
||||
}
|
||||
|
||||
.app_logo
|
||||
{
|
||||
width: 60%;
|
||||
margin: 20%;
|
||||
filter: saturate(0);
|
||||
|
||||
& > img
|
||||
{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.app_rentals
|
||||
{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
& > li
|
||||
{
|
||||
list-style-type: none;
|
||||
}
|
||||
}
|
||||
|
||||
.rental
|
||||
{
|
||||
&.prior
|
||||
{
|
||||
& > .rental_bike {}
|
||||
& > .rental_start {}
|
||||
& > .rental_pause {display: none;}
|
||||
& > .rental_finish {display: none;}
|
||||
& > .rental_open {display: none;}
|
||||
}
|
||||
|
||||
&.running
|
||||
{
|
||||
& > .rental_bike {}
|
||||
& > .rental_start {display: none;}
|
||||
& > .rental_pause {}
|
||||
& > .rental_finish {}
|
||||
& > .rental_open {}
|
||||
}
|
||||
|
||||
&.paused
|
||||
{
|
||||
& > .rental_bike {}
|
||||
& > .rental_start {display: none;}
|
||||
& > .rental_pause {display: none;}
|
||||
& > .rental_finish {display: none;}
|
||||
& > .rental_open {}
|
||||
}
|
||||
}
|
||||
40
source/style/default.less
Normal file
40
source/style/default.less
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
@hue: 150;
|
||||
|
||||
html
|
||||
{
|
||||
background-color: hsv(@hue, 0%, 0%);
|
||||
color: hsv(@hue, 0%, 100%);
|
||||
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
/*
|
||||
background-color: hsv(@hue, 0%, 25%);
|
||||
color: hsv(@hue, 0%, 75%);
|
||||
*/
|
||||
}
|
||||
|
||||
.formfield
|
||||
{
|
||||
& > input,
|
||||
& > button
|
||||
{
|
||||
font-family: monospace;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
& > input
|
||||
{
|
||||
background-color: hsv(@hue, 0%, 75%);
|
||||
color: hsv(@hue, 0%, 0%);
|
||||
}
|
||||
|
||||
& > button
|
||||
{
|
||||
background-color: hsv(@hue, 75%, 50%);
|
||||
color: hsv(@hue, 0%, 100%);
|
||||
}
|
||||
}
|
||||
|
||||
40
source/style/strogg.less
Normal file
40
source/style/strogg.less
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
@hue: 0;
|
||||
|
||||
html
|
||||
{
|
||||
background-color: hsv(@hue, 0%, 0%);
|
||||
color: hsv(@hue, 0%, 100%);
|
||||
|
||||
font-family: strogg;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
/*
|
||||
background-color: hsv(@hue, 0%, 25%);
|
||||
color: hsv(@hue, 0%, 75%);
|
||||
*/
|
||||
}
|
||||
|
||||
.formfield
|
||||
{
|
||||
& > input,
|
||||
& > button
|
||||
{
|
||||
font-family: strogg;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
& > input
|
||||
{
|
||||
background-color: hsv(@hue, 0%, 75%);
|
||||
color: hsv(@hue, 0%, 0%);
|
||||
}
|
||||
|
||||
& > button
|
||||
{
|
||||
background-color: hsv(@hue, 75%, 50%);
|
||||
color: hsv(@hue, 0%, 100%);
|
||||
}
|
||||
}
|
||||
|
||||
4
tools/build
Executable file
4
tools/build
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
make --file=tools/makefile
|
||||
|
||||
11
tools/deploy
Executable file
11
tools/deploy
Executable file
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
if [ $# -ge 1 ] ; then target=$1 && shift ; else target="pv-mehl:~/websites/folksprak.org/htdocs/ryde" ; fi
|
||||
|
||||
rsync \
|
||||
--recursive \
|
||||
--update \
|
||||
--verbose \
|
||||
build/ \
|
||||
${target}
|
||||
|
||||
146
tools/makefile
Normal file
146
tools/makefile
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
cmd_mkdir := mkdir -p
|
||||
cmd_log := echo "--"
|
||||
cmd_tsc := tsc --target es2020 --lib es2020,dom
|
||||
cmd_copy := cp --recursive --update
|
||||
cmd_lessc := lessc
|
||||
|
||||
|
||||
all: \
|
||||
structure \
|
||||
logic \
|
||||
style \
|
||||
conf \
|
||||
media \
|
||||
localization \
|
||||
fonts
|
||||
.PHONY: all
|
||||
|
||||
structure: structure-log structure-exe
|
||||
.PHONY: structure
|
||||
|
||||
structure-exe: \
|
||||
build/index.html
|
||||
.PHONY: structure-exe
|
||||
|
||||
structure-log:
|
||||
@ ${cmd_log} "structure …"
|
||||
.PHONY: structure-log
|
||||
|
||||
build/index.html: source/structure/index.html
|
||||
@ ${cmd_mkdir} build
|
||||
@ ${cmd_copy} $^ $@
|
||||
|
||||
logic: logic-log logic-exe
|
||||
.PHONY: logic
|
||||
|
||||
logic-log:
|
||||
@ ${cmd_log} "logic …"
|
||||
.PHONY: logic-log
|
||||
|
||||
logic-exe: \
|
||||
build/logic.js
|
||||
.PHONY: logic-exe
|
||||
|
||||
build/logic.js: \
|
||||
source/logic/base.ts \
|
||||
source/logic/helpers/call.ts \
|
||||
source/logic/helpers/string.ts \
|
||||
source/logic/helpers/storage.ts \
|
||||
source/logic/helpers/dom.ts \
|
||||
source/logic/helpers/mvc.ts \
|
||||
source/logic/helpers/loc.ts \
|
||||
source/logic/helpers/conf.ts \
|
||||
source/logic/helpers/nextbike.ts \
|
||||
source/logic/model/rental.ts \
|
||||
source/logic/model/app.ts \
|
||||
source/logic/platform/web/app.ts \
|
||||
source/logic/platform/web/rental.ts \
|
||||
source/logic/view/console/rental.ts \
|
||||
source/logic/view/console/app.ts \
|
||||
source/logic/view/web/rental.ts \
|
||||
source/logic/view/web/app.ts \
|
||||
source/logic/control/rental.ts \
|
||||
source/logic/control/app.ts \
|
||||
source/logic/main.ts
|
||||
@ ${cmd_mkdir} build
|
||||
@ ${cmd_tsc} $^ --outFile $@
|
||||
|
||||
style: style-log style-exe
|
||||
.PHONY: style
|
||||
|
||||
style-log:
|
||||
@ ${cmd_log} "style …"
|
||||
.PHONY: style-log
|
||||
|
||||
style-exe: \
|
||||
build/style/base.css \
|
||||
build/style/default.css \
|
||||
build/style/strogg.css
|
||||
.PHONY: style-exe
|
||||
|
||||
build/style/base.css: source/style/base.less
|
||||
@ ${cmd_mkdir} $(dir $@)
|
||||
@ ${cmd_lessc} $^ > $@
|
||||
|
||||
build/style/default.css: source/style/default.less
|
||||
@ ${cmd_mkdir} $(dir $@)
|
||||
@ ${cmd_lessc} $^ > $@
|
||||
|
||||
build/style/strogg.css: source/style/strogg.less
|
||||
@ ${cmd_mkdir} $(dir $@)
|
||||
@ ${cmd_lessc} $^ > $@
|
||||
|
||||
conf: conf-log conf-exe
|
||||
.PHONY: conf
|
||||
|
||||
conf-log:
|
||||
@ ${cmd_log} "conf …"
|
||||
.PHONY: conf-log
|
||||
|
||||
conf-exe: \
|
||||
build/conf.json
|
||||
.PHONY: conf-exe
|
||||
|
||||
build/conf.json: source/data/conf.json
|
||||
@ ${cmd_mkdir} $(dir $@)
|
||||
@ ${cmd_copy} $^ $@
|
||||
|
||||
media: media-log media-exe
|
||||
.PHONY: media
|
||||
|
||||
media-log:
|
||||
@ ${cmd_log} "media …"
|
||||
.PHONY: media-log
|
||||
|
||||
media-exe: \
|
||||
build/logo.svg
|
||||
.PHONY: media-exe
|
||||
|
||||
build/logo.svg: source/media/logo.svg
|
||||
@ ${cmd_mkdir} $(dir $@)
|
||||
@ ${cmd_copy} $^ $@
|
||||
|
||||
localization: localization-log localization-exe
|
||||
.PHONY: localization
|
||||
|
||||
localization-log:
|
||||
@ ${cmd_log} "localization …"
|
||||
.PHONY: localization-log
|
||||
|
||||
localization-exe:
|
||||
@ ${cmd_mkdir} build/localization
|
||||
@ ${cmd_copy} source/data/localization/* build/localization/
|
||||
.PHONY: localization-exe
|
||||
|
||||
fonts: fonts-log fonts-exe
|
||||
.PHONY: fonts
|
||||
|
||||
fonts-log:
|
||||
@ ${cmd_log} "fonts …"
|
||||
.PHONY: fonts-log
|
||||
|
||||
fonts-exe:
|
||||
@ ${cmd_mkdir} build/fonts
|
||||
@ ${cmd_copy} source/fonts/* build/fonts/
|
||||
.PHONY: fonts-exe
|
||||
|
||||
Loading…
Reference in a new issue