commit 3d1ac28d49ea14fa2f2a4ddf65455d9bafbce6d5
parent 46678a28e1fecb7e14c7799f3b516b9585e372f7
Author: triesap <137732411+triesap@users.noreply.github.com>
Date: Sat, 26 Oct 2024 19:17:08 +0000
Edit `models/trade-product/add` update entry components, add rendering logic, add styles. Add superellipse css/js. Add styles. Add client file system module.
Diffstat:
15 files changed, 306 insertions(+), 220 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -3433,6 +3433,7 @@ dependencies = [
"tauri",
"tauri-build",
"tauri-plugin-dialog",
+ "tauri-plugin-fs",
"tauri-plugin-geolocation",
"tauri-plugin-http",
"tauri-plugin-map-display",
diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml
@@ -23,6 +23,7 @@ serde_json = "1.0"
sqlx = { version = "0.8.2", features = ["sqlite", "runtime-tokio"] }
tauri = { version = "2.0.0", features = ["protocol-asset"] }
tauri-plugin-dialog = "2.0.0"
+tauri-plugin-fs = "2.0.0"
tauri-plugin-geolocation = "2.0.0"
tauri-plugin-http = "2.0.0"
tauri-plugin-map-display = { git = "https://github.com/inkibra/tauri-plugins", tag = "@inkibra/tauri-plugin-map-display@0.2.0", package="tauri-plugin-map-display" }
diff --git a/crates/tauri/Info.ios.plist b/crates/tauri/Info.ios.plist
@@ -13,5 +13,16 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
+ <key>NSPrivacyAccessedAPITypes</key>
+ <array>
+ <dict>
+ <key>NSPrivacyAccessedAPIType</key>
+ <string>NSPrivacyAccessedAPICategoryFileTimestamp</string>
+ <key>NSPrivacyAccessedAPITypeReasons</key>
+ <array>
+ <string>C617.1</string>
+ </array>
+ </dict>
+ </array>
</dict>
</plist>
\ No newline at end of file
diff --git a/crates/tauri/src/lib.rs b/crates/tauri/src/lib.rs
@@ -44,6 +44,7 @@ pub fn run() {
})
})
.plugin(tauri_plugin_dialog::init())
+ .plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_geolocation::init())
.plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_map_display::init())
diff --git a/package.json b/package.json
@@ -48,6 +48,7 @@
"@radroots/theme": "workspace:*",
"@radroots/utils": "workspace:*",
"chart.js": "^4.4.5",
+ "css-paint-polyfill": "^3.4.0",
"sql.js": "^1.11.0"
}
}
\ No newline at end of file
diff --git a/src/app.html b/src/app.html
@@ -8,9 +8,11 @@
<link rel="stylesheet" type="text/css" href="/phosphor-icons/fill.css" />
<link rel="stylesheet" type="text/css" href="/phosphor-icons/light.css" />
<link rel="stylesheet" type="text/css" href="/phosphor-icons/regular.css" />
- <link rel="stylesheet" type="text/css" href="/stylesheets/maplibre-gl.css" />
+ <link rel="stylesheet" type="text/css" href="/stylesheets/styles-maplibre-gl.css" />
+ <link rel="stylesheet" type="text/css" href="/stylesheets/styles-superellipse.css" />
<script src="/keyva.min.js"></script>
+ <script src="/squircle.min.js"></script>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no viewport-fit=cover" />
diff --git a/src/lib/client.ts b/src/lib/client.ts
@@ -1,10 +1,11 @@
-import { ClientNostr, TauriClientDb, TauriClientDevice, TauriClientDialog, TauriClientGeolocation, TauriClientHaptics, TauriClientHttp, TauriClientKeying, TauriClientKeystore, TauriClientLogger, TauriClientMap, TauriClientNotification, TauriClientOs, TauriClientWindow } from "@radroots/client";
+import { ClientNostr, TauriClientDb, TauriClientDevice, TauriClientDialog, TauriClientFs, TauriClientGeolocation, TauriClientHaptics, TauriClientHttp, TauriClientKeying, TauriClientKeystore, TauriClientLogger, TauriClientMap, TauriClientNotification, TauriClientOs, TauriClientWindow } from "@radroots/client";
import { Geocoder } from "@radroots/geocoder";
export const geoc = new Geocoder(`/geonames/geonames.db`);
export const db = new TauriClientDb();
export const device = new TauriClientDevice();
export const dialog = new TauriClientDialog();
+export const fs = new TauriClientFs();
export const geol = new TauriClientGeolocation();
export const haptics = new TauriClientHaptics();
export const os = new TauriClientOs();
diff --git a/src/lib/conf.ts b/src/lib/conf.ts
@@ -16,6 +16,9 @@ export const ks = {
nostr_publickey: `keys:nostr:`,
}
};
+export const ascii = {
+ bullet: '•'
+}
export const cfg = {
app: {
diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte
@@ -21,7 +21,7 @@
import { onMount } from "svelte";
type PageParamButtons = {
- route: NavigationRoute;
+ route?: NavigationRoute;
label: string;
key: GlyphKey;
weight?: GlyphWeight;
@@ -50,9 +50,24 @@
key: `note-blank`,
},
{
- route: `/models/trade-product`,
label: `Farm Products`,
key: `basket`,
+ callback: async () => {
+ const trade_products = await db.trade_product_get({
+ list: [`all`],
+ });
+ if (`results` in trade_products) {
+ if (trade_products.results.length === 0) {
+ $nav_prev.push({
+ route: `/`,
+ label: `Back`,
+ });
+ await route(`/models/trade-product/add`);
+ return;
+ }
+ }
+ await route(`/models/trade-product`);
+ },
},
{
route: `/`,
@@ -102,7 +117,7 @@
<div class={`flex flex-col pt-2 justify-center items-center`}>
{#if tmp_show_no_profile}
<button
- class={`relative flex flex-row h-24 w-${$app_layout} p-4 gap-4 justify-center items-center bg-layer-2-surface/60 rounded-touch touch-layer-1 touch-layer-1-raise-less el-re`}
+ class={`relative flex flex-row h-24 w-${$app_layout} p-4 gap-4 justify-center items-center bg-layer-2-surface/60 round-20 touch-layer-1 touch-layer-1-raise-less el-re`}
on:click={async () => {
await route(`/models/nostr-profile`);
}}
@@ -153,10 +168,10 @@
<div class={`flex flex-col w-full gap-5 justify-start items-center`}>
{#each page_param.buttons[$app_cfg_type] as btn}
<button
- class={`flex flex-row h-20 w-${$app_layout} py-2 px-6 justify-between items-center rounded-touch bg-layer-1-surface touch-layer-1 touch-layer-1-raise-less el-re`}
+ class={`flex flex-row h-20 w-${$app_layout} py-2 px-6 justify-between items-center bg-layer-1-surface touch-layer-1 touch-layer-1-raise-less round-20 el-re`}
on:click={async () => {
if (btn.callback) await btn.callback();
- await route(btn.route);
+ else if (btn.route) await route(btn.route);
}}
>
<div
diff --git a/src/routes/(app)/models/nostr-profile/+page.svelte b/src/routes/(app)/models/nostr-profile/+page.svelte
@@ -4,15 +4,15 @@
import {
app_nostr_key,
app_notify,
+ Glyph,
type ISelectOption,
LayoutTrellis,
LayoutView,
Nav,
nav_prev,
route,
- SelectElement,
+ SelectEl,
t,
- Glyph,
TrellisTitle,
} from "@radroots/svelte-lib";
import { onMount } from "svelte";
@@ -233,45 +233,41 @@
<div
class={`z-10 absolute top-2 right-3 flex flex-row h-full justify-end pr-1`}
>
- <SelectElement
+ <SelectEl
+ value={`~`}
basis={{
- args: {
- layer: 0,
- mask: true,
- callback: async ({ value }) => {
- await handle_key_options_press(
- {
- option: value,
- public_key:
- li.public_key,
- },
- );
- },
- options: [
- {
- entries:
- page_param.options_list.filter(
- (i) =>
- !(
- !li.name &&
- i.value ===
- `edit-profile-name`
- ) &&
- !(
- li.name &&
- i.value ===
- `add-profile-name`
- ) &&
- !(
- li.public_key ===
- $app_nostr_key &&
- i.value ===
- `set-key-active`
- ),
- ),
- },
- ],
+ layer: 0,
+ //mask: true,
+ callback: async ({ value }) => {
+ await handle_key_options_press({
+ option: value,
+ public_key: li.public_key,
+ });
},
+ options: [
+ {
+ entries:
+ page_param.options_list.filter(
+ (i) =>
+ !(
+ !li.name &&
+ i.value ===
+ `edit-profile-name`
+ ) &&
+ !(
+ li.name &&
+ i.value ===
+ `add-profile-name`
+ ) &&
+ !(
+ li.public_key ===
+ $app_nostr_key &&
+ i.value ===
+ `set-key-active`
+ ),
+ ),
+ },
+ ],
}}
>
<svelte:fragment slot="element">
@@ -284,7 +280,7 @@
}}
/>
</svelte:fragment>
- </SelectElement>
+ </SelectEl>
</div>
</div>
{/each}
diff --git a/src/routes/(app)/models/trade-product/+page.svelte b/src/routes/(app)/models/trade-product/+page.svelte
@@ -6,7 +6,6 @@
LayoutTrellis,
LayoutView,
Nav,
- nav_prev,
route,
t,
time_iso,
@@ -39,14 +38,6 @@
);
return;
}
- if (trade_products.results.length === 0) {
- $nav_prev.push({
- route: `/`,
- label: `Back`,
- });
- await route(`/models/trade-product/add`);
- return;
- }
const data: LoadData = {
trade_products: trade_products.results,
diff --git a/src/routes/(app)/models/trade-product/add/+page.svelte b/src/routes/(app)/models/trade-product/add/+page.svelte
@@ -24,7 +24,8 @@
el_id,
EntryLine,
EntryMultiline,
- EntryOption,
+ EntrySelect,
+ EntryWrap,
Fill,
fmt_geol_latitude,
fmt_geol_longitude,
@@ -38,6 +39,7 @@
LayoutView,
locale,
Nav,
+ SelectEl,
sleep,
t,
view_effect,
@@ -117,12 +119,7 @@
}
});
- $: {
- console.log(`$carousel_index `, $carousel_index);
- console.log(`$carousel_index_max `, $carousel_index_max);
- }
-
- let el_trellis_wrap_price: HTMLElement | null;
+ // let el_trellis_wrap_price: HTMLElement | null;
let loading_submit = false;
@@ -433,6 +430,19 @@
map_choose_loc_geoc_point_select = map_choose_loc_geoc_point;
};
+ const handle_entry_focus = async (id_key: string): Promise<void> => {
+ try {
+ const el = el_id(fmt_id(id_key));
+ el?.classList.add(`entry-layer-1-highlight`);
+ el?.focus();
+ await handle_back(2);
+ await sleep(1000);
+ el?.classList.remove(`entry-layer-1-highlight`);
+ } catch (e) {
+ console.log(`(error) handle_entry_focus `, e);
+ }
+ };
+
const submit = async (): Promise<void> => {
try {
loading_submit = true;
@@ -477,63 +487,82 @@
value: `${$t(`icu.show_*`, { value: `${$t(`common.options`)}` })}`,
},
callback: async () => {
+ const kv_other = await kv.get(
+ fmt_id(`key`),
+ );
+ if (kv_other) {
+ const confirm =
+ await dialog.confirm({
+ message: `${$t(`icu.the_current_entry_*_will_be_deleted`, { value: kv_other })}. ${$t(`common.do_you_want_to_continue_q`)}`,
+ });
+ if (confirm === true)
+ await kv.set(
+ fmt_id(`key`),
+ trade_key_default,
+ );
+ }
await toggle_show_key_other(false);
},
}
: undefined,
}}
>
- {#if show_sel_trade_product_key_other}
- <div
- class={`relative flex flex-row w-full justify-center items-center rounded-2xl`}
- >
- <EntryLine
- basis={{
- el: {
- id: fmt_id(`title`),
- sync: true,
- sync_init: true,
- placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`icu.*_title`, { value: `${$t(`common.listing`)}` })}`.toLowerCase() })}`,
- field: {
- charset:
- trade_product_form_fields
- .title.charset,
- validate:
- trade_product_form_fields
- .title.validation,
- validate_keypress: true,
+ {#if !show_sel_trade_product_key_other}
+ <EntrySelect
+ bind:value={sel_trade_product_key}
+ basis={{
+ wrap: {
+ id: fmt_id(`key_wrap`),
+ },
+ el: {
+ id: fmt_id(`key`),
+ sync: true,
+ options: [
+ ...trade_keys.map((i) => ({
+ value: i,
+ label: `${$t(`trade.product.key.${i}`, { default: i })}`,
+ })),
+ {
+ value: `other`,
+ label: `${$t(`common.other`)}`,
},
+ ],
+ callback: async (val) => {
+ const el = el_id(
+ fmt_id(`key_wrap`),
+ );
+ el?.classList.remove(
+ `entry-layer-1-highlight`,
+ );
+ if (val === `other`) {
+ await toggle_show_key_other(
+ true,
+ );
+ }
},
- }}
- />
- </div>
+ },
+ }}
+ />
{:else}
- <EntryOption
- bind:value={sel_trade_product_key}
+ <EntryLine
basis={{
- id_wrap: fmt_id(`key_wrap`),
- id: fmt_id(`key`),
- classes: `font-mono-display`,
- sync: true,
- options: [
- ...trade_keys.map((i) => ({
- value: i,
- label: `${$t(`trade.product.key.${i}`, { default: i })}`,
- })),
- {
- value: `other`,
- label: `${$t(`common.other`)}`,
+ wrap: {
+ id: fmt_id(`key_wrap`),
+ },
+ el: {
+ id: fmt_id(`key`),
+ sync: true,
+ sync_init: true,
+ placeholder: `${$t(`icu.enter_the_*`, { value: `${$t(`icu.*_name`, { value: `${$t(`common.product`)}` })}`.toLowerCase() })}`,
+ field: {
+ charset:
+ trade_product_form_fields.title
+ .charset,
+ validate:
+ trade_product_form_fields.title
+ .validation,
+ validate_keypress: true,
},
- ],
- callback: async (val) => {
- el_id(
- fmt_id(`key_wrap`),
- )?.classList.remove(
- `entry-layer-1-highlight`,
- );
- if (val === `other`) {
- await toggle_show_key_other(true);
- }
},
}}
/>
@@ -546,11 +575,10 @@
},
}}
>
- <div
- bind:this={el_trellis_wrap_price}
- id={fmt_id(`price_wrap`)}
- tabindex={-1}
- class={`relative el-re flex flex-row w-full pl-2 justify-between items-center h-form_line bg-layer-1-surface rounded-2xl`}
+ <EntryWrap
+ basis={{
+ id: fmt_id(`price_wrap`),
+ }}
>
<InputElement
basis={{
@@ -579,11 +607,17 @@
period_count < 2) ||
value.length < 1
) {
- el_trellis_wrap_price?.classList.remove(
+ const el = el_id(
+ fmt_id(`price_wrap`),
+ );
+ el?.classList.remove(
`entry-layer-1-highlight`,
);
} else {
- el_trellis_wrap_price?.classList.add(
+ const el = el_id(
+ fmt_id(`price_wrap`),
+ );
+ el?.classList.add(
`entry-layer-1-highlight`,
);
}
@@ -591,43 +625,55 @@
}}
/>
<div
- class={`flex flex-row gap-2 pl-3 pr-4 justify-end items-center bg-layer-1-surface rounded-r-2xl text-layer-1-glyph/70`}
+ class={`flex flex-row gap-2 justify-end items-center text-layer-1-glyph/70`}
>
- <EntryOption
+ <SelectEl
bind:value={sel_trade_product_price_currency}
basis={{
id: fmt_id(`price_currency`),
- classes: `w-fit font-mono-display font-[500] text-lg`,
+ classes: `w-fit font-circ font-[500] text-[1rem]`,
layer: false,
- hide_arrows: true,
- sync: true,
- options: fiat_currencies.map((i) => ({
- value: i,
- label: `${$t(`currency.${i}.symbol`, { default: i })}`,
- })),
+ //hide_arrows: true,
+ //sync: true,
+ options: [
+ {
+ entries: fiat_currencies.map(
+ (i) => ({
+ value: i,
+ label: `${$t(`currency.${i}.symbol`, { default: i })}`,
+ }),
+ ),
+ },
+ ],
}}
/>
<p
- class={`font-sans font-[500] text-[1.1rem] -translate-y-[1px] scale-y-[110%]`}
+ class={`font-sans font-[500] text-[1.1rem] -translate-y-[1px] scale-y-[120%]`}
>
{`/`}
</p>
- <EntryOption
+ <SelectEl
bind:value={sel_trade_product_price_qty_unit}
basis={{
id: fmt_id(`price_qty_unit`),
- classes: `w-fit font-mono-display font-[600] text-[0.95rem] leading-[1rem]`,
+ classes: `w-fit font-circ font-[500] text-[1rem]`,
layer: false,
- hide_arrows: true,
- sync: true,
- options: mass_units.map((i) => ({
- value: i,
- label: `${$t(`measurement.mass.unit.${i}_ab`, { default: i })}`,
- })),
+ // hide_arrows: true,
+ // sync: true,
+ options: [
+ {
+ entries: mass_units.map(
+ (i) => ({
+ value: i,
+ label: `${$t(`measurement.mass.unit.${i}_ab`, { default: i })}`,
+ }),
+ ),
+ },
+ ],
}}
/>
</div>
- </div>
+ </EntryWrap>
</LayoutTrellisLine>
<LayoutTrellisLine
basis={{
@@ -654,87 +700,94 @@
tabindex={-1}
class={`relative el-re flex flex-row w-full gap-3 justify-between items-center h-form_line bg-layer-1-surface text-layer-1-glyph rounded-2xl`}
>
- {#if show_sel_trade_product_qty_tup_other}
+ {#if !show_sel_trade_product_qty_tup_other}
+ <EntrySelect
+ bind:value={sel_trade_product_qty_tup}
+ basis={{
+ wrap: {
+ id: `tmp`,
+ },
+ el: {
+ options: [
+ ...ls_trade_product_quantities.map(
+ (i) => ({
+ value: fmt_trade_quantity_val(
+ i,
+ ),
+ label: `${i.mass} ${$t(`measurement.mass.unit.${i.mass_unit}_ab`, { default: i.mass_unit })} ${i.label}`,
+ }),
+ ),
+ {
+ value: `other`,
+ label: `${$t(`common.other`)}`,
+ },
+ ],
+ callback: async (val) => {
+ el_id(
+ fmt_id(`qty_wrap`),
+ )?.classList.remove(
+ `entry-layer-1-highlight`,
+ );
+ if (val === `other`) {
+ await toggle_show_qty_amt_other(
+ true,
+ );
+ } else {
+ await kv.set(
+ fmt_id(`qty_avail`),
+ `1`,
+ );
+ }
+ },
+ },
+ }}
+ />
+ {:else}
<div
class={`relative flex flex-row w-full justify-center items-center`}
>
- <EntryLine
+ <InputElement
basis={{
- el: {
- id: fmt_id(`qty_amt`),
- layer: false,
- sync: true,
- placeholder: `${$t(`icu.enter_number_of_*_per_order`, { value: `${$t(`measurement.mass.unit.${sel_trade_product_price_qty_unit}_ab`, { default: sel_trade_product_price_qty_unit })}` })}`,
- field: {
- charset:
- trade_product_form_fields
- .qty_amt.charset,
- validate:
- trade_product_form_fields
- .qty_amt.validation,
- validate_keypress: true,
- },
+ id: fmt_id(`qty_amt`),
+ layer: false,
+ sync: true,
+ placeholder: `${$t(`icu.enter_number_of_*_per_order`, { value: `${$t(`measurement.mass.unit.${sel_trade_product_price_qty_unit}_ab`, { default: sel_trade_product_price_qty_unit })}` })}`,
+ field: {
+ charset:
+ trade_product_form_fields
+ .qty_amt.charset,
+ validate:
+ trade_product_form_fields
+ .qty_amt.validation,
+ validate_keypress: true,
},
}}
/>
<div
class={`absolute top-0 right-0 flex flex-row h-full gap-2 justify-center items-center`}
>
- <EntryOption
+ <EntrySelect
bind:value={sel_trade_product_qty_unit}
basis={{
- id: fmt_id(`qty_unit`),
- classes: `w-[3.5rem] text-layer-1-glyph font-[500]`,
- layer: false,
- sync: true,
- options: mass_units.map(
- (i) => ({
- value: i,
- label: `${$t(`measurement.mass.unit.${i}_ab`, { default: i })}`,
- }),
- ),
+ wrap: {
+ id: `tmp2`,
+ },
+ el: {
+ id: fmt_id(`qty_unit`),
+ classes: `w-[3.5rem] text-layer-1-glyph font-[500]`,
+ //layer: false,
+ //sync: true,
+ options: mass_units.map(
+ (i) => ({
+ value: i,
+ label: `${$t(`measurement.mass.unit.${i}_ab`, { default: i })}`,
+ }),
+ ),
+ },
}}
/>
</div>
</div>
- {:else}
- <EntryOption
- bind:value={sel_trade_product_qty_tup}
- basis={{
- classes: `font-mono-display`,
- options: [
- ...ls_trade_product_quantities.map(
- (i) => ({
- value: fmt_trade_quantity_val(
- i,
- ),
- label: `${i.mass} ${$t(`measurement.mass.unit.${i.mass_unit}_ab`, { default: i.mass_unit })} ${i.label}`,
- }),
- ),
- {
- value: `other`,
- label: `${$t(`common.other`)}`,
- },
- ],
- callback: async (val) => {
- el_id(
- fmt_id(`qty_wrap`),
- )?.classList.remove(
- `entry-layer-1-highlight`,
- );
- if (val === `other`) {
- await toggle_show_qty_amt_other(
- true,
- );
- } else {
- await kv.set(
- fmt_id(`qty_avail`),
- `1`,
- );
- }
- },
- }}
- />
{/if}
</div>
</LayoutTrellisLine>
@@ -926,17 +979,8 @@
<button
class={`flex flex-row justify-start items-center active:opacity-60 transition-all`}
on:click={async () => {
- const el = el_id(
- fmt_id(`key_wrap`),
- );
- el?.classList.add(
- `entry-layer-1-highlight`,
- );
- el?.focus();
- await handle_back(2);
- await sleep(1000);
- el?.classList.remove(
- `entry-layer-1-highlight`,
+ await handle_entry_focus(
+ `key_wrap`,
);
}}
>
@@ -1042,20 +1086,27 @@
<button
class={`flex flex-row justify-start items-center active:opacity-60 transition-all`}
on:click={async () => {
- const el = el_id(
+ await handle_entry_focus(
+ `price_wrap`,
+ );
+ /*const el = el_id(
fmt_id(
`price_wrap`,
),
);
+ console.log(`el `, el);
el?.classList.add(
`entry-layer-1-highlight`,
);
el?.focus();
await handle_back(2);
- await sleep(1000);
+ await sleep(
+ cfg.delay
+ .entry_focus,
+ );
el?.classList.remove(
`entry-layer-1-highlight`,
- );
+ );*/
}}
>
<p
@@ -1116,7 +1167,10 @@
);
el?.focus();
await handle_back(2);
- await sleep(1000);
+ await sleep(
+ cfg.delay
+ .entry_focus,
+ );
el?.classList.remove(
`entry-layer-1-highlight`,
);
@@ -1318,7 +1372,9 @@
>
<EntryLine
basis={{
- id_wrap: fmt_id(`title_wrap`),
+ wrap: {
+ id: fmt_id(`title_wrap`),
+ },
el: {
id: fmt_id(`title`),
sync: true,
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
@@ -23,15 +23,16 @@
type NavigationRoute,
} from "@radroots/svelte-lib";
import { parse_color_mode, parse_theme_key } from "@radroots/theme";
+ import "css-paint-polyfill";
import { onDestroy, onMount } from "svelte";
import "../app.css";
- //let unlisten_logger: IClientUnlisten;
let route_render: NavigationRoute | undefined = undefined;
onMount(async () => {
try {
- //unlisten_logger = await logger.init();
+ if (`paintWorklet` in CSS)
+ (CSS as any).paintWorklet.addModule(`/squircle.min.js`);
const metadata: IClientDeviceMetadata = {
version: os.version(),
platform: os.platform(),
@@ -46,7 +47,6 @@
onDestroy(async () => {
try {
- //unlisten_logger();
route_render = undefined;
} catch (e) {
} finally {
diff --git a/static/squircle.min.js b/static/squircle.min.js
@@ -0,0 +1 @@
+const drawSquircle = (ctx, geom, radii, smooth, lineWidth, color) => { const defaultFill = color; const lineWidthOffset = lineWidth / 2; ctx.beginPath(); ctx.lineTo(radii[0], lineWidthOffset); ctx.lineTo(geom.width - radii[1], lineWidthOffset); ctx.bezierCurveTo(geom.width - radii[1] / smooth, lineWidthOffset, geom.width - lineWidthOffset, radii[1] / smooth, geom.width - lineWidthOffset, radii[1]); ctx.lineTo(geom.width - lineWidthOffset, geom.height - radii[2]); ctx.bezierCurveTo(geom.width - lineWidthOffset, geom.height - radii[2] / smooth, geom.width - radii[2] / smooth, geom.height - lineWidthOffset, geom.width - radii[2], geom.height - lineWidthOffset); ctx.lineTo(radii[3], geom.height - lineWidthOffset); ctx.bezierCurveTo(radii[3] / smooth, geom.height - lineWidthOffset, lineWidthOffset, geom.height - radii[3] / smooth, lineWidthOffset, geom.height - radii[3]); ctx.lineTo(lineWidthOffset, radii[0]); ctx.bezierCurveTo(lineWidthOffset, radii[0] / smooth, radii[0] / smooth, lineWidthOffset, radii[0], lineWidthOffset); ctx.closePath(); if (lineWidth) { ctx.strokeStyle = defaultFill; ctx.lineWidth = lineWidth; ctx.stroke() } else { ctx.fillStyle = defaultFill; ctx.fill() } }; class SquircleClass { static get contextOptions() { return { alpha: true } } static get inputProperties() { return ["--squircle-radius", "--squircle-radius-top-left", "--squircle-radius-top-right", "--squircle-radius-bottom-right", "--squircle-radius-bottom-left", "--squircle-smooth", "--squircle-outline", "--squircle-fill"] } paint(ctx, geom, properties) { const smoothRatio = 10; const distanceRatio = 1.8; const squircleSmooth = parseFloat(properties.get("--squircle-smooth") * smoothRatio); const individualRadiiProps = SquircleClass.inputProperties.slice(1, 5); let squircleRadii = individualRadiiProps.map(prop => { const value = properties.get(prop); return value ? parseInt(value, 10) * distanceRatio : NaN }); let shorthand_R; if (squircleRadii.some(isNaN)) { const radiusRegex = /([0-9]+[a-z%]*)/g; const radius_shorthand = properties.get("--squircle-radius").toString(); const matches = radius_shorthand.match(radiusRegex); if (matches) { shorthand_R = matches.map(val => parseInt(val, 10) * distanceRatio); while (shorthand_R.length < 4) { if (shorthand_R.length === 1) { shorthand_R.push(shorthand_R[0]) } else if (shorthand_R.length === 2) { shorthand_R = [shorthand_R[0], shorthand_R[1], shorthand_R[0], shorthand_R[1]] } else if (shorthand_R.length === 3) { shorthand_R = [shorthand_R[0], shorthand_R[1], shorthand_R[2], shorthand_R[1]] } } } else { const defaultRadius = squircleRadii.every(isNaN) ? 8 * distanceRatio : 0; shorthand_R = [defaultRadius, defaultRadius, defaultRadius, defaultRadius] } } squircleRadii = squircleRadii.map((val, i) => isNaN(val) ? shorthand_R[i] : val); const squrcleOutline = parseFloat(properties.get("--squircle-outline"), 10); const squrcleColor = properties.get("--squircle-fill").toString(); const isSmooth = () => { if (typeof properties.get("--squircle-smooth")[0] !== "undefined") { if (squircleSmooth === 0) { return 1 } return squircleSmooth } else { return 10 } }; const isOutline = () => { if (squrcleOutline) { return squrcleOutline } else { return 0 } }; const isColor = () => { if (squrcleColor) { return squrcleColor } else { return "#f45" } }; const maxRadius = Math.max(...squircleRadii); if (maxRadius < geom.width / 2 && maxRadius < geom.height / 2) { drawSquircle(ctx, geom, squircleRadii, isSmooth(), isOutline(), isColor()) } else { const minRadius = Math.min(geom.width / 2, geom.height / 2); drawSquircle(ctx, geom, squircleRadii.map(() => minRadius), isSmooth(), isOutline(), isColor()) } } } if (typeof registerPaint !== "undefined") { registerPaint("squircle", SquircleClass) }
+\ No newline at end of file
diff --git a/tailwind.config.ts b/tailwind.config.ts
@@ -6,7 +6,7 @@ import tailwind_default from "tailwindcss/defaultTheme";
const { fontFamily: tw_font } = tailwind_default;
const heights_form = {
- line: "44px",
+ line: "46px",
};
const heights_responsive = {
@@ -101,6 +101,10 @@ const config: Config = {
envelopeButtonCancel: ["1.1rem", { lineHeight: "1.75rem", fontWeight: 600 }],
envelopeButtonLabel: ["1.1rem", { lineHeight: "1.75rem", fontWeight: 500 }],
},
+ gridTemplateColumns: {
+ '16': 'repeat(16, minmax(0, 1fr))',
+ '24': 'repeat(24, minmax(0, 1fr))',
+ },
height: {
...heights,
...dimensions,
@@ -139,6 +143,7 @@ const config: Config = {
},
borderRadius: {
input_form: "8px",
+ entry: "1.05rem",
touch: "1.25rem"
},
}