diff --git a/comps/form/field/FieldInput.tsx b/comps/form/field/FieldInput.tsx index 9eaa1b3..178d4ff 100755 --- a/comps/form/field/FieldInput.tsx +++ b/comps/form/field/FieldInput.tsx @@ -134,8 +134,12 @@ export const FieldInput: FC<{ <> {prefix && prefix !== "" ? (
{prefix}
@@ -194,8 +198,12 @@ export const FieldInput: FC<{ {suffix && suffix !== "" ? (
{suffix}
diff --git a/comps/form/field/type/FilePreview.tsx b/comps/form/field/type/FilePreview.tsx index fdd19a6..1411c69 100755 --- a/comps/form/field/type/FilePreview.tsx +++ b/comps/form/field/type/FilePreview.tsx @@ -1,3 +1,4 @@ +import { useLocal } from "lib/utils/use-local"; import { ExternalLink } from "lucide-react"; import { ReactElement } from "react"; @@ -8,6 +9,25 @@ export const ThumbPreview = ({ url: string; options: ReactElement; }) => { + const local = useLocal({ size: "", is_doc: true }, async () => { + if (url.startsWith("_file/")) { + let _url = siteurl(`/_finfo/${url.substring("_file/".length)}`); + + if ( + location.hostname === "prasi.avolut.com" || + location.host === "localhost:4550" + ) { + const newurl = new URL(location.href); + newurl.pathname = `/_proxy/${_url}`; + _url = newurl.toString(); + } + + const info = await fetch(_url); + local.size = (await info.json())?.size; + local.render(); + } + }); + const file = getFileName(url); if (typeof file === "string") return; @@ -34,14 +54,23 @@ export const ThumbPreview = ({ outline: 1px solid #1c4ed8; } `, - "c-flex c-justify-center c-items-center" + "c-flex c-justify-center c-items-center c-flex-col" )} onClick={() => { let _url = siteurl(url || ""); window.open(_url, "_blank"); }} > - {file.extension} +
{file.extension}
+
+ {local.size} +
); @@ -49,6 +78,7 @@ export const ThumbPreview = ({ if (url.startsWith("_file/")) { if ([".png", ".jpeg", ".jpg", ".webp"].find((e) => url.endsWith(e))) { is_image = true; + local.is_doc = false; content = ( { diff --git a/comps/form/field/type/TypeDropdown.tsx b/comps/form/field/type/TypeDropdown.tsx index 2d4dbc6..c27c299 100755 --- a/comps/form/field/type/TypeDropdown.tsx +++ b/comps/form/field/type/TypeDropdown.tsx @@ -3,7 +3,6 @@ import { FieldLoading } from "lib/comps/ui/field-loading"; import { Typeahead } from "lib/comps/ui/typeahead"; import { FC, useEffect } from "react"; import { FMLocal, FieldLocal, FieldProp } from "../../typings"; -import { call_prasi_events } from "lib/exports"; export const TypeDropdown: FC<{ field: FieldLocal; @@ -35,23 +34,27 @@ export const TypeDropdown: FC<{ data: e.data, }; }); - let v = typeof arg.opt_get_value === "function" - ? arg.opt_get_value({ - fm, - name: field.name, - options: local.options, - type: field.type, - }) - : fm.data[field.name]; - let f = list.find((ex) => ex.value === v); - if(!f){ - arg.opt_set_value({ - fm, - name: field.name, - type: field.type, - options: local.options, - selected: [], - }); + let v = + typeof arg.opt_get_value === "function" + ? arg.opt_get_value({ + fm, + name: field.name, + options: local.options, + type: field.type, + }) + : fm.data[field.name]; + if (field.type === "single-option") { + let f = list.find((ex: any) => ex.value === v); + + if (!f) { + arg.opt_set_value({ + fm, + name: field.name, + type: field.type, + options: local.options, + selected: [], + }); + } } local.options = list; } else { @@ -140,8 +143,8 @@ export const TypeDropdown: FC<{ popupClassName = cx( css` .opt-item { - padding-top: 0px; - padding-bottom: 0px; + padding-top: 4px; + padding-bottom: 4px; line-height: 15px; font-size: 12px; border: 0px; diff --git a/comps/form/field/type/TypeRichText.tsx b/comps/form/field/type/TypeRichText.tsx index a6dcdd1..ac5af2e 100755 --- a/comps/form/field/type/TypeRichText.tsx +++ b/comps/form/field/type/TypeRichText.tsx @@ -11,38 +11,30 @@ export const FieldRichText: FC<{ prop: PropTypeInput; }> = ({ field, fm, prop }) => { const local = useLocal({ - ref: null as any, + ref: null as null | HTMLDivElement, + q: null as null | Quill, }); useEffect(() => { if (local.ref) { - const q = new Quill(local.ref, { + local.ref.innerHTML = fm.data[field.name] || ""; + local.q = new Quill(local.ref, { theme: "snow", modules: { toolbar: [ ["bold", "italic", "underline", "strike"], // toggled buttons - ["blockquote", "code-block"], - ["link", "image", "video", "formula"], - - [{ header: 1 }, { header: 2 }], // custom button values [{ list: "ordered" }, { list: "bullet" }, { list: "check" }], - [{ script: "sub" }, { script: "super" }], // superscript/subscript [{ indent: "-1" }, { indent: "+1" }], // outdent/indent - [{ direction: "rtl" }], // text direction - - [{ size: ["small", false, "large", "huge"] }], // custom dropdown - [{ header: [1, 2, 3, 4, 5, 6, false] }], - - [{ color: [] }, { background: [] }], // dropdown with defaults from theme - [{ font: [] }], - [{ align: [] }], - ["clean"], // remove formatting button ], }, }); + + local.q.on("text-change", (delta, oldDelta, source) => { + fm.data[field.name] = local.q?.getSemanticHTML(); + fm.render(); + }); } }, []); - let value: any = fm.data[field.name]; return (
{ + e.stopPropagation(); + e.preventDefault(); + }} >
(local.ref = e)} className={cx(css` - height: 20rem !important; + min-height: 5rem !important; `)} >
diff --git a/comps/form/field/type/TypeUploadMulti.tsx b/comps/form/field/type/TypeUploadMulti.tsx index 90f8783..1d10a5b 100755 --- a/comps/form/field/type/TypeUploadMulti.tsx +++ b/comps/form/field/type/TypeUploadMulti.tsx @@ -16,9 +16,8 @@ export const FieldUploadMulti: FC<{ arg: FieldProp; on_change: (e: any) => void | Promise; }> = ({ field, fm, prop, on_change, arg }) => { - let value: string = (fm.data[field.name] || "").trim(); - + const input = useLocal({ value: 0 as any, display: false as any, @@ -136,6 +135,9 @@ export const FieldUploadMulti: FC<{ .upload-star { border: 1px solid gray; } + .btn-del { + border: 1px solid red; + } } `, fm.data[cover.field] === value && @@ -188,9 +190,8 @@ export const FieldUploadMulti: FC<{ } }} className={cx( - "c-flex c-flex-row c-items-center c-px-1 c-rounded c-bg-white c-cursor-pointer hover:c-bg-red-100 transition-all", + "c-flex c-flex-row c-items-center c-px-1 c-rounded c-bg-white c-cursor-pointer hover:c-bg-red-100 transition-all btn-del", css` - border: 1px solid red; width: 25px; height: 25px; ` @@ -258,11 +259,21 @@ export const FieldUploadMulti: FC<{ )} -
-
+
+
)} -
+
diff --git a/comps/form/gen/gen-form/on-submit.ts b/comps/form/gen/gen-form/on-submit.ts index dcbb3b6..d7b3986 100755 --- a/comps/form/gen/gen-form/on-submit.ts +++ b/comps/form/gen/gen-form/on-submit.ts @@ -150,14 +150,16 @@ ${ fm.data = form; md.selected = form; if (md.props.mode !== "full") md.master.reload({ toast: false }); - md.render(); - fm.render(); - + if (fm.props.back_on_save === "y") { md.selected = null; md.tab.active = "master"; md.params.apply(); md.render(); + } else { + md.params.apply(); + md.render(); + fm.render(); } }` } diff --git a/comps/form/utils/init.tsx b/comps/form/utils/init.tsx index a6fff78..5606e72 100755 --- a/comps/form/utils/init.tsx +++ b/comps/form/utils/init.tsx @@ -1,13 +1,12 @@ import { parseGenField } from "@/gen/utils"; +import { MDLocal } from "lib/comps/md/utils/typings"; +import { Button } from "lib/comps/ui/button"; +import { toast } from "lib/comps/ui/toast"; import get from "lodash.get"; import { AlertTriangle, Check, ChevronLeft, Loader2, Plus } from "lucide-react"; import { FMLocal, FMProps } from "../typings"; import { editorFormData } from "./ed-data"; import { formError } from "./error"; -import { toast } from "lib/comps/ui/toast"; -import { Button } from "lib/comps/ui/button"; -import { MDLocal } from "lib/comps/md/utils/typings"; -import { masterDetailApplyParams } from "lib/comps/md/utils/md-hash"; export const formInit = (fm: FMLocal, props: FMProps) => { for (const [k, v] of Object.entries(props)) { diff --git a/comps/md/MasterDetail.tsx b/comps/md/MasterDetail.tsx index 87c828b..d5d0b9b 100755 --- a/comps/md/MasterDetail.tsx +++ b/comps/md/MasterDetail.tsx @@ -131,7 +131,8 @@ export const MasterDetail: FC = (arg) => { return (
{md.props.show_head === "always" && } diff --git a/comps/ui/badge.tsx b/comps/ui/badge.tsx index 9c74ea8..58fef6e 100755 --- a/comps/ui/badge.tsx +++ b/comps/ui/badge.tsx @@ -4,7 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/utils" const badgeVariants = cva( - "c-inline-flex c-items-center c-rounded-full c-border c-px-2.5 c-py-0.5 c-text-xs c-font-semibold c-transition-colors focus:c-outline-none focus:c-ring-2 focus:c-ring-ring focus:c-ring-offset-2", + "c-inline-flex c-items-center c-rounded-full c-border c-px-2.5 c-py-0.5 c-font-semibold c-transition-colors focus:c-outline-none focus:c-ring-2 focus:c-ring-ring focus:c-ring-offset-2", { variants: { variant: { diff --git a/comps/ui/typeahead-opt.tsx b/comps/ui/typeahead-opt.tsx index 9e9a316..b842097 100755 --- a/comps/ui/typeahead-opt.tsx +++ b/comps/ui/typeahead-opt.tsx @@ -82,7 +82,7 @@ export const TypeaheadOptions: FC<{ })} {searching ? ( -
+
Loading...
) : ( diff --git a/comps/ui/typeahead.tsx b/comps/ui/typeahead.tsx index 350ee58..d7ce33b 100755 --- a/comps/ui/typeahead.tsx +++ b/comps/ui/typeahead.tsx @@ -337,18 +337,33 @@ export const Typeahead: FC<{
0 + ? css` + input { + margin-top: 5px; + } + ` + : css` + input { + margin-top: 5px; + } + ` )} onClick={() => { if (!disabled) input.current?.focus(); }} > {local.mode === "multi" ? ( - <> +
{valueLabel.map((e, idx) => { return ( { if (!disabled) { @@ -377,7 +393,7 @@ export const Typeahead: FC<{ ); })} - +
) : ( <> )} @@ -531,7 +547,7 @@ export const Typeahead: FC<{ disabled={disabled} spellCheck={false} className={cx( - "c-flex-1 c-mb-2 c-text-sm c-outline-none c-bg-transparent", + "c-flex-1 c-mb-2 c-outline-none c-bg-transparent", local.mode === "single" ? "c-cursor-pointer" : "" )} onKeyDown={keydown} diff --git a/utils/format-value.tsx b/utils/format-value.tsx index 6199821..ba40b8b 100755 --- a/utils/format-value.tsx +++ b/utils/format-value.tsx @@ -130,6 +130,46 @@ export const FormatValue: FC<{ return ; } + if (name.startsWith("desc")) { + return ( +
+
+
+ ); + } + + if (typeof value === "string" && value.startsWith("_file/")) { + return ( + { + let _url = siteurl(value || ""); + window.open(_url, "_blank"); + }} + className={cx( + "c-rounded-md", + css` + &:hover { + outline: 2px solid #1c4ed8; + } + `, + css` + width: 25px; + height: 25px; + background-image: linear-gradient(45deg, #ccc 25%, transparent 25%), + linear-gradient(135deg, #ccc 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, #ccc 75%), + linear-gradient(135deg, transparent 75%, #ccc 75%); + background-size: 25px 25px; /* Must be a square */ + background-position: 0 0, 12.5px 0, 12.5px -12.5px, 0px 12.5px; /* Must be half of one side of the square */ + ` + )} + src={siteurl( + `/_img/${value.substring("_file/".length)}?${"w=25&h=25&fit=cover"}` + )} + /> + ); + } + return (
{value}