simplify components
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 3s
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 3s
This commit is contained in:
@@ -14,17 +14,11 @@ import { ui, val, getIcon } from "../utils.js";
|
||||
* - btn-active, btn-disabled
|
||||
*/
|
||||
export const Button = (props, children) => {
|
||||
const { class: className, loading, icon, ...rest } = props;
|
||||
|
||||
const iconEl = getIcon(icon);
|
||||
const { class: className, ...rest } = props;
|
||||
|
||||
return Tag("button", {
|
||||
...rest,
|
||||
class: ui('btn', className),
|
||||
disabled: () => val(loading) || val(props.disabled),
|
||||
}, () => [
|
||||
val(loading) && Tag("span", { class: "loading loading-spinner" }),
|
||||
iconEl,
|
||||
children
|
||||
].filter(Boolean));
|
||||
disabled: () => val(props.disabled),
|
||||
}, () => children);
|
||||
};
|
||||
@@ -1,45 +1,52 @@
|
||||
import { $$ } from "sigpro";
|
||||
export const Fetch = ({ url, options = {}, fallback = "Cargando..." }, { children }) => {
|
||||
const state = $$({ data: null, loading: true, error: null });
|
||||
let controller = null;
|
||||
import { $$, Tag, isFunc } from "sigpro";
|
||||
|
||||
const run = async () => {
|
||||
if (controller) controller.abort();
|
||||
controller = new AbortController();
|
||||
state.loading = true;
|
||||
state.error = null;
|
||||
const _cache = new Map();
|
||||
|
||||
try {
|
||||
const targetUrl = isFunc(url) ? url() : url;
|
||||
const fetchOpts = {
|
||||
...(isFunc(options) ? options() : options),
|
||||
signal: controller.signal
|
||||
};
|
||||
const getStore = (key) => {
|
||||
if (!_cache.has(key)) {
|
||||
_cache.set(key, $$({ data: null, loading: false, error: null }));
|
||||
}
|
||||
return _cache.get(key);
|
||||
};
|
||||
|
||||
const res = await fetch(targetUrl, fetchOpts);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
|
||||
const contentType = res.headers.get("content-type");
|
||||
state.data = contentType?.includes("application/json")
|
||||
? await res.json()
|
||||
: await res.text();
|
||||
} catch (err) {
|
||||
if (err.name !== 'AbortError') state.error = err.message;
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
};
|
||||
export const Request = async (key, url, opts = {}) => {
|
||||
const store = getStore(key);
|
||||
const { body, ...rest } = opts;
|
||||
|
||||
store.loading = true;
|
||||
store.error = null;
|
||||
|
||||
if (isFunc(url)) Watch(url, run);
|
||||
else run();
|
||||
try {
|
||||
const config = {
|
||||
method: rest.method || 'GET',
|
||||
headers: { 'Content-Type': 'application/json', ...rest.headers },
|
||||
...rest
|
||||
};
|
||||
|
||||
onUnmount(() => controller?.abort());
|
||||
if (body) config.body = typeof body === 'object' ? JSON.stringify(body) : body;
|
||||
|
||||
return Tag("div", { class: "sigpro-fetch" }, [
|
||||
const res = await fetch(url, config);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
|
||||
const result = await res.json();
|
||||
store.data = result;
|
||||
return result;
|
||||
} catch (err) {
|
||||
store.error = err.message;
|
||||
throw err;
|
||||
} finally {
|
||||
store.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
export const Response = ({ name, loading, error }, { children }) => {
|
||||
const store = getStore(name);
|
||||
|
||||
return Tag("div", { style: "display:contents" }, [
|
||||
() => {
|
||||
if (state.loading) return fallback;
|
||||
if (state.error) return Tag("span", { style: "color:red" }, state.error);
|
||||
if (state.data) return isFunc(children[0]) ? children[0](state.data) : children;
|
||||
if (store.loading) return loading || "Cargando...";
|
||||
if (store.error) return isFunc(error) ? error(store.error) : Tag("p", {}, store.error);
|
||||
if (store.data) return isFunc(children[0]) ? children[0](store.data) : children;
|
||||
return null;
|
||||
}
|
||||
]);
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import { $$, Tag, isFunc } from "sigpro";
|
||||
|
||||
const _cache = new Map();
|
||||
|
||||
const getStore = (key) => {
|
||||
if (!_cache.has(key)) {
|
||||
_cache.set(key, $$({ data: null, loading: false, error: null }));
|
||||
}
|
||||
return _cache.get(key);
|
||||
};
|
||||
|
||||
export const Request = async (key, url, opts = {}) => {
|
||||
const store = getStore(key);
|
||||
const { body, ...rest } = opts;
|
||||
|
||||
store.loading = true;
|
||||
store.error = null;
|
||||
|
||||
try {
|
||||
const config = {
|
||||
method: rest.method || 'GET',
|
||||
headers: { 'Content-Type': 'application/json', ...rest.headers },
|
||||
...rest
|
||||
};
|
||||
|
||||
if (body) config.body = typeof body === 'object' ? JSON.stringify(body) : body;
|
||||
|
||||
const res = await fetch(url, config);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
|
||||
const result = await res.json();
|
||||
store.data = result;
|
||||
return result;
|
||||
} catch (err) {
|
||||
store.error = err.message;
|
||||
throw err;
|
||||
} finally {
|
||||
store.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
export const Response = ({ name, loading, error }, { children }) => {
|
||||
const store = getStore(name);
|
||||
|
||||
return Tag("div", { style: "display:contents" }, [
|
||||
() => {
|
||||
if (store.loading) return loading || "Cargando...";
|
||||
if (store.error) return isFunc(error) ? error(store.error) : Tag("p", {}, store.error);
|
||||
if (store.data) return isFunc(children[0]) ? children[0](store.data) : children;
|
||||
return null;
|
||||
}
|
||||
]);
|
||||
};
|
||||
11
src/components/Spinner.js
Normal file
11
src/components/Spinner.js
Normal file
@@ -0,0 +1,11 @@
|
||||
// components/Spinner.js
|
||||
import { Tag } from "sigpro";
|
||||
import { val } from "../utils.js";
|
||||
|
||||
export const Spinner = (props) => {
|
||||
const { value, ...rest } = props;
|
||||
return If(
|
||||
() => val(value),
|
||||
() => Tag("span", { class: "loading loading-spinner", ...rest })
|
||||
);
|
||||
};
|
||||
@@ -2,8 +2,6 @@
|
||||
@plugin "daisyui";
|
||||
@plugin "@iconify/tailwind4";
|
||||
|
||||
/* join join-vertical lg:join-horizontal divider divider-horizontal validator validator-hint glass */
|
||||
|
||||
@plugin "daisyui/theme" {
|
||||
name: "light";
|
||||
default: true;
|
||||
@@ -99,6 +97,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.floating-label span {
|
||||
color: oklch(30% 0.01 260); /* Gris más oscuro (30% es más oscuro que 45%) */
|
||||
font-size: 1.1rem; /* text-base: más grande que 0.875rem */
|
||||
@@ -115,18 +114,6 @@
|
||||
font-size: 1.1rem; /* Mantiene el mismo tamaño */
|
||||
}
|
||||
|
||||
.collapse .collapse-content {
|
||||
transform: scaleY(0);
|
||||
transform-origin: top;
|
||||
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
.collapse:has(input:checked) .collapse-content {
|
||||
transform: scaleY(1);
|
||||
height: auto;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.tab-content-inner {
|
||||
animation: tabFadeIn 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
@@ -144,8 +131,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* sigpro-ui daisyUI classes - extracted from components */
|
||||
|
||||
/* join join-vertical lg:join-horizontal divider divider-horizontal validator validator-hint glass */
|
||||
|
||||
/* Accordion */
|
||||
/* .input, .input-bordered, .input-ghost, .input-primary, .input-secondary, .input-accent, .input-info, .input-success, .input-warning, .input-error, .input-xs, .input-sm, .input-md, .input-lg, .floating-label, */
|
||||
|
||||
@@ -353,4 +343,7 @@
|
||||
/* .hover:bg-base-200, */
|
||||
|
||||
/* Misc */
|
||||
/* .active, .hr, .label, .label-text, */
|
||||
/* .active, .hr, .label, .label-text, */
|
||||
|
||||
/* Icons */
|
||||
/* .icon-[lucide--heart] */
|
||||
Reference in New Issue
Block a user