fix upload style

This commit is contained in:
rizky 2024-07-29 18:13:27 -07:00
parent 984ad22ae8
commit c3bb624d25
4 changed files with 106 additions and 38 deletions

View File

@ -11,6 +11,7 @@ export const SingleOption: FC<{
fm: FMLocal; fm: FMLocal;
arg: FieldProp; arg: FieldProp;
}> = ({ field, fm, arg }) => { }> = ({ field, fm, arg }) => {
return ( return (
<> <>
{arg.sub_type === "dropdown" ? ( {arg.sub_type === "dropdown" ? (
@ -23,7 +24,7 @@ export const SingleOption: FC<{
<FieldRadio arg={arg} field={field} fm={fm} /> <FieldRadio arg={arg} field={field} fm={fm} />
) : arg.sub_type === "checkbox" ? ( ) : arg.sub_type === "checkbox" ? (
<FieldSingleCheckbox arg={arg} field={field} fm={fm} /> <FieldSingleCheckbox arg={arg} field={field} fm={fm} />
) :( ) : (
<></> <></>
)} )}
</> </>

View File

@ -120,17 +120,17 @@ export const FieldUpload: FC<{
} }
}; };
return ( return (
<div className="c-flex-grow c-flex-row c-flex c-w-full c-h-full c-items-center"> <div className="c-flex-grow c-flex-row c-flex c-w-full c-h-full c-items-stretch">
{input.fase === "start" ? ( {input.fase === "start" ? (
<> <>
<div className="c-flex c-flex-row c-relative c-flex-grow"> <div className="c-flex c-flex-row c-relative c-flex-grow c-items-center">
<input <input
ref={(ref) => (input.ref = ref)} ref={(ref) => (input.ref = ref)}
type="file" type="file"
multiple={false} multiple={false}
onChange={on_upload} onChange={on_upload}
className={cx( className={cx(
"c-absolute c-w-full c-h-full c-cursor-pointer c-top-0 c-left-0 c-hidden" "c-absolute c-w-full c-h-full c-cursor-pointer c-top-0 c-left-0 c-opacity-0"
)} )}
/> />
{styling === "inline" ? ( {styling === "inline" ? (
@ -138,11 +138,11 @@ export const FieldUpload: FC<{
<div <div
onClick={() => { onClick={() => {
if (input.ref) { if (input.ref) {
console.log(input.ref) console.log(input.ref);
input.ref.click(); input.ref.click();
} }
}} }}
className="c-items-center c-flex c-text-base c-px-5 c-py-3 c-outline-none c-rounded c-cursor-pointer " className="c-items-center c-flex c-text-base c-px-5 c-outline-none c-rounded c-cursor-pointer "
> >
<div className="c-flex c-flex-row c-items-center c-px-2"> <div className="c-flex c-flex-row c-items-center c-px-2">
<Upload className="c-h-4 c-w-4" /> <Upload className="c-h-4 c-w-4" />
@ -203,45 +203,38 @@ export const FieldUpload: FC<{
</div> </div>
</> </>
) : input.fase === "upload" ? ( ) : input.fase === "upload" ? (
<> <div className="c-flex c-items-center">
<div className="c-px-2"> <div className="c-px-2">
<Loader2 className={cx("c-h-5 c-w-5 c-animate-spin")} /> <Loader2 className={cx("c-h-5 c-w-5 c-animate-spin")} />
</div> </div>
<div className="c-px-2">Uploading</div> <div className="">Uploading</div>
</> </div>
) : input.fase === "preview" ? ( ) : input.fase === "preview" ? (
<> <div className="c-flex c-justify-between c-flex-1 c-p-1">
<div className="c-flex c-flex-row c-p-2 c-items-center">
<IconFile type={getFileName(siteurl(value)).extension} />
</div>
<div <div
className="c-line-clamp-1 c-flex-grow c-items-center" className="c-flex c-border c-rounded c-items-center c-px-2 hover:c-bg-blue-50 c-cursor-pointer"
onClick={() => { onClick={() => {
let url = siteurl(value); let url = siteurl(value);
window.open(url, "_blank"); window.open(url, "_blank");
}} }}
> >
{getFileName(siteurl(value)).fullname} <Filename url={siteurl(value)} />
</div> <div className="ml-2">
<div className="c-flex c-flex-row c-items-center"> <ExternalLink size="12px" />
<div className="c-flex c-flex-row c-space-x-1 c-px-2">
<SquareArrowOutUpRight
className="c-h-5 c-w-5"
onClick={() => {
let url = siteurl(value);
window.open(url, "_blank");
}}
/>
<Trash2
className="c-text-red-500 c-h-5 c-w-5"
onClick={() => {
fm.data[field.name] = null;
fm.render();
}}
/>
</div> </div>
</div> </div>
</> <div className="c-flex c-flex-row c-items-center c-border c-px-2 c-cursor-pointer hover:c-bg-red-100">
<Trash2
className="c-text-red-500 c-h-4 c-w-4"
onClick={() => {
if (confirm("Clear this file ?")) {
fm.data[field.name] = null;
fm.render();
}
}}
/>
</div>
</div>
) : ( ) : (
<></> <></>
)} )}
@ -281,6 +274,80 @@ export const FieldUpload: FC<{
</div> </div>
); );
}; };
const Filename = ({ url }: { url: string }) => {
const file = getFileName(url);
const color = darkenColor(generateRandomColor(file.extension));
return (
<>
<div
className={cx(
css`
border: 1px solid ${color};
color: ${color};
border-radius: 3px;
text-transform: uppercase;
padding: 0px 5px;
font-size: 9px;
height: 15px;
margin-right: 5px;
`,
"c-flex c-items-center"
)}
>
{file.extension}
</div>
<div
className={cx(
css`
font-size: 13px;
`
)}
>
Open in New Tab
</div>
</>
);
};
function darkenColor(color: string, factor: number = 0.5): string {
const rgb = hexToRgb(color);
const r = Math.floor(rgb.r * factor);
const g = Math.floor(rgb.g * factor);
const b = Math.floor(rgb.b * factor);
return rgbToHex(r, g, b);
}
function hexToRgb(hex: string): { r: number; g: number; b: number } {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16),
}
: { r: 0, g: 0, b: 0 };
}
function rgbToHex(r: number, g: number, b: number): string {
return `#${r.toString(16).padStart(2, "0")}${g
.toString(16)
.padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
}
function generateRandomColor(str: string): string {
let hash = 0;
if (str.length === 0) return hash.toString(); // Return a string representation of the hash
for (let i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash;
}
let color = "#";
for (let i = 0; i < 3; i++) {
const value = (hash >> (i * 8)) & 255;
color += ("00" + value.toString(16)).substr(-2);
}
return color;
}
const getFileName = (url: string) => { const getFileName = (url: string) => {
const fileName = url.substring(url.lastIndexOf("/") + 1); const fileName = url.substring(url.lastIndexOf("/") + 1);
const dotIndex = fileName.lastIndexOf("."); const dotIndex = fileName.lastIndexOf(".");

View File

@ -28,7 +28,7 @@ export const on_load_rel = ({
const skip_select = const skip_select =
!isEmptyString(type) && !isEmptyString(type) &&
["checkbox", "typeahead", "button"].includes(type as any); ["checkbox", "typeahead", "button"].includes(type as any);
return `\ return `\
async (arg: { async (arg: {
field: any; field: any;
@ -55,7 +55,7 @@ async (arg: {
ext_select[rel__id_parent] = true; ext_select[rel__id_parent] = true;
} }
const where = await call_prasi_events("field", "relation_load", [fm, arg.field]) || {}; const where = (await call_prasi_events("field", "relation_load", [fm, arg.field]) || {}) as Prisma.${table}WhereInput;
let items = await db.${table}.findMany({ let items = await db.${table}.findMany({
select: { select: {

View File

@ -42,7 +42,7 @@ export const gen_prop_fields = async (gen_table: string, depth?: number) => {
} }
return await loadSchemaLayer( return await loadSchemaLayer(
id_site, id_site,
typeof depth === "undefined" ? 5 : depth, typeof depth === "undefined" ? 4 : depth,
{}, {},
gen_table gen_table
); );
@ -153,8 +153,8 @@ const loadSingle = async (id_site: string, table: string) => {
} }
await Promise.all(pending[table]); await Promise.all(pending[table]);
single[table] = { single[table] = {
cols: await pending[table][0] as any, cols: (await pending[table][0]) as any,
rels: await pending[table][1] as any, rels: (await pending[table][1]) as any,
}; };
await kset(idb_key, single[table]); await kset(idb_key, single[table]);