From b4e5b7f2a2e3910e51f28dc920f6a74711d1c7e3 Mon Sep 17 00:00:00 2001 From: emielvdveen Date: Wed, 9 Nov 2022 12:01:54 +0100 Subject: [PATCH] Redesign SplashScreen --- dist/assets/lottie/spinner-dark.json | 1 + dist/assets/lottie/spinner-light.json | 1 + dist/assets/lottie/spinner-primary.json | 1 + dist/framework/processing/python/worker.d.ts | 2 +- dist/framework/processing/python/worker.js | 2 +- dist/framework/processing/worker_engine.d.ts | 5 ++ dist/framework/processing/worker_engine.js | 81 ++++++++++++++++++- dist/framework/types/elements.d.ts | 14 +++- dist/framework/types/elements.js | 8 +- dist/framework/types/pages.d.ts | 3 +- .../framework/visualisation/react/engine.d.ts | 1 - dist/framework/visualisation/react/engine.js | 6 -- .../react/ui/elements/button.d.ts | 2 +- .../visualisation/react/ui/elements/button.js | 11 ++- .../react/ui/elements/spinner.d.ts | 5 +- .../react/ui/elements/spinner.js | 25 +++--- .../visualisation/react/ui/elements/text.d.ts | 3 +- .../visualisation/react/ui/elements/text.js | 4 + .../react/ui/pages/donation_page.js | 5 +- .../react/ui/pages/splash_screen.js | 41 +++++++--- dist/py_script.js | 2 +- dist/styles.css | 2 +- package-lock.json | 31 +++++++ package.json | 1 + src/assets/lottie/spinner-dark.json | 1 + src/assets/lottie/spinner-light.json | 1 + src/assets/lottie/spinner-primary.json | 1 + src/framework/processing/python/worker.js | 17 +--- src/framework/processing/worker_engine.ts | 41 +++++++++- src/framework/types/elements.ts | 23 +++++- src/framework/types/pages.ts | 3 +- src/framework/visualisation/react/engine.tsx | 7 -- .../react/ui/elements/button.tsx | 23 +++++- .../react/ui/elements/spinner.tsx | 32 ++++---- .../visualisation/react/ui/elements/text.tsx | 10 ++- .../react/ui/pages/donation_page.tsx | 5 -- .../react/ui/pages/splash_screen.tsx | 53 +++++++++--- src/py_script.ts | 9 +-- 38 files changed, 353 insertions(+), 130 deletions(-) create mode 100644 dist/assets/lottie/spinner-dark.json create mode 100644 dist/assets/lottie/spinner-light.json create mode 100644 dist/assets/lottie/spinner-primary.json create mode 100644 src/assets/lottie/spinner-dark.json create mode 100644 src/assets/lottie/spinner-light.json create mode 100644 src/assets/lottie/spinner-primary.json diff --git a/dist/assets/lottie/spinner-dark.json b/dist/assets/lottie/spinner-dark.json new file mode 100644 index 00000000..d147f861 --- /dev/null +++ b/dist/assets/lottie/spinner-dark.json @@ -0,0 +1 @@ +{"v":"5.7.5","fr":30,"ip":0,"op":50,"w":20,"h":20,"nm":"Loading spinner BLUE","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[10,10,0],"ix":2,"l":2},"a":{"a":0,"k":[3.178,3.178,0],"ix":1,"l":2},"s":{"a":0,"k":[36.9132,36.9132,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[45.356,45.356],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.13333333333333333,0.13333333333333333,0.13333333333333333,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3.178,3.178],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.335],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[0]},{"t":50,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.17],"y":[1]},"o":{"x":[0.362],"y":[0.158]},"t":0,"s":[0.1]},{"t":40,"s":[100]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.166],"y":[0.61]},"o":{"x":[0.75],"y":[0.35]},"t":0,"s":[0]},{"t":50,"s":[360]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/dist/assets/lottie/spinner-light.json b/dist/assets/lottie/spinner-light.json new file mode 100644 index 00000000..0f515a19 --- /dev/null +++ b/dist/assets/lottie/spinner-light.json @@ -0,0 +1 @@ +{"v":"5.7.5","fr":30,"ip":0,"op":50,"w":20,"h":20,"nm":"Loading spinner BLUE","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[10,10,0],"ix":2,"l":2},"a":{"a":0,"k":[3.178,3.178,0],"ix":1,"l":2},"s":{"a":0,"k":[36.9132,36.9132,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[45.356,45.356],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3.178,3.178],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.335],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[0]},{"t":50,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.17],"y":[1]},"o":{"x":[0.362],"y":[0.158]},"t":0,"s":[0.1]},{"t":40,"s":[100]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.166],"y":[0.61]},"o":{"x":[0.75],"y":[0.35]},"t":0,"s":[0]},{"t":50,"s":[360]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/dist/assets/lottie/spinner-primary.json b/dist/assets/lottie/spinner-primary.json new file mode 100644 index 00000000..dea3d01e --- /dev/null +++ b/dist/assets/lottie/spinner-primary.json @@ -0,0 +1 @@ +{"v":"5.7.5","fr":30,"ip":0,"op":50,"w":20,"h":20,"nm":"Loading spinner BLUE","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[10,10,0],"ix":2,"l":2},"a":{"a":0,"k":[3.178,3.178,0],"ix":1,"l":2},"s":{"a":0,"k":[36.9132,36.9132,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[45.356,45.356],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.25882352941176473,0.4470588235294118,0.9372549019607843,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3.178,3.178],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.335],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[0]},{"t":50,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.17],"y":[1]},"o":{"x":[0.362],"y":[0.158]},"t":0,"s":[0.1]},{"t":40,"s":[100]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.166],"y":[0.61]},"o":{"x":[0.75],"y":[0.35]},"t":0,"s":[0]},{"t":50,"s":[360]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/dist/framework/processing/python/worker.d.ts b/dist/framework/processing/python/worker.d.ts index bb57b326..1bdb56aa 100644 --- a/dist/framework/processing/python/worker.d.ts +++ b/dist/framework/processing/python/worker.d.ts @@ -5,4 +5,4 @@ declare function initialise(): any; declare function loadScript(script: any): void; declare function pyWorker(): string; declare let pyScript: any; -declare const pyPortApi: "\nclass CommandUIRender:\n __slots__ = \"page\"\n def __init__(self, page):\n self.page = page\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"CommandUIRender\"\n dict[\"page\"] = self.page.toDict()\n return dict\n\nclass CommandSystemDonate:\n __slots__ = \"key\", \"json_string\"\n def __init__(self, key, json_string):\n self.key = key\n self.json_string = json_string\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"CommandSystemDonate\"\n dict[\"key\"] = self.key\n dict[\"json_string\"] = self.json_string\n return dict\n\n \nclass PropsUIHeader:\n __slots__ = \"title\"\n def __init__(self, title):\n self.title = title\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIHeader\"\n dict[\"title\"] = self.title.toDict()\n return dict\n\n\nclass PropsUIPromptConfirm:\n __slots__ = \"text\", \"ok\", \"cancel\"\n def __init__(self, text, ok, cancel):\n self.text = text\n self.ok = ok\n self.cancel = cancel\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConfirm\"\n dict[\"text\"] = self.text.toDict()\n dict[\"ok\"] = self.ok.toDict()\n dict[\"cancel\"] = self.cancel.toDict()\n return dict\n\n\nclass PropsUISpinner:\n __slots__ = \"text\"\n def __init__(self, text):\n self.text = text\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUISpinner\"\n dict[\"text\"] = self.text.toDict()\n return dict\n\n\nclass PropsUIPromptConsentForm:\n __slots__ = \"title\", \"description\", \"tables\", \"meta_tables\"\n def __init__(self, title, description, tables, meta_tables):\n self.title = title\n self.description = description \n self.tables = tables\n self.meta_tables = meta_tables\n def translate_tables(self):\n output = []\n for table in self.tables:\n output.append(table.toDict())\n return output\n def translate_meta_tables(self):\n output = []\n for table in self.meta_tables:\n output.append(table.toDict())\n return output\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConsentForm\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"tables\"] = self.translate_tables()\n dict[\"metaTables\"] = self.translate_meta_tables()\n return dict\n\n\nclass PropsUIPromptConsentFormTable:\n __slots__ = \"id\", \"title\", \"data_frame\"\n def __init__(self, id, title, data_frame):\n self.id = id\n self.title = title\n self.data_frame = data_frame\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConsentFormTable\"\n dict[\"id\"] = self.id\n dict[\"title\"] = self.title\n dict[\"data_frame\"] = self.data_frame.to_json()\n return dict\n\n\nclass PropsUIPromptFileInput:\n __slots__ = \"title\", \"description\", \"extensions\"\n def __init__(self, title, description, extensions):\n self.title = title\n self.description = description\n self.extensions = extensions\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptFileInput\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"extensions\"] = self.extensions\n return dict\n\n\nclass PropsUIPromptRadioInput:\n __slots__ = \"title\", \"description\", \"items\"\n def __init__(self, title, description, items):\n self.title = title\n self.description = description\n self.items = items\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptRadioInput\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"items\"] = self.items\n return dict\n\n\nclass PropsUIPageDonation:\n __slots__ = \"header\", \"body\", \"spinner\"\n def __init__(self, header, body, spinner):\n self.header = header\n self.body = body\n self.spinner = spinner\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageDonation\"\n dict[\"header\"] = self.header.toDict()\n dict[\"body\"] = self.body.toDict()\n dict[\"spinner\"] = self.spinner.toDict()\n return dict\n\n\nclass PropsUIPageStart:\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageStart\"\n return dict\n\n\nclass PropsUIPageEnd:\n __slots__ = \"header\" \n def __init__(self, header):\n self.header = header\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageEnd\"\n dict[\"header\"] = self.header.toDict()\n return dict\n\n\nclass Translatable:\n __slots__ = \"translations\"\n def __init__(self, translations):\n self.translations = translations\n def toDict(self):\n dict = {}\n dict[\"translations\"] = self.translations\n return dict \n"; +declare const pyPortApi: "\nclass CommandUIRender:\n __slots__ = \"page\"\n def __init__(self, page):\n self.page = page\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"CommandUIRender\"\n dict[\"page\"] = self.page.toDict()\n return dict\n\nclass CommandSystemDonate:\n __slots__ = \"key\", \"json_string\"\n def __init__(self, key, json_string):\n self.key = key\n self.json_string = json_string\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"CommandSystemDonate\"\n dict[\"key\"] = self.key\n dict[\"json_string\"] = self.json_string\n return dict\n\n \nclass PropsUIHeader:\n __slots__ = \"title\"\n def __init__(self, title):\n self.title = title\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIHeader\"\n dict[\"title\"] = self.title.toDict()\n return dict\n\n\nclass PropsUIPromptConfirm:\n __slots__ = \"text\", \"ok\", \"cancel\"\n def __init__(self, text, ok, cancel):\n self.text = text\n self.ok = ok\n self.cancel = cancel\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConfirm\"\n dict[\"text\"] = self.text.toDict()\n dict[\"ok\"] = self.ok.toDict()\n dict[\"cancel\"] = self.cancel.toDict()\n return dict\n\n\nclass PropsUIPromptConsentForm:\n __slots__ = \"title\", \"description\", \"tables\", \"meta_tables\"\n def __init__(self, title, description, tables, meta_tables):\n self.title = title\n self.description = description \n self.tables = tables\n self.meta_tables = meta_tables\n def translate_tables(self):\n output = []\n for table in self.tables:\n output.append(table.toDict())\n return output\n def translate_meta_tables(self):\n output = []\n for table in self.meta_tables:\n output.append(table.toDict())\n return output\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConsentForm\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"tables\"] = self.translate_tables()\n dict[\"metaTables\"] = self.translate_meta_tables()\n return dict\n\n\nclass PropsUIPromptConsentFormTable:\n __slots__ = \"id\", \"title\", \"data_frame\"\n def __init__(self, id, title, data_frame):\n self.id = id\n self.title = title\n self.data_frame = data_frame\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConsentFormTable\"\n dict[\"id\"] = self.id\n dict[\"title\"] = self.title\n dict[\"data_frame\"] = self.data_frame.to_json()\n return dict\n\n\nclass PropsUIPromptFileInput:\n __slots__ = \"title\", \"description\", \"extensions\"\n def __init__(self, title, description, extensions):\n self.title = title\n self.description = description\n self.extensions = extensions\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptFileInput\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"extensions\"] = self.extensions\n return dict\n\n\nclass PropsUIPromptRadioInput:\n __slots__ = \"title\", \"description\", \"items\"\n def __init__(self, title, description, items):\n self.title = title\n self.description = description\n self.items = items\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptRadioInput\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"items\"] = self.items\n return dict\n\n\nclass PropsUIPageDonation:\n __slots__ = \"header\", \"body\"\n def __init__(self, header, body):\n self.header = header\n self.body = body\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageDonation\"\n dict[\"header\"] = self.header.toDict()\n dict[\"body\"] = self.body.toDict()\n return dict\n\n\nclass PropsUIPageStart:\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageStart\"\n return dict\n\n\nclass PropsUIPageEnd:\n __slots__ = \"header\" \n def __init__(self, header):\n self.header = header\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageEnd\"\n dict[\"header\"] = self.header.toDict()\n return dict\n\n\nclass Translatable:\n __slots__ = \"translations\"\n def __init__(self, translations):\n self.translations = translations\n def toDict(self):\n dict = {}\n dict[\"translations\"] = self.translations\n return dict \n"; diff --git a/dist/framework/processing/python/worker.js b/dist/framework/processing/python/worker.js index 85974cc9..193acbab 100644 --- a/dist/framework/processing/python/worker.js +++ b/dist/framework/processing/python/worker.js @@ -80,7 +80,7 @@ function loadScript(script) { self.pyodide.runPython(pyPortApi); self.pyodide.runPython(script); } -var pyPortApi = "\nclass CommandUIRender:\n __slots__ = \"page\"\n def __init__(self, page):\n self.page = page\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"CommandUIRender\"\n dict[\"page\"] = self.page.toDict()\n return dict\n\nclass CommandSystemDonate:\n __slots__ = \"key\", \"json_string\"\n def __init__(self, key, json_string):\n self.key = key\n self.json_string = json_string\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"CommandSystemDonate\"\n dict[\"key\"] = self.key\n dict[\"json_string\"] = self.json_string\n return dict\n\n \nclass PropsUIHeader:\n __slots__ = \"title\"\n def __init__(self, title):\n self.title = title\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIHeader\"\n dict[\"title\"] = self.title.toDict()\n return dict\n\n\nclass PropsUIPromptConfirm:\n __slots__ = \"text\", \"ok\", \"cancel\"\n def __init__(self, text, ok, cancel):\n self.text = text\n self.ok = ok\n self.cancel = cancel\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConfirm\"\n dict[\"text\"] = self.text.toDict()\n dict[\"ok\"] = self.ok.toDict()\n dict[\"cancel\"] = self.cancel.toDict()\n return dict\n\n\nclass PropsUISpinner:\n __slots__ = \"text\"\n def __init__(self, text):\n self.text = text\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUISpinner\"\n dict[\"text\"] = self.text.toDict()\n return dict\n\n\nclass PropsUIPromptConsentForm:\n __slots__ = \"title\", \"description\", \"tables\", \"meta_tables\"\n def __init__(self, title, description, tables, meta_tables):\n self.title = title\n self.description = description \n self.tables = tables\n self.meta_tables = meta_tables\n def translate_tables(self):\n output = []\n for table in self.tables:\n output.append(table.toDict())\n return output\n def translate_meta_tables(self):\n output = []\n for table in self.meta_tables:\n output.append(table.toDict())\n return output\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConsentForm\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"tables\"] = self.translate_tables()\n dict[\"metaTables\"] = self.translate_meta_tables()\n return dict\n\n\nclass PropsUIPromptConsentFormTable:\n __slots__ = \"id\", \"title\", \"data_frame\"\n def __init__(self, id, title, data_frame):\n self.id = id\n self.title = title\n self.data_frame = data_frame\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConsentFormTable\"\n dict[\"id\"] = self.id\n dict[\"title\"] = self.title\n dict[\"data_frame\"] = self.data_frame.to_json()\n return dict\n\n\nclass PropsUIPromptFileInput:\n __slots__ = \"title\", \"description\", \"extensions\"\n def __init__(self, title, description, extensions):\n self.title = title\n self.description = description\n self.extensions = extensions\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptFileInput\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"extensions\"] = self.extensions\n return dict\n\n\nclass PropsUIPromptRadioInput:\n __slots__ = \"title\", \"description\", \"items\"\n def __init__(self, title, description, items):\n self.title = title\n self.description = description\n self.items = items\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptRadioInput\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"items\"] = self.items\n return dict\n\n\nclass PropsUIPageDonation:\n __slots__ = \"header\", \"body\", \"spinner\"\n def __init__(self, header, body, spinner):\n self.header = header\n self.body = body\n self.spinner = spinner\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageDonation\"\n dict[\"header\"] = self.header.toDict()\n dict[\"body\"] = self.body.toDict()\n dict[\"spinner\"] = self.spinner.toDict()\n return dict\n\n\nclass PropsUIPageStart:\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageStart\"\n return dict\n\n\nclass PropsUIPageEnd:\n __slots__ = \"header\" \n def __init__(self, header):\n self.header = header\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageEnd\"\n dict[\"header\"] = self.header.toDict()\n return dict\n\n\nclass Translatable:\n __slots__ = \"translations\"\n def __init__(self, translations):\n self.translations = translations\n def toDict(self):\n dict = {}\n dict[\"translations\"] = self.translations\n return dict \n"; +var pyPortApi = "\nclass CommandUIRender:\n __slots__ = \"page\"\n def __init__(self, page):\n self.page = page\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"CommandUIRender\"\n dict[\"page\"] = self.page.toDict()\n return dict\n\nclass CommandSystemDonate:\n __slots__ = \"key\", \"json_string\"\n def __init__(self, key, json_string):\n self.key = key\n self.json_string = json_string\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"CommandSystemDonate\"\n dict[\"key\"] = self.key\n dict[\"json_string\"] = self.json_string\n return dict\n\n \nclass PropsUIHeader:\n __slots__ = \"title\"\n def __init__(self, title):\n self.title = title\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIHeader\"\n dict[\"title\"] = self.title.toDict()\n return dict\n\n\nclass PropsUIPromptConfirm:\n __slots__ = \"text\", \"ok\", \"cancel\"\n def __init__(self, text, ok, cancel):\n self.text = text\n self.ok = ok\n self.cancel = cancel\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConfirm\"\n dict[\"text\"] = self.text.toDict()\n dict[\"ok\"] = self.ok.toDict()\n dict[\"cancel\"] = self.cancel.toDict()\n return dict\n\n\nclass PropsUIPromptConsentForm:\n __slots__ = \"title\", \"description\", \"tables\", \"meta_tables\"\n def __init__(self, title, description, tables, meta_tables):\n self.title = title\n self.description = description \n self.tables = tables\n self.meta_tables = meta_tables\n def translate_tables(self):\n output = []\n for table in self.tables:\n output.append(table.toDict())\n return output\n def translate_meta_tables(self):\n output = []\n for table in self.meta_tables:\n output.append(table.toDict())\n return output\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConsentForm\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"tables\"] = self.translate_tables()\n dict[\"metaTables\"] = self.translate_meta_tables()\n return dict\n\n\nclass PropsUIPromptConsentFormTable:\n __slots__ = \"id\", \"title\", \"data_frame\"\n def __init__(self, id, title, data_frame):\n self.id = id\n self.title = title\n self.data_frame = data_frame\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptConsentFormTable\"\n dict[\"id\"] = self.id\n dict[\"title\"] = self.title\n dict[\"data_frame\"] = self.data_frame.to_json()\n return dict\n\n\nclass PropsUIPromptFileInput:\n __slots__ = \"title\", \"description\", \"extensions\"\n def __init__(self, title, description, extensions):\n self.title = title\n self.description = description\n self.extensions = extensions\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptFileInput\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"extensions\"] = self.extensions\n return dict\n\n\nclass PropsUIPromptRadioInput:\n __slots__ = \"title\", \"description\", \"items\"\n def __init__(self, title, description, items):\n self.title = title\n self.description = description\n self.items = items\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPromptRadioInput\"\n dict[\"title\"] = self.title.toDict()\n dict[\"description\"] = self.description.toDict()\n dict[\"items\"] = self.items\n return dict\n\n\nclass PropsUIPageDonation:\n __slots__ = \"header\", \"body\"\n def __init__(self, header, body):\n self.header = header\n self.body = body\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageDonation\"\n dict[\"header\"] = self.header.toDict()\n dict[\"body\"] = self.body.toDict()\n return dict\n\n\nclass PropsUIPageStart:\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageStart\"\n return dict\n\n\nclass PropsUIPageEnd:\n __slots__ = \"header\" \n def __init__(self, header):\n self.header = header\n def toDict(self):\n dict = {}\n dict[\"__type__\"] = \"PropsUIPageEnd\"\n dict[\"header\"] = self.header.toDict()\n return dict\n\n\nclass Translatable:\n __slots__ = \"translations\"\n def __init__(self, translations):\n self.translations = translations\n def toDict(self):\n dict = {}\n dict[\"translations\"] = self.translations\n return dict \n"; function pyWorker() { return "\n from collections.abc import Generator\n import json\n import html\n import pandas as pd\n\n\n class ScriptWrapper(Generator):\n def __init__(self, script):\n self.script = script\n def send(self, data):\n command = self.script.send(data)\n return command.toDict()\n def throw(self, type=None, value=None, traceback=None):\n raise StopIteration\n script = process()\n ScriptWrapper(script)\n "; } diff --git a/dist/framework/processing/worker_engine.d.ts b/dist/framework/processing/worker_engine.d.ts index 92591eca..ab532d6a 100644 --- a/dist/framework/processing/worker_engine.d.ts +++ b/dist/framework/processing/worker_engine.d.ts @@ -4,9 +4,14 @@ export default class WorkerProcessingEngine implements ProcessingEngine { worker: Worker; commandHandler: CommandHandler; script: Script; + resolveInitialized: () => void; + resolveContinue: () => void; constructor(worker: Worker, commandHandler: CommandHandler); handleEvent(event: any): void; start(script: Script): void; + waitForInitialization(): Promise; + waitForSplashScreen(): Promise; + renderSplashScreen(): void; loadScript(script: any): void; firstRunCycle(): void; nextRunCycle(response: Response): void; diff --git a/dist/framework/processing/worker_engine.js b/dist/framework/processing/worker_engine.js index 38b1809e..245c9bd4 100644 --- a/dist/framework/processing/worker_engine.js +++ b/dist/framework/processing/worker_engine.js @@ -1,3 +1,39 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; import { isCommand } from '../types/commands'; var WorkerProcessingEngine = /** @class */ (function () { function WorkerProcessingEngine(worker, commandHandler) { @@ -20,7 +56,7 @@ var WorkerProcessingEngine = /** @class */ (function () { break; case 'loadScriptDone': console.log('[ReactEngine] Received: loadScriptDone'); - this.firstRunCycle(); + this.resolveInitialized(); break; case 'runCycleDone': console.log('[ReactEngine] received: event', event.data.scriptEvent); @@ -31,9 +67,50 @@ var WorkerProcessingEngine = /** @class */ (function () { } }; WorkerProcessingEngine.prototype.start = function (script) { + var _this = this; console.log('[WorkerProcessingEngine] started'); this.script = script; - this.worker.postMessage({ eventType: 'initialise' }); + var waitForInitialization = this.waitForInitialization(); + var waitForSplashScreen = this.waitForSplashScreen(); + Promise.all([waitForInitialization, waitForSplashScreen]).then(function () { _this.firstRunCycle(); }, function () { }); + }; + WorkerProcessingEngine.prototype.waitForInitialization = function () { + return __awaiter(this, void 0, void 0, function () { + var _this = this; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, new Promise(function (resolve) { + _this.resolveInitialized = resolve; + _this.worker.postMessage({ eventType: 'initialise' }); + })]; + case 1: return [2 /*return*/, _a.sent()]; + } + }); + }); + }; + WorkerProcessingEngine.prototype.waitForSplashScreen = function () { + return __awaiter(this, void 0, void 0, function () { + var _this = this; + return __generator(this, function (_a) { + switch (_a.label) { + case 0: return [4 /*yield*/, new Promise(function (resolve) { + _this.resolveContinue = resolve; + _this.renderSplashScreen(); + })]; + case 1: return [2 /*return*/, _a.sent()]; + } + }); + }); + }; + WorkerProcessingEngine.prototype.renderSplashScreen = function () { + var _this = this; + var command = { __type__: 'CommandUIRender', page: { __type__: 'PropsUIPageSplashScreen' } }; + if (isCommand(command)) { + this.commandHandler.onCommand(command).then(function (_response) { return _this.resolveContinue(); }, function () { }); + } + else { + console.log('HUH?!'); + } }; WorkerProcessingEngine.prototype.loadScript = function (script) { this.worker.postMessage({ eventType: 'loadScript', script: script }); diff --git a/dist/framework/types/elements.d.ts b/dist/framework/types/elements.d.ts index 053ccad4..578b7718 100644 --- a/dist/framework/types/elements.d.ts +++ b/dist/framework/types/elements.d.ts @@ -1,10 +1,17 @@ import { PropsUIPage } from './pages'; import { PropsUIPrompt } from './prompts'; export declare type PropsUI = PropsUIText | PropsUIButton | PropsUICheckBox | PropsUIRadioItem | PropsUISpinner | PropsUIHeader | PropsUITable | PropsUISearchBar | PropsUIPage | PropsUIPrompt; -export declare type PropsUIText = PropsUITextTitle0 | PropsUITextTitle1 | PropsUITextTitle2 | PropsUITextTitle6 | PropsUITextBodyLarge; +export declare type PropsUIText = PropsUITextTitle0 | PropsUITextTitle1 | PropsUITextTitle2 | PropsUITextTitle6 | PropsUITextBodyLarge | PropsUITextLabel; export declare type PropsUIButton = PropsUIButtonPrimary | PropsUIButtonSecundary | PropsUIButtonForward | PropsUIButtonLabel; export declare function isPropsUI(arg: any): arg is PropsUI; export declare function isPropsUIText(arg: any): arg is PropsUIText; +export interface PropsUITextLabel { + __type__: 'PropsUITextLabel'; + text: string; + color?: string; + margin?: string; +} +export declare function isPropsUITextLabel(arg: any): arg is PropsUITextLabel; export interface PropsUITextBodyLarge { __type__: 'PropsUITextBodyLarge'; text: string; @@ -52,6 +59,8 @@ export interface PropsUIButtonPrimary { __type__: 'PropsUIButtonPrimary'; label: string; color?: string; + enabled?: boolean; + spinning?: boolean; onClick: () => void; } export declare function isPropsUIButtonPrimary(arg: any): arg is PropsUIButtonPrimary; @@ -96,7 +105,8 @@ export interface PropsUICheckBox { export declare function isPropsUICheckBox(arg: any): arg is PropsUICheckBox; export interface PropsUISpinner { __type__: 'PropsUISpinner'; - text: Text; + spinning?: boolean; + color?: string; } export declare function isPropsUISpinner(arg: any): arg is PropsUISpinner; export interface PropsUIHeader { diff --git a/dist/framework/types/elements.js b/dist/framework/types/elements.js index d6a4dd39..d289fe04 100644 --- a/dist/framework/types/elements.js +++ b/dist/framework/types/elements.js @@ -17,7 +17,11 @@ export function isPropsUIText(arg) { isPropsUITextTitle0(arg) || isPropsUITextTitle0(arg) || isPropsUITextBodyLarge(arg) || - isPropsUITextBodyMedium(arg); + isPropsUITextBodyMedium(arg) || + isPropsUITextLabel(arg); +} +export function isPropsUITextLabel(arg) { + return isInstanceOf(arg, 'PropsUITextLabel', ['text', 'color', 'margin']); } export function isPropsUITextBodyLarge(arg) { return isInstanceOf(arg, 'PropsUITextBodyLarge', ['text', 'color', 'margin']); @@ -66,7 +70,7 @@ export function isPropsUICheckBox(arg) { return isInstanceOf(arg, 'PropsUICheckBox', ['id', 'selected', 'onSelect']); } export function isPropsUISpinner(arg) { - return isInstanceOf(arg, 'PropsUISpinner', ['text']); + return isInstanceOf(arg, 'PropsUISpinner', ['color', 'spinning']); } export function isPropsUIHeader(arg) { return isInstanceOf(arg, 'PropsUIHeader', ['title']); diff --git a/dist/framework/types/pages.d.ts b/dist/framework/types/pages.d.ts index 42a0647d..f93e9519 100644 --- a/dist/framework/types/pages.d.ts +++ b/dist/framework/types/pages.d.ts @@ -1,4 +1,4 @@ -import { PropsUIHeader, PropsUISpinner } from './elements'; +import { PropsUIHeader } from './elements'; import { PropsUIPromptFileInput, PropsUIPromptConfirm, PropsUIPromptConsentForm } from './prompts'; export declare type PropsUIPage = PropsUIPageSplashScreen | PropsUIPageDonation | PropsUIPageStart | PropsUIPageEnd; export declare function isPropsUIPage(arg: any): arg is PropsUIPage; @@ -14,7 +14,6 @@ export interface PropsUIPageDonation { __type__: 'PropsUIPageDonation'; header: PropsUIHeader; body: PropsUIPromptFileInput | PropsUIPromptConfirm | PropsUIPromptConsentForm; - spinner: PropsUISpinner; } export declare function isPropsUIPageDonation(arg: any): arg is PropsUIPageDonation; export interface PropsUIPageEnd { diff --git a/dist/framework/visualisation/react/engine.d.ts b/dist/framework/visualisation/react/engine.d.ts index 18009fcc..25cc0394 100644 --- a/dist/framework/visualisation/react/engine.d.ts +++ b/dist/framework/visualisation/react/engine.d.ts @@ -11,7 +11,6 @@ export default class ReactEngine implements VisualisationEngine { constructor(factory: VisualisationFactory); start(rootElement: HTMLElement, locale: string): void; render(command: CommandUIRender): Promise; - renderSplashScreen(): void; renderPage(props: PropsUIPage): Promise; terminate(): void; renderElements(elements: JSX.Element[]): void; diff --git a/dist/framework/visualisation/react/engine.js b/dist/framework/visualisation/react/engine.js index de08f2f7..00b36255 100644 --- a/dist/framework/visualisation/react/engine.js +++ b/dist/framework/visualisation/react/engine.js @@ -45,7 +45,6 @@ var ReactEngine = /** @class */ (function () { console.log('[ReactEngine] started'); this.root = ReactDOM.createRoot(rootElement); this.locale = locale; - this.renderSplashScreen(); }; ReactEngine.prototype.render = function (command) { return __awaiter(this, void 0, void 0, function () { @@ -62,11 +61,6 @@ var ReactEngine = /** @class */ (function () { }); }); }; - ReactEngine.prototype.renderSplashScreen = function () { - var context = { locale: this.locale, resolve: function () { } }; - var page = this.factory.createPage({ __type__: 'PropsUIPageSplashScreen' }, context); - this.renderElements([page]); - }; ReactEngine.prototype.renderPage = function (props) { return __awaiter(this, void 0, void 0, function () { var _this = this; diff --git a/dist/framework/visualisation/react/ui/elements/button.d.ts b/dist/framework/visualisation/react/ui/elements/button.d.ts index 66d42b1d..b9e8befb 100644 --- a/dist/framework/visualisation/react/ui/elements/button.d.ts +++ b/dist/framework/visualisation/react/ui/elements/button.d.ts @@ -1,7 +1,7 @@ /// import { Weak } from '../../../../helpers'; import { PropsUIButtonBack, PropsUIButtonForward, PropsUIButtonLabel, PropsUIButtonPrimary, PropsUIButtonSecundary } from '../../../../types/elements'; -export declare const PrimaryButton: ({ label, color, onClick }: Weak) => JSX.Element; +export declare const PrimaryButton: ({ label, spinning, enabled, color, onClick }: Weak) => JSX.Element; export declare const SecondaryButton: ({ label, color, onClick }: Weak) => JSX.Element; export declare const BackButton: ({ label, onClick }: Weak) => JSX.Element; export declare const ForwardButton: ({ label, onClick }: Weak) => JSX.Element; diff --git a/dist/framework/visualisation/react/ui/elements/button.js b/dist/framework/visualisation/react/ui/elements/button.js index 65663fee..e94ea16d 100644 --- a/dist/framework/visualisation/react/ui/elements/button.js +++ b/dist/framework/visualisation/react/ui/elements/button.js @@ -12,9 +12,16 @@ var __assign = (this && this.__assign) || function () { import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import BackSvg from '../../../../../assets/images/back.svg'; import ForwardSvg from '../../../../../assets/images/forward.svg'; +import { Spinner } from './spinner'; +function spinnerColor(buttonColor) { + if (buttonColor.includes('bg-tertiary')) { + return 'dark'; + } + return 'light'; +} export var PrimaryButton = function (_a) { - var label = _a.label, _b = _a.color, color = _b === void 0 ? 'bg-primary text-white' : _b, onClick = _a.onClick; - return (_jsx("div", __assign({ className: "pt-15px pb-15px active:shadow-top4px active:pt-4 active:pb-14px leading-none font-button text-button rounded pr-4 pl-4 cursor-pointer ".concat(color), onClick: onClick }, { children: _jsx("div", __assign({ id: 'confirm-button', className: 'flex-wrap' }, { children: label })) }))); + var label = _a.label, _b = _a.spinning, spinning = _b === void 0 ? false : _b, _c = _a.enabled, enabled = _c === void 0 ? true : _c, _d = _a.color, color = _d === void 0 ? 'bg-primary text-white' : _d, onClick = _a.onClick; + return (_jsxs("div", __assign({ className: 'relative' }, { children: [_jsx("div", __assign({ className: "pt-15px pb-15px pr-4 pl-4 leading-none font-button text-button rounded ".concat(enabled ? 'cursor-pointer active:shadow-top4px active:pt-4 active:pb-14px' : '', " ").concat(color), onClick: onClick }, { children: _jsx("div", __assign({ id: 'confirm-button', className: "flex-wrap ".concat(spinning ? 'opacity-0' : '') }, { children: label })) })), _jsx("div", __assign({ className: "absolute top-0 h-full w-full flex flex-col justify-center items-center ".concat(spinning ? '' : 'hidden') }, { children: _jsx("div", __assign({ className: 'w-5 h-5' }, { children: _jsx(Spinner, { color: spinnerColor(color), spinning: spinning }) })) }))] }))); }; export var SecondaryButton = function (_a) { var label = _a.label, _b = _a.color, color = _b === void 0 ? 'bg-delete text-delete' : _b, onClick = _a.onClick; diff --git a/dist/framework/visualisation/react/ui/elements/spinner.d.ts b/dist/framework/visualisation/react/ui/elements/spinner.d.ts index 79402e33..7148f1b5 100644 --- a/dist/framework/visualisation/react/ui/elements/spinner.d.ts +++ b/dist/framework/visualisation/react/ui/elements/spinner.d.ts @@ -1,7 +1,6 @@ /// import { Weak } from '../../../../helpers'; import { PropsUISpinner } from '../../../../types/elements'; -import { ReactFactoryContext } from '../../factory'; -declare type Props = Weak & ReactFactoryContext; -export declare const Spinner: (props: Props) => JSX.Element; +declare type Props = Weak; +export declare const Spinner: ({ spinning, color }: Props) => JSX.Element; export {}; diff --git a/dist/framework/visualisation/react/ui/elements/spinner.js b/dist/framework/visualisation/react/ui/elements/spinner.js index 93d7e93f..f2aa8105 100644 --- a/dist/framework/visualisation/react/ui/elements/spinner.js +++ b/dist/framework/visualisation/react/ui/elements/spinner.js @@ -9,16 +9,17 @@ var __assign = (this && this.__assign) || function () { }; return __assign.apply(this, arguments); }; -import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; -import SpinnerSvg from '../../../../../assets/images/spinner.svg'; -import { Translator } from '../../../../translator'; -function prepareCopy(_a) { - var text = _a.text, locale = _a.locale; - return { - text: Translator.translate(text, locale) - }; -} -export var Spinner = function (props) { - var text = prepareCopy(props).text; - return (_jsxs("div", __assign({ id: 'spinner', className: 'flex flex-row items-center gap-4' }, { children: [_jsx("div", __assign({ className: 'font-body text-bodymedium text-grey1' }, { children: text })), _jsx("div", __assign({ className: 'w-10 h-10' }, { children: _jsx("img", { src: SpinnerSvg }) }))] }))); +import { jsx as _jsx } from "react/jsx-runtime"; +import Lottie from 'lottie-react'; +import spinnerLight from '../../../../../assets/lottie/spinner-light.json'; +import spinnerDark from '../../../../../assets/lottie/spinner-dark.json'; +export var Spinner = function (_a) { + var _b = _a.spinning, spinning = _b === void 0 ? true : _b, _c = _a.color, color = _c === void 0 ? 'light' : _c; + function animationData() { + if (color === 'dark') { + return spinnerDark; + } + return spinnerLight; + } + return (_jsx("div", __assign({ id: 'spinner', className: 'flex flex-row items-center gap-4' }, { children: _jsx("div", __assign({ className: 'w-5 h-5' }, { children: _jsx(Lottie, { animationData: animationData(), loop: spinning }) })) }))); }; diff --git a/dist/framework/visualisation/react/ui/elements/text.d.ts b/dist/framework/visualisation/react/ui/elements/text.d.ts index e3a3ad4b..ad7fea77 100644 --- a/dist/framework/visualisation/react/ui/elements/text.d.ts +++ b/dist/framework/visualisation/react/ui/elements/text.d.ts @@ -1,9 +1,10 @@ /// import { Weak } from '../../../../helpers'; -import { PropsUITextBodyLarge, PropsUITextBodyMedium, PropsUITextTitle0, PropsUITextTitle1, PropsUITextTitle2, PropsUITextTitle6 } from '../../../../types/elements'; +import { PropsUITextBodyLarge, PropsUITextBodyMedium, PropsUITextLabel, PropsUITextTitle0, PropsUITextTitle1, PropsUITextTitle2, PropsUITextTitle6 } from '../../../../types/elements'; export declare const BodyLarge: ({ text, color, margin }: Weak) => JSX.Element; export declare const BodyMedium: ({ text, color, margin }: Weak) => JSX.Element; export declare const Title0: ({ text, color, margin }: Weak) => JSX.Element; export declare const Title1: ({ text, color, margin }: Weak) => JSX.Element; export declare const Title2: ({ text, color, margin }: Weak) => JSX.Element; export declare const Title6: ({ text, color, margin }: Weak) => JSX.Element; +export declare const Label: ({ text, color, margin }: Weak) => JSX.Element; diff --git a/dist/framework/visualisation/react/ui/elements/text.js b/dist/framework/visualisation/react/ui/elements/text.js index 2d4f9fb1..59a9112c 100644 --- a/dist/framework/visualisation/react/ui/elements/text.js +++ b/dist/framework/visualisation/react/ui/elements/text.js @@ -34,3 +34,7 @@ export var Title6 = function (_a) { var text = _a.text, _b = _a.color, color = _b === void 0 ? 'text-grey1' : _b, _c = _a.margin, margin = _c === void 0 ? 'mb-2' : _c; return (_jsx("div", __assign({ className: "text-title6 font-title6 ".concat(margin, " ").concat(color) }, { children: text }))); }; +export var Label = function (_a) { + var text = _a.text, _b = _a.color, color = _b === void 0 ? 'text-grey1' : _b, _c = _a.margin, margin = _c === void 0 ? '' : _c; + return (_jsx("div", __assign({ className: "text-label font-label ".concat(color, " ").concat(margin) }, { children: text }))); +}; diff --git a/dist/framework/visualisation/react/ui/pages/donation_page.js b/dist/framework/visualisation/react/ui/pages/donation_page.js index c4f48362..95fa7a28 100644 --- a/dist/framework/visualisation/react/ui/pages/donation_page.js +++ b/dist/framework/visualisation/react/ui/pages/donation_page.js @@ -10,18 +10,15 @@ var __assign = (this && this.__assign) || function () { return __assign.apply(this, arguments); }; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; -import React from 'react'; import TextBundle from '../../../../text_bundle'; import { Translator } from '../../../../translator'; import { isPropsUIPromptConfirm, isPropsUIPromptConsentForm, isPropsUIPromptFileInput } from '../../../../types/prompts'; import { ForwardButton } from '../elements/button'; -import { Spinner } from '../elements/spinner'; import { Title0 } from '../elements/text'; import { Confirm } from '../prompts/confirm'; import { ConsentForm } from '../prompts/consent_form'; import { FileInput } from '../prompts/file_input'; export var DonationPage = function (props) { - var spinnerHidden = React.useState(true)[0]; var _a = prepareCopy(props), title = _a.title, forwardButton = _a.forwardButton; var resolve = props.resolve; function renderBody(props) { @@ -41,7 +38,7 @@ export var DonationPage = function (props) { function handleSkip() { resolve === null || resolve === void 0 ? void 0 : resolve({ __type__: 'PayloadFalse', value: false }); } - return (_jsxs(_Fragment, { children: [_jsx(Title0, { text: title }), renderBody(props), _jsx("div", __assign({ className: spinnerHidden ? 'hidden' : '' }, { children: _jsx(Spinner, __assign({}, props.spinner, { locale: props.locale })) })), _jsx("div", { className: 'mb-10' }), _jsxs("div", __assign({ className: 'flex flex-row gap-4 items-center w-full' }, { children: [_jsx("div", { className: 'flex-grow' }), _jsx(ForwardButton, { label: forwardButton, onClick: handleSkip })] }))] })); + return (_jsxs(_Fragment, { children: [_jsx(Title0, { text: title }), renderBody(props), _jsx("div", { className: 'mb-10' }), _jsxs("div", __assign({ className: 'flex flex-row gap-4 items-center w-full' }, { children: [_jsx("div", { className: 'flex-grow' }), _jsx(ForwardButton, { label: forwardButton, onClick: handleSkip })] }))] })); }; function prepareCopy(_a) { var title = _a.header.title, locale = _a.locale; diff --git a/dist/framework/visualisation/react/ui/pages/splash_screen.js b/dist/framework/visualisation/react/ui/pages/splash_screen.js index 474ee7fa..486d9e4b 100644 --- a/dist/framework/visualisation/react/ui/pages/splash_screen.js +++ b/dist/framework/visualisation/react/ui/pages/splash_screen.js @@ -9,28 +9,47 @@ var __assign = (this && this.__assign) || function () { }; return __assign.apply(this, arguments); }; -import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; +import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; +import React from 'react'; import TextBundle from '../../../../text_bundle'; import { Translator } from '../../../../translator'; -import { Spinner } from '../elements/spinner'; -import { BodyLarge, Title0 } from '../elements/text'; +import { PrimaryButton } from '../elements/button'; +import { CheckBox } from '../elements/check_box'; +import { BodyLarge, Label, Title0 } from '../elements/text'; function prepareCopy(_a) { var locale = _a.locale; return { title: Translator.translate(title, locale), - description: Translator.translate(description, locale) + description: Translator.translate(description, locale), + continueButton: Translator.translate(continueButton, locale), + privacyLabel: Translator.translate(privacyLabel, locale) }; } export var SplashScreen = function (props) { - var _a = prepareCopy(props), title = _a.title, description = _a.description; - return (_jsxs(_Fragment, { children: [_jsx(Title0, { text: title }), _jsx(BodyLarge, { text: description }), _jsx(Spinner, __assign({ text: spinnerText }, props))] })); + var _a = React.useState(false), checked = _a[0], setChecked = _a[1]; + var _b = React.useState(false), waiting = _b[0], setWaiting = _b[1]; + var _c = prepareCopy(props), title = _c.title, description = _c.description, continueButton = _c.continueButton, privacyLabel = _c.privacyLabel; + var resolve = props.resolve; + function handleContinue() { + if (checked && !waiting) { + setWaiting(true); + resolve === null || resolve === void 0 ? void 0 : resolve({ __type__: 'PayloadVoid', value: undefined }); + } + } + function handleCheck() { + setChecked(true); + } + return (_jsxs(_Fragment, { children: [_jsx(Title0, { text: title }), _jsx(BodyLarge, { text: description }), _jsxs("div", __assign({ className: 'flex flex-col gap-8' }, { children: [_jsxs("div", __assign({ className: 'flex flex-row gap-4 items-center' }, { children: [_jsx(CheckBox, { id: '0', selected: checked, onSelect: function () { return handleCheck(); } }), _jsx(Label, { text: privacyLabel })] })), _jsx("div", __assign({ className: "flex flex-row gap-4 ".concat(checked ? '' : 'opacity-30') }, { children: _jsx(PrimaryButton, { label: continueButton, onClick: handleContinue, enabled: checked, spinning: waiting }) }))] }))] })); }; var title = new TextBundle() .add('en', 'Welcome') .add('nl', 'Welkom'); var description = new TextBundle() - .add('en', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.') - .add('nl', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'); -var spinnerText = new TextBundle() - .add('en', 'One moment please..') - .add('nl', 'Een moment geduld..'); + .add('en', 'This way you can donate your data to the University of Amsterdam. The data we ask you to donate can be used to research… . We explain step by step what is expected of you. No data is saved or sent during these steps. The data is only saved when you are asked whether you want to send the data. Thank you in advance.') + .add('nl', 'U kunt zo uw gegevens gaan doneren aan de universiteit van Amsterdam. De gegevens die we u vragen te doneren kunnen worden gebruikt om te onderzoeken … . We leggen u stap voor stap uit wat er van u verwacht wordt. Tijdens deze stappen worden geen gegevens opgeslagen of verstuurd. Pas als u de vraag krijgt of u de gegevens wilt versturen, worden de gegevens opgeslagen. Alvast hartelijk dank.'); +var continueButton = new TextBundle() + .add('en', 'Continue') + .add('nl', 'Ga verder'); +var privacyLabel = new TextBundle() + .add('en', 'I have read and agree to the privacy conditions.') + .add('nl', 'Ik heb de privacy voorwaarden gelezen en ben hiermee akkoord.'); diff --git a/dist/py_script.js b/dist/py_script.js index 958ab11e..0ba4d0dc 100644 --- a/dist/py_script.js +++ b/dist/py_script.js @@ -1 +1 @@ -export var PyScript = "\nimport pandas as pd\nimport zipfile\n\ndef process():\n yield render_start_page()\n\n platforms = [\"Twitter\", \"Instagram\", \"Youtube\"]\n for index, platform in enumerate(platforms):\n meta_data = [] \n meta_data.append((\"debug\", f\"{platform}: start\"))\n\n data = None\n while True:\n meta_data.append((\"debug\", f\"{platform}: prompt file\"))\n promptFile = prompt_file(platform, \"application/zip, text/plain\")\n fileResult = yield render_donation_page(index+1, platform, promptFile)\n if fileResult.__type__ == 'PayloadString':\n meta_data.append((\"debug\", f\"{platform}: extracting file\"))\n extractionResult = doSomethingWithTheFile(platform, fileResult.value)\n if extractionResult != 'invalid': \n meta_data.append((\"debug\", f\"{platform}: extraction successful, go to consent form\")) \n data = extractionResult\n break\n else:\n meta_data.append((\"debug\", f\"{platform}: prompt confirmation to retry file selection\")) \n retry_result = yield render_donation_page(index+1, platform, retry_confirmation())\n if retry_result.__type__ == 'PayloadTrue':\n meta_data.append((\"debug\", f\"{platform}: skip due to invalid file\")) \n continue\n else: \n meta_data.append((\"debug\", f\"{platform}: retry prompt file\")) \n break\n else:\n meta_data.append((\"debug\", f\"{platform}: skip to next step\")) \n break\n\n if data is not None:\n meta_data.append((\"debug\", f\"{platform}: prompt consent\"))\n prompt = prompt_consent(platform, data, meta_data)\n consent_result = yield render_donation_page(index+1, platform, prompt)\n if consent_result.__type__ == \"PayloadJSON\":\n meta_data.append((\"debug\", f\"{platform}: donate consent data\"))\n yield donate(platform, consent_result.value)\n\n yield render_end_page()\n\n\ndef render_start_page():\n page = PropsUIPageStart()\n return CommandUIRender(page)\n\n\ndef render_end_page():\n header = PropsUIHeader(Translatable({\n \"en\": \"Thank you\",\n \"nl\": \"Dank je wel\"\n }))\n page = PropsUIPageEnd(header)\n return CommandUIRender(page)\n\n\ndef render_donation_page(index, platform, body):\n header = PropsUIHeader(Translatable({\n \"en\": f\"Step {index}: {platform}\",\n \"nl\": f\"Stap {index}: {platform}\"\n }))\n page = PropsUIPageDonation(header, body, spinner())\n return CommandUIRender(page)\n\n\ndef retry_confirmation():\n text = Translatable({\n \"en\": \"The selected file is invalid. Do you want to select a different file?\",\n \"nl\": \"Het geselecteerde bestaand is ongeldig. Wil je een ander bestand selecteren ?\"\n })\n ok = Translatable({\n \"en\": \"Different file\",\n \"nl\": \"Ander bestand\"\n })\n cancel = Translatable({\n \"en\": \"Cancel\",\n \"nl\": \"Annuleren\"\n })\n return PropsUIPromptConfirm(text, ok, cancel)\n\n\ndef spinner():\n return PropsUISpinner(Translatable({\n \"en\": \"One moment please\",\n \"nl\": \"Een moment geduld\"\n }))\n\n\ndef prompt_file(platform, extensions):\n title = Translatable({\n \"en\": f\"Select {platform} file\",\n \"nl\": f\"Selecteer {platform} bestand\"\n })\n\n description = Translatable({\n \"en\": \"Please select this file so we can extract relevant information for our research.\",\n \"nl\": \"Je kan deze file nu selecteren zodat wij er relevante informatie uit kunnen halen voor ons onderzoek.\"\n })\n\n return PropsUIPromptFileInput(title, description, extensions)\n\n\ndef doSomethingWithTheFile(platform, filename):\n return extract_zip_contents(filename)\n\n\ndef extract_zip_contents(filename):\n names = []\n try:\n file = zipfile.ZipFile(filename)\n data = []\n for name in file.namelist():\n names.append(name)\n info = file.getinfo(name)\n data.append((name, info.compress_size, info.file_size))\n return data\n except:\n return \"invalid\" \n\n\ndef prompt_consent(id, data, meta_data):\n title = Translatable({\n \"en\": \"Extracted data\",\n \"nl\": \"Gevonden gegevens\"\n })\n\n description = Translatable({\n \"en\": \"Please have a good look at the extracted data before giving consent to use this data.\",\n \"nl\": \"Bekijk de gegevens goed voordat je consent geeft om deze te gebruiken.\"\n })\n\n data_frame = pd.DataFrame(data, columns=[\"filename\", \"compressed size\", \"size\"])\n table = PropsUIPromptConsentFormTable(\"zip_content\", \"The zip contains the following files:\", data_frame)\n meta_frame = pd.DataFrame(meta_data, columns=[\"type\", \"message\"])\n meta_table = PropsUIPromptConsentFormTable(\"log_messages\", \"Log messages:\", meta_frame)\n return PropsUIPromptConsentForm(title, description, [table], [meta_table])\n\n\ndef donate(key, json_string):\n return CommandSystemDonate(key, json_string)\n"; +export var PyScript = "\nimport pandas as pd\nimport zipfile\n\ndef process():\n yield render_start_page()\n\n platforms = [\"Twitter\", \"Instagram\", \"Youtube\"]\n for index, platform in enumerate(platforms):\n meta_data = [] \n meta_data.append((\"debug\", f\"{platform}: start\"))\n\n data = None\n while True:\n meta_data.append((\"debug\", f\"{platform}: prompt file\"))\n promptFile = prompt_file(platform, \"application/zip, text/plain\")\n fileResult = yield render_donation_page(index+1, platform, promptFile)\n if fileResult.__type__ == 'PayloadString':\n meta_data.append((\"debug\", f\"{platform}: extracting file\"))\n extractionResult = doSomethingWithTheFile(platform, fileResult.value)\n if extractionResult != 'invalid': \n meta_data.append((\"debug\", f\"{platform}: extraction successful, go to consent form\")) \n data = extractionResult\n break\n else:\n meta_data.append((\"debug\", f\"{platform}: prompt confirmation to retry file selection\")) \n retry_result = yield render_donation_page(index+1, platform, retry_confirmation())\n if retry_result.__type__ == 'PayloadTrue':\n meta_data.append((\"debug\", f\"{platform}: skip due to invalid file\")) \n continue\n else: \n meta_data.append((\"debug\", f\"{platform}: retry prompt file\")) \n break\n else:\n meta_data.append((\"debug\", f\"{platform}: skip to next step\")) \n break\n\n if data is not None:\n meta_data.append((\"debug\", f\"{platform}: prompt consent\"))\n prompt = prompt_consent(platform, data, meta_data)\n consent_result = yield render_donation_page(index+1, platform, prompt)\n if consent_result.__type__ == \"PayloadJSON\":\n meta_data.append((\"debug\", f\"{platform}: donate consent data\"))\n yield donate(platform, consent_result.value)\n\n yield render_end_page()\n\n\ndef render_start_page():\n page = PropsUIPageStart()\n return CommandUIRender(page)\n\n\ndef render_end_page():\n header = PropsUIHeader(Translatable({\n \"en\": \"Thank you\",\n \"nl\": \"Dank je wel\"\n }))\n page = PropsUIPageEnd(header)\n return CommandUIRender(page)\n\n\ndef render_donation_page(index, platform, body):\n header = PropsUIHeader(Translatable({\n \"en\": f\"Step {index}: {platform}\",\n \"nl\": f\"Stap {index}: {platform}\"\n }))\n page = PropsUIPageDonation(header, body)\n return CommandUIRender(page)\n\n\ndef retry_confirmation():\n text = Translatable({\n \"en\": \"The selected file is invalid. Do you want to select a different file?\",\n \"nl\": \"Het geselecteerde bestaand is ongeldig. Wil je een ander bestand selecteren ?\"\n })\n ok = Translatable({\n \"en\": \"Different file\",\n \"nl\": \"Ander bestand\"\n })\n cancel = Translatable({\n \"en\": \"Cancel\",\n \"nl\": \"Annuleren\"\n })\n return PropsUIPromptConfirm(text, ok, cancel)\n\n\ndef prompt_file(platform, extensions):\n title = Translatable({\n \"en\": f\"Select {platform} file\",\n \"nl\": f\"Selecteer {platform} bestand\"\n })\n\n description = Translatable({\n \"en\": \"Please select this file so we can extract relevant information for our research.\",\n \"nl\": \"Je kan deze file nu selecteren zodat wij er relevante informatie uit kunnen halen voor ons onderzoek.\"\n })\n\n return PropsUIPromptFileInput(title, description, extensions)\n\n\ndef doSomethingWithTheFile(platform, filename):\n return extract_zip_contents(filename)\n\n\ndef extract_zip_contents(filename):\n names = []\n try:\n file = zipfile.ZipFile(filename)\n data = []\n for name in file.namelist():\n names.append(name)\n info = file.getinfo(name)\n data.append((name, info.compress_size, info.file_size))\n return data\n except:\n return \"invalid\" \n\n\ndef prompt_consent(id, data, meta_data):\n title = Translatable({\n \"en\": \"Extracted data\",\n \"nl\": \"Gevonden gegevens\"\n })\n\n description = Translatable({\n \"en\": \"Please have a good look at the extracted data before giving consent to use this data.\",\n \"nl\": \"Bekijk de gegevens goed voordat je consent geeft om deze te gebruiken.\"\n })\n\n data_frame = pd.DataFrame(data, columns=[\"filename\", \"compressed size\", \"size\"])\n table = PropsUIPromptConsentFormTable(\"zip_content\", \"The zip contains the following files:\", data_frame)\n meta_frame = pd.DataFrame(meta_data, columns=[\"type\", \"message\"])\n meta_table = PropsUIPromptConsentFormTable(\"log_messages\", \"Log messages:\", meta_frame)\n return PropsUIPromptConsentForm(title, description, [table], [meta_table])\n\n\ndef donate(key, json_string):\n return CommandSystemDonate(key, json_string)\n"; diff --git a/dist/styles.css b/dist/styles.css index 00acc0cc..fc21cbcb 100644 --- a/dist/styles.css +++ b/dist/styles.css @@ -1 +1 @@ -/*! tailwindcss v3.1.8 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::-webkit-backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.m-6{margin:1.5rem}.mr-2{margin-right:.5rem}.-mt-2px{margin-top:-2px}.ml-2{margin-left:.5rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mb-6{margin-bottom:1.5rem}.mb-2{margin-bottom:.5rem}.mb-10{margin-bottom:2.5rem}.mb-4{margin-bottom:1rem}.mt-8{margin-top:2rem}.mt-4{margin-top:1rem}.mt-10{margin-top:2.5rem}.flex{display:flex}.table{display:table}.hidden{display:none}.h-full{height:100%}.h-48px{height:48px}.h-10{height:2.5rem}.w-full{width:100%}.w-10{width:2.5rem}.w-8{width:2rem}.max-w-sheet{max-width:760px}.flex-shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;user-select:none}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.rounded{border-radius:.25rem}.border-2{border-width:2px}.border-solid{border-style:solid}.border-grey3{--tw-border-opacity:1;border-color:rgb(204 204 204/var(--tw-border-opacity))}.bg-primary{--tw-bg-opacity:1;background-color:rgb(66 114 239/var(--tw-bg-opacity))}.bg-delete{--tw-bg-opacity:1;background-color:rgb(219 30 30/var(--tw-bg-opacity))}.bg-success{--tw-bg-opacity:1;background-color:rgb(111 202 55/var(--tw-bg-opacity))}.bg-tertiary{--tw-bg-opacity:1;background-color:rgb(255 207 96/var(--tw-bg-opacity))}.bg-opacity-0{--tw-bg-opacity:0}.px-2{padding-left:.5rem;padding-right:.5rem}.pt-15px{padding-top:15px}.pb-15px{padding-bottom:15px}.pr-4{padding-right:1rem}.pl-4{padding-left:1rem}.pt-13px{padding-top:13px}.pb-13px{padding-bottom:13px}.pt-1{padding-top:.25rem}.pb-1{padding-bottom:.25rem}.pl-3{padding-left:.75rem}.pr-3{padding-right:.75rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.font-button,.font-label{font-family:Finador-Bold,sans-serif}.font-body{font-family:Finador-Light,sans-serif}.font-title3,.font-title4{font-family:Finador-Black,sans-serif}.font-title5,.font-title6{font-family:Finador-Bold,sans-serif}.font-subhead{font-family:Finador-Medium,sans-serif}.text-button{font-size:18px;line-height:18px}.text-label{font-size:16px;line-height:16px}.text-bodymedium{font-size:20px;line-height:30px}.text-bodylarge{font-size:24px;line-height:36px}.text-title4{font-size:28px;line-height:32px}.text-title3{font-size:32px;line-height:38px}.text-title6{font-size:20px;line-height:22px}.text-title5{font-size:24px;line-height:26px}.text-subhead{font-size:20px;line-height:20px}.leading-none{line-height:1}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-delete{--tw-text-opacity:1;color:rgb(219 30 30/var(--tw-text-opacity))}.text-grey1{--tw-text-opacity:1;color:rgb(34 34 34/var(--tw-text-opacity))}.filter{-webkit-filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.hover\:bg-grey5:hover{--tw-bg-opacity:1;background-color:rgb(246 246 246/var(--tw-bg-opacity))}.focus\:border-primary:focus{--tw-border-opacity:1;border-color:rgb(66 114 239/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.active\:pt-4:active{padding-top:1rem}.active\:pb-14px:active{padding-bottom:14px}.active\:pt-14px:active{padding-top:14px}.active\:pb-3:active{padding-bottom:.75rem}.active\:pt-5px:active{padding-top:5px}.active\:pb-3px:active{padding-bottom:3px}.active\:shadow-top4px:active{--tw-shadow:inset 0 4px 0 0 rgba(0,0,0,.15);--tw-shadow-colored:inset 0 4px 0 0 var(--tw-shadow-color)}.active\:shadow-top2px:active,.active\:shadow-top4px:active{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.active\:shadow-top2px:active{--tw-shadow:inset 0 2px 0 0 rgba(0,0,0,.15);--tw-shadow-colored:inset 0 2px 0 0 var(--tw-shadow-color)}@media (min-width:640px){.sm\:font-title2,.sm\:font-title3,.sm\:font-title4{font-family:Finador-Black,sans-serif}.sm\:text-title2{font-size:40px;line-height:44px}.sm\:text-title3{font-size:32px;line-height:38px}.sm\:text-title4{font-size:28px;line-height:32px}}@media (min-width:768px){.md\:mb-8{margin-bottom:2rem}}@media (min-width:1024px){.lg\:m-14{margin:3.5rem}.lg\:mb-10{margin-bottom:2.5rem}.lg\:font-title0{font-family:Finador-Black,sans-serif}.lg\:font-title1{font-family:Arial,sans-serif}.lg\:font-title2,.lg\:font-title3{font-family:Finador-Black,sans-serif}.lg\:text-title0{font-size:64px;line-height:68px}.lg\:text-title1{font-size:50px;line-height:50px}.lg\:text-title2{font-size:40px;line-height:44px}.lg\:text-title3{font-size:32px;line-height:38px}} \ No newline at end of file +/*! tailwindcss v3.1.8 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::-webkit-backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.absolute{position:absolute}.relative{position:relative}.top-0{top:0}.m-6{margin:1.5rem}.mr-2{margin-right:.5rem}.-mt-2px{margin-top:-2px}.ml-2{margin-left:.5rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mb-6{margin-bottom:1.5rem}.mb-2{margin-bottom:.5rem}.mb-10{margin-bottom:2.5rem}.mb-4{margin-bottom:1rem}.mt-8{margin-top:2rem}.mt-4{margin-top:1rem}.mt-10{margin-top:2.5rem}.flex{display:flex}.table{display:table}.hidden{display:none}.h-full{height:100%}.h-5{height:1.25rem}.h-48px{height:48px}.w-full{width:100%}.w-5{width:1.25rem}.w-8{width:2rem}.max-w-sheet{max-width:760px}.flex-shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;user-select:none}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.justify-center{justify-content:center}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-8{gap:2rem}.rounded{border-radius:.25rem}.border-2{border-width:2px}.border-solid{border-style:solid}.border-grey3{--tw-border-opacity:1;border-color:rgb(204 204 204/var(--tw-border-opacity))}.bg-tertiary{--tw-bg-opacity:1;background-color:rgb(255 207 96/var(--tw-bg-opacity))}.bg-primary{--tw-bg-opacity:1;background-color:rgb(66 114 239/var(--tw-bg-opacity))}.bg-delete{--tw-bg-opacity:1;background-color:rgb(219 30 30/var(--tw-bg-opacity))}.bg-success{--tw-bg-opacity:1;background-color:rgb(111 202 55/var(--tw-bg-opacity))}.bg-opacity-0{--tw-bg-opacity:0}.px-2{padding-left:.5rem;padding-right:.5rem}.pt-15px{padding-top:15px}.pb-15px{padding-bottom:15px}.pr-4{padding-right:1rem}.pl-4{padding-left:1rem}.pt-13px{padding-top:13px}.pb-13px{padding-bottom:13px}.pt-1{padding-top:.25rem}.pb-1{padding-bottom:.25rem}.pl-3{padding-left:.75rem}.pr-3{padding-right:.75rem}.pt-3{padding-top:.75rem}.text-left{text-align:left}.font-button,.font-label{font-family:Finador-Bold,sans-serif}.font-body{font-family:Finador-Light,sans-serif}.font-title3,.font-title4{font-family:Finador-Black,sans-serif}.font-title5,.font-title6{font-family:Finador-Bold,sans-serif}.font-subhead{font-family:Finador-Medium,sans-serif}.text-button{font-size:18px;line-height:18px}.text-label{font-size:16px;line-height:16px}.text-bodymedium{font-size:20px;line-height:30px}.text-bodylarge{font-size:24px;line-height:36px}.text-title4{font-size:28px;line-height:32px}.text-title3{font-size:32px;line-height:38px}.text-title6{font-size:20px;line-height:22px}.text-title5{font-size:24px;line-height:26px}.text-subhead{font-size:20px;line-height:20px}.leading-none{line-height:1}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-delete{--tw-text-opacity:1;color:rgb(219 30 30/var(--tw-text-opacity))}.text-grey1{--tw-text-opacity:1;color:rgb(34 34 34/var(--tw-text-opacity))}.opacity-0{opacity:0}.opacity-30{opacity:.3}.filter{-webkit-filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.hover\:bg-grey5:hover{--tw-bg-opacity:1;background-color:rgb(246 246 246/var(--tw-bg-opacity))}.focus\:border-primary:focus{--tw-border-opacity:1;border-color:rgb(66 114 239/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.active\:pt-4:active{padding-top:1rem}.active\:pb-14px:active{padding-bottom:14px}.active\:pt-14px:active{padding-top:14px}.active\:pb-3:active{padding-bottom:.75rem}.active\:pt-5px:active{padding-top:5px}.active\:pb-3px:active{padding-bottom:3px}.active\:shadow-top4px:active{--tw-shadow:inset 0 4px 0 0 rgba(0,0,0,.15);--tw-shadow-colored:inset 0 4px 0 0 var(--tw-shadow-color)}.active\:shadow-top2px:active,.active\:shadow-top4px:active{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.active\:shadow-top2px:active{--tw-shadow:inset 0 2px 0 0 rgba(0,0,0,.15);--tw-shadow-colored:inset 0 2px 0 0 var(--tw-shadow-color)}@media (min-width:640px){.sm\:font-title2,.sm\:font-title3,.sm\:font-title4{font-family:Finador-Black,sans-serif}.sm\:text-title2{font-size:40px;line-height:44px}.sm\:text-title3{font-size:32px;line-height:38px}.sm\:text-title4{font-size:28px;line-height:32px}}@media (min-width:768px){.md\:mb-8{margin-bottom:2rem}}@media (min-width:1024px){.lg\:m-14{margin:3.5rem}.lg\:mb-10{margin-bottom:2.5rem}.lg\:font-title0{font-family:Finador-Black,sans-serif}.lg\:font-title1{font-family:Arial,sans-serif}.lg\:font-title2,.lg\:font-title3{font-family:Finador-Black,sans-serif}.lg\:text-title0{font-size:64px;line-height:68px}.lg\:text-title1{font-size:50px;line-height:50px}.lg\:text-title2{font-size:40px;line-height:44px}.lg\:text-title3{font-size:32px;line-height:38px}} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index f894334d..e018023c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@types/react": "^18.0.21", "@types/react-dom": "^18.0.6", "lodash": "^4.17.21", + "lottie-react": "^2.3.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", @@ -10056,6 +10057,23 @@ "loose-envify": "cli.js" } }, + "node_modules/lottie-react": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/lottie-react/-/lottie-react-2.3.1.tgz", + "integrity": "sha512-8cxd6XZZtECT6LoAhCftRdYrEpHxiouvB5EPiYA+TtCG5LHNYAdMS9IVIHcxKtWnpo7x16QfCLj1XLXZpaN81A==", + "dependencies": { + "lottie-web": "^5.9.4" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/lottie-web": { + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.9.6.tgz", + "integrity": "sha512-JFs7KsHwflugH5qIXBpB4905yC1Sub2MZWtl/elvO/QC6qj1ApqbUZJyjzJseJUtVpgiDaXQLjBlIJGS7UUUXA==" + }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -23576,6 +23594,19 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "lottie-react": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/lottie-react/-/lottie-react-2.3.1.tgz", + "integrity": "sha512-8cxd6XZZtECT6LoAhCftRdYrEpHxiouvB5EPiYA+TtCG5LHNYAdMS9IVIHcxKtWnpo7x16QfCLj1XLXZpaN81A==", + "requires": { + "lottie-web": "^5.9.4" + } + }, + "lottie-web": { + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.9.6.tgz", + "integrity": "sha512-JFs7KsHwflugH5qIXBpB4905yC1Sub2MZWtl/elvO/QC6qj1ApqbUZJyjzJseJUtVpgiDaXQLjBlIJGS7UUUXA==" + }, "lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", diff --git a/package.json b/package.json index 4d1710d4..a4285843 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@types/react": "^18.0.21", "@types/react-dom": "^18.0.6", "lodash": "^4.17.21", + "lottie-react": "^2.3.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", diff --git a/src/assets/lottie/spinner-dark.json b/src/assets/lottie/spinner-dark.json new file mode 100644 index 00000000..d147f861 --- /dev/null +++ b/src/assets/lottie/spinner-dark.json @@ -0,0 +1 @@ +{"v":"5.7.5","fr":30,"ip":0,"op":50,"w":20,"h":20,"nm":"Loading spinner BLUE","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[10,10,0],"ix":2,"l":2},"a":{"a":0,"k":[3.178,3.178,0],"ix":1,"l":2},"s":{"a":0,"k":[36.9132,36.9132,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[45.356,45.356],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.13333333333333333,0.13333333333333333,0.13333333333333333,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3.178,3.178],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.335],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[0]},{"t":50,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.17],"y":[1]},"o":{"x":[0.362],"y":[0.158]},"t":0,"s":[0.1]},{"t":40,"s":[100]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.166],"y":[0.61]},"o":{"x":[0.75],"y":[0.35]},"t":0,"s":[0]},{"t":50,"s":[360]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/assets/lottie/spinner-light.json b/src/assets/lottie/spinner-light.json new file mode 100644 index 00000000..0f515a19 --- /dev/null +++ b/src/assets/lottie/spinner-light.json @@ -0,0 +1 @@ +{"v":"5.7.5","fr":30,"ip":0,"op":50,"w":20,"h":20,"nm":"Loading spinner BLUE","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[10,10,0],"ix":2,"l":2},"a":{"a":0,"k":[3.178,3.178,0],"ix":1,"l":2},"s":{"a":0,"k":[36.9132,36.9132,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[45.356,45.356],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3.178,3.178],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.335],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[0]},{"t":50,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.17],"y":[1]},"o":{"x":[0.362],"y":[0.158]},"t":0,"s":[0.1]},{"t":40,"s":[100]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.166],"y":[0.61]},"o":{"x":[0.75],"y":[0.35]},"t":0,"s":[0]},{"t":50,"s":[360]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/assets/lottie/spinner-primary.json b/src/assets/lottie/spinner-primary.json new file mode 100644 index 00000000..dea3d01e --- /dev/null +++ b/src/assets/lottie/spinner-primary.json @@ -0,0 +1 @@ +{"v":"5.7.5","fr":30,"ip":0,"op":50,"w":20,"h":20,"nm":"Loading spinner BLUE","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[10,10,0],"ix":2,"l":2},"a":{"a":0,"k":[3.178,3.178,0],"ix":1,"l":2},"s":{"a":0,"k":[36.9132,36.9132,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[45.356,45.356],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.25882352941176473,0.4470588235294118,0.9372549019607843,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":7,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[3.178,3.178],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.335],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":15,"s":[0]},{"t":50,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.17],"y":[1]},"o":{"x":[0.362],"y":[0.158]},"t":0,"s":[0.1]},{"t":40,"s":[100]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.166],"y":[0.61]},"o":{"x":[0.75],"y":[0.35]},"t":0,"s":[0]},{"t":50,"s":[360]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":300,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/src/framework/processing/python/worker.js b/src/framework/processing/python/worker.js index fd6ba19b..10ed5149 100755 --- a/src/framework/processing/python/worker.js +++ b/src/framework/processing/python/worker.js @@ -142,17 +142,6 @@ class PropsUIPromptConfirm: return dict -class PropsUISpinner: - __slots__ = "text" - def __init__(self, text): - self.text = text - def toDict(self): - dict = {} - dict["__type__"] = "PropsUISpinner" - dict["text"] = self.text.toDict() - return dict - - class PropsUIPromptConsentForm: __slots__ = "title", "description", "tables", "meta_tables" def __init__(self, title, description, tables, meta_tables): @@ -226,17 +215,15 @@ class PropsUIPromptRadioInput: class PropsUIPageDonation: - __slots__ = "header", "body", "spinner" - def __init__(self, header, body, spinner): + __slots__ = "header", "body" + def __init__(self, header, body): self.header = header self.body = body - self.spinner = spinner def toDict(self): dict = {} dict["__type__"] = "PropsUIPageDonation" dict["header"] = self.header.toDict() dict["body"] = self.body.toDict() - dict["spinner"] = self.spinner.toDict() return dict diff --git a/src/framework/processing/worker_engine.ts b/src/framework/processing/worker_engine.ts index df16c528..1c7dd582 100755 --- a/src/framework/processing/worker_engine.ts +++ b/src/framework/processing/worker_engine.ts @@ -1,11 +1,13 @@ import { CommandHandler, ProcessingEngine } from '../types/modules' -import { isCommand, Response, Script } from '../types/commands' +import { CommandUIRender, isCommand, Response, Script } from '../types/commands' export default class WorkerProcessingEngine implements ProcessingEngine { worker: Worker commandHandler: CommandHandler script!: Script + resolveInitialized!: () => void + resolveContinue!: () => void constructor (worker: Worker, commandHandler: CommandHandler) { this.commandHandler = commandHandler @@ -31,7 +33,7 @@ export default class WorkerProcessingEngine implements ProcessingEngine { case 'loadScriptDone': console.log('[ReactEngine] Received: loadScriptDone') - this.firstRunCycle() + this.resolveInitialized() break case 'runCycleDone': @@ -49,7 +51,40 @@ export default class WorkerProcessingEngine implements ProcessingEngine { start (script: Script): void { console.log('[WorkerProcessingEngine] started') this.script = script - this.worker.postMessage({ eventType: 'initialise' }) + + const waitForInitialization: Promise = this.waitForInitialization() + const waitForSplashScreen: Promise = this.waitForSplashScreen() + + Promise.all([waitForInitialization, waitForSplashScreen]).then( + () => { this.firstRunCycle() }, + () => {} + ) + } + + async waitForInitialization (): Promise { + return await new Promise((resolve) => { + this.resolveInitialized = resolve + this.worker.postMessage({ eventType: 'initialise' }) + }) + } + + async waitForSplashScreen (): Promise { + return await new Promise((resolve) => { + this.resolveContinue = resolve + this.renderSplashScreen() + }) + } + + renderSplashScreen (): void { + const command: CommandUIRender = { __type__: 'CommandUIRender', page: { __type__: 'PropsUIPageSplashScreen' } } + if (isCommand(command)) { + this.commandHandler.onCommand(command).then( + (_response) => this.resolveContinue(), + () => {} + ) + } else { + console.log('HUH?!') + } } loadScript (script: any): void { diff --git a/src/framework/types/elements.ts b/src/framework/types/elements.ts index a0c69434..92cb4d24 100644 --- a/src/framework/types/elements.ts +++ b/src/framework/types/elements.ts @@ -20,7 +20,8 @@ export type PropsUIText = PropsUITextTitle1 | PropsUITextTitle2 | PropsUITextTitle6 | - PropsUITextBodyLarge + PropsUITextBodyLarge | + PropsUITextLabel export type PropsUIButton = PropsUIButtonPrimary | @@ -47,7 +48,18 @@ export function isPropsUIText (arg: any): arg is PropsUIText { isPropsUITextTitle0(arg) || isPropsUITextTitle0(arg) || isPropsUITextBodyLarge(arg) || - isPropsUITextBodyMedium(arg) + isPropsUITextBodyMedium(arg) || + isPropsUITextLabel(arg) +} + +export interface PropsUITextLabel { + __type__: 'PropsUITextLabel' + text: string + color?: string + margin?: string +} +export function isPropsUITextLabel (arg: any): arg is PropsUITextLabel { + return isInstanceOf(arg, 'PropsUITextLabel', ['text', 'color', 'margin']) } export interface PropsUITextBodyLarge { @@ -123,6 +135,8 @@ export interface PropsUIButtonPrimary { __type__: 'PropsUIButtonPrimary' label: string color?: string + enabled?: boolean + spinning?: boolean onClick: () => void } export function isPropsUIButtonPrimary (arg: any): arg is PropsUIButtonPrimary { @@ -194,10 +208,11 @@ export function isPropsUICheckBox (arg: any): arg is PropsUICheckBox { export interface PropsUISpinner { __type__: 'PropsUISpinner' - text: Text + spinning?: boolean + color?: string } export function isPropsUISpinner (arg: any): arg is PropsUISpinner { - return isInstanceOf(arg, 'PropsUISpinner', ['text']) + return isInstanceOf(arg, 'PropsUISpinner', ['color', 'spinning']) } // Header diff --git a/src/framework/types/pages.ts b/src/framework/types/pages.ts index 621fcf20..d22efed0 100644 --- a/src/framework/types/pages.ts +++ b/src/framework/types/pages.ts @@ -1,5 +1,5 @@ import { isInstanceOf } from '../helpers' -import { PropsUIHeader, PropsUISpinner } from './elements' +import { PropsUIHeader } from './elements' import { PropsUIPromptFileInput, PropsUIPromptConfirm, PropsUIPromptConsentForm } from './prompts' export type PropsUIPage = @@ -35,7 +35,6 @@ export interface PropsUIPageDonation { __type__: 'PropsUIPageDonation' header: PropsUIHeader body: PropsUIPromptFileInput | PropsUIPromptConfirm | PropsUIPromptConsentForm - spinner: PropsUISpinner } export function isPropsUIPageDonation (arg: any): arg is PropsUIPageDonation { return isInstanceOf(arg, 'PropsUIPageDonation', ['header', 'body']) diff --git a/src/framework/visualisation/react/engine.tsx b/src/framework/visualisation/react/engine.tsx index ef08551c..2d00d631 100644 --- a/src/framework/visualisation/react/engine.tsx +++ b/src/framework/visualisation/react/engine.tsx @@ -19,7 +19,6 @@ export default class ReactEngine implements VisualisationEngine { console.log('[ReactEngine] started') this.root = ReactDOM.createRoot(rootElement) this.locale = locale - this.renderSplashScreen() } async render (command: CommandUIRender): Promise { @@ -33,12 +32,6 @@ export default class ReactEngine implements VisualisationEngine { }) } - renderSplashScreen (): void { - const context = { locale: this.locale, resolve: () => {} } - const page = this.factory.createPage({ __type__: 'PropsUIPageSplashScreen' }, context) - this.renderElements([page]) - } - async renderPage (props: PropsUIPage): Promise { console.log('[ReactEngine] render page: ' + JSON.stringify(props)) return await new Promise((resolve) => { diff --git a/src/framework/visualisation/react/ui/elements/button.tsx b/src/framework/visualisation/react/ui/elements/button.tsx index 2d641288..c6972489 100644 --- a/src/framework/visualisation/react/ui/elements/button.tsx +++ b/src/framework/visualisation/react/ui/elements/button.tsx @@ -3,12 +3,27 @@ import { PropsUIButtonBack, PropsUIButtonForward, PropsUIButtonLabel, PropsUIBut import BackSvg from '../../../../../assets/images/back.svg' import ForwardSvg from '../../../../../assets/images/forward.svg' +import { Spinner } from './spinner' -export const PrimaryButton = ({ label, color = 'bg-primary text-white', onClick }: Weak): JSX.Element => { +function spinnerColor (buttonColor: string): string { + if (buttonColor.includes('bg-tertiary')) { + return 'dark' + } + return 'light' +} + +export const PrimaryButton = ({ label, spinning = false, enabled = true, color = 'bg-primary text-white', onClick }: Weak): JSX.Element => { return ( -
-
- {label} +
+
+
+ {label} +
+
+
+
+ +
) diff --git a/src/framework/visualisation/react/ui/elements/spinner.tsx b/src/framework/visualisation/react/ui/elements/spinner.tsx index 2ca1f751..26fbfcfe 100644 --- a/src/framework/visualisation/react/ui/elements/spinner.tsx +++ b/src/framework/visualisation/react/ui/elements/spinner.tsx @@ -1,29 +1,25 @@ -import SpinnerSvg from '../../../../../assets/images/spinner.svg' import { Weak } from '../../../../helpers' -import { Translator } from '../../../../translator' import { PropsUISpinner } from '../../../../types/elements' -import { ReactFactoryContext } from '../../factory' -interface Copy { - text: string -} +import React from 'react' +import Lottie from 'lottie-react' +import spinnerLight from '../../../../../assets/lottie/spinner-light.json' +import spinnerDark from '../../../../../assets/lottie/spinner-dark.json' -function prepareCopy ({ text, locale }: Props): Copy { - return { - text: Translator.translate(text, locale) - } -} +type Props = Weak -type Props = Weak & ReactFactoryContext - -export const Spinner = (props: Props): JSX.Element => { - const { text } = prepareCopy(props) +export const Spinner = ({ spinning = true, color = 'light' }: Props): JSX.Element => { + function animationData (): unknown { + if (color === 'dark') { + return spinnerDark + } + return spinnerLight + } return (
-
{text}
-
- +
+
) diff --git a/src/framework/visualisation/react/ui/elements/text.tsx b/src/framework/visualisation/react/ui/elements/text.tsx index 6a8fb504..80d758fa 100644 --- a/src/framework/visualisation/react/ui/elements/text.tsx +++ b/src/framework/visualisation/react/ui/elements/text.tsx @@ -1,5 +1,5 @@ import { Weak } from '../../../../helpers' -import { PropsUITextBodyLarge, PropsUITextBodyMedium, PropsUITextTitle0, PropsUITextTitle1, PropsUITextTitle2, PropsUITextTitle6 } from '../../../../types/elements' +import { PropsUITextBodyLarge, PropsUITextBodyMedium, PropsUITextLabel, PropsUITextTitle0, PropsUITextTitle1, PropsUITextTitle2, PropsUITextTitle6 } from '../../../../types/elements' export const BodyLarge = ({ text, color = 'text-grey1', margin = 'mb-6 md:mb-8 lg:mb-10' }: Weak): JSX.Element => { return ( @@ -48,3 +48,11 @@ export const Title6 = ({ text, color = 'text-grey1', margin = 'mb-2' }: Weak ) } + +export const Label = ({ text, color = 'text-grey1', margin = '' }: Weak): JSX.Element => { + return ( +
+ {text} +
+ ) +} diff --git a/src/framework/visualisation/react/ui/pages/donation_page.tsx b/src/framework/visualisation/react/ui/pages/donation_page.tsx index 8d253940..08cf199e 100644 --- a/src/framework/visualisation/react/ui/pages/donation_page.tsx +++ b/src/framework/visualisation/react/ui/pages/donation_page.tsx @@ -7,7 +7,6 @@ import { PropsUIPageDonation } from '../../../../types/pages' import { isPropsUIPromptConfirm, isPropsUIPromptConsentForm, isPropsUIPromptFileInput } from '../../../../types/prompts' import { ReactFactoryContext } from '../../factory' import { ForwardButton } from '../elements/button' -import { Spinner } from '../elements/spinner' import { Title0 } from '../elements/text' import { Confirm } from '../prompts/confirm' import { ConsentForm } from '../prompts/consent_form' @@ -16,7 +15,6 @@ import { FileInput } from '../prompts/file_input' type Props = Weak & ReactFactoryContext export const DonationPage = (props: Props): JSX.Element => { - const [spinnerHidden] = React.useState(true) const { title, forwardButton } = prepareCopy(props) const { resolve } = props @@ -43,9 +41,6 @@ export const DonationPage = (props: Props): JSX.Element => { <> {renderBody(props)} -
- -
diff --git a/src/framework/visualisation/react/ui/pages/splash_screen.tsx b/src/framework/visualisation/react/ui/pages/splash_screen.tsx index 9444841d..3cf9e126 100644 --- a/src/framework/visualisation/react/ui/pages/splash_screen.tsx +++ b/src/framework/visualisation/react/ui/pages/splash_screen.tsx @@ -1,14 +1,18 @@ +import React from 'react' import { Weak } from '../../../../helpers' import TextBundle from '../../../../text_bundle' import { Translator } from '../../../../translator' import { PropsUIPageSplashScreen } from '../../../../types/pages' import { ReactFactoryContext } from '../../factory' -import { Spinner } from '../elements/spinner' -import { BodyLarge, Title0 } from '../elements/text' +import { PrimaryButton } from '../elements/button' +import { CheckBox } from '../elements/check_box' +import { BodyLarge, Label, Title0 } from '../elements/text' interface Copy { title: string description: string + continueButton: string + privacyLabel: string } type Props = Weak & ReactFactoryContext @@ -16,29 +20,58 @@ type Props = Weak & ReactFactoryContext function prepareCopy ({ locale }: Props): Copy { return { title: Translator.translate(title, locale), - description: Translator.translate(description, locale) + description: Translator.translate(description, locale), + continueButton: Translator.translate(continueButton, locale), + privacyLabel: Translator.translate(privacyLabel, locale) } } export const SplashScreen = (props: Props): JSX.Element => { - const { title, description } = prepareCopy(props) + const [checked, setChecked] = React.useState(false) + const [waiting, setWaiting] = React.useState(false) + const { title, description, continueButton, privacyLabel } = prepareCopy(props) + const { resolve } = props + + function handleContinue (): void { + if (checked && !waiting) { + setWaiting(true) + resolve?.({ __type__: 'PayloadVoid', value: undefined }) + } + } + + function handleCheck (): void { + setChecked(true) + } return ( <> - +
+
+ handleCheck()} /> +
+
+ +
+
) } + const title = new TextBundle() .add('en', 'Welcome') .add('nl', 'Welkom') const description = new TextBundle() - .add('en', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.') - .add('nl', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.') + .add('en', 'This way you can donate your data to the University of Amsterdam. The data we ask you to donate can be used to research… . We explain step by step what is expected of you. No data is saved or sent during these steps. The data is only saved when you are asked whether you want to send the data. Thank you in advance.') + .add('nl', 'U kunt zo uw gegevens gaan doneren aan de universiteit van Amsterdam. De gegevens die we u vragen te doneren kunnen worden gebruikt om te onderzoeken … . We leggen u stap voor stap uit wat er van u verwacht wordt. Tijdens deze stappen worden geen gegevens opgeslagen of verstuurd. Pas als u de vraag krijgt of u de gegevens wilt versturen, worden de gegevens opgeslagen. Alvast hartelijk dank.') + +const continueButton = new TextBundle() + .add('en', 'Continue') + .add('nl', 'Ga verder') -const spinnerText = new TextBundle() - .add('en', 'One moment please..') - .add('nl', 'Een moment geduld..') +const privacyLabel = new TextBundle() + .add('en', 'I have read and agree to the privacy conditions.') + .add('nl', 'Ik heb de privacy voorwaarden gelezen en ben hiermee akkoord.') diff --git a/src/py_script.ts b/src/py_script.ts index 6f8fbd17..89ecee73 100644 --- a/src/py_script.ts +++ b/src/py_script.ts @@ -65,7 +65,7 @@ def render_donation_page(index, platform, body): "en": f"Step {index}: {platform}", "nl": f"Stap {index}: {platform}" })) - page = PropsUIPageDonation(header, body, spinner()) + page = PropsUIPageDonation(header, body) return CommandUIRender(page) @@ -85,13 +85,6 @@ def retry_confirmation(): return PropsUIPromptConfirm(text, ok, cancel) -def spinner(): - return PropsUISpinner(Translatable({ - "en": "One moment please", - "nl": "Een moment geduld" - })) - - def prompt_file(platform, extensions): title = Translatable({ "en": f"Select {platform} file",