-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1 parent
a04148d
commit a229018
Showing
30 changed files
with
5,646 additions
and
644 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export default function Metadata({ seoTitle, seoDescription }) { | ||
return ( | ||
<> | ||
<title>{seoTitle}</title> | ||
<meta name="description" content={seoDescription} /> | ||
<meta property="og:image" content="/static/images/typr-og.jpg" /> | ||
<meta property="og:image:width" content="1200" /> | ||
<meta property="og:image:height" content="630" /> | ||
<meta property="og:image:alt" content="Tiptypr Editor Preview" /> | ||
</> | ||
); | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import React, { useEffect } from 'react'; | ||
|
||
const KofiWidget = () => { | ||
useEffect(() => { | ||
const script = document.createElement('script'); | ||
script.src = 'https://storage.ko-fi.com/cdn/scripts/overlay-widget.js'; | ||
script.async = true; | ||
script.onload = () => { | ||
window.kofiWidgetOverlay.draw('prototypr', { | ||
'type': 'floating-chat', | ||
'floating-chat.donateButton.text': 'Tip Me', | ||
'floating-chat.donateButton.background-color': '#00b9fe', | ||
'floating-chat.donateButton.text-color': '#fff' | ||
}); | ||
}; | ||
document.body.appendChild(script); | ||
|
||
return () => { | ||
document.body.removeChild(script); | ||
}; | ||
}, []); | ||
|
||
return null; // This component doesn't render anything visible | ||
}; | ||
|
||
export default KofiWidget; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import React, { useState } from "react"; | ||
import * as Dialog from "@radix-ui/react-dialog"; | ||
import { Cross2Icon } from "@radix-ui/react-icons"; | ||
|
||
const KoFiDialog = ({ color, id, label }) => { | ||
const [isOpen, setIsOpen] = useState(false); | ||
|
||
return ( | ||
<Dialog.Root open={isOpen} onOpenChange={setIsOpen}> | ||
<Dialog.Trigger asChild> | ||
<div | ||
title={label} | ||
className="kofi-button w-fit text-sm hover:shadow-md transition transition-all duration-400 cursor-pointer rounded-lg px-3 h-[28px] flex flex-col justify-center" | ||
style={{ backgroundColor: color }} | ||
onClick={() => setIsOpen(!isOpen)} | ||
> | ||
<div className="kofitext gap-1 flex my-auto items-center"> | ||
<img | ||
src="https://ko-fi.com/img/cup-border.png" | ||
className="kofiimg" | ||
alt="Ko-Fi button" | ||
/> | ||
<div className="flex my-auto text-xs items-center text-white"> | ||
{label} | ||
</div> | ||
</div> | ||
</div> | ||
</Dialog.Trigger> | ||
<Dialog.Portal> | ||
<Dialog.Overlay className="fixed inset-0 bg-black bg-opacity-50 z-[9999]" /> | ||
<Dialog.Content | ||
forceMount={true} | ||
className="fixed w-[400px] h-[712px] overflow-hidden top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white p-0 rounded-xl shadow-lg z-[9999]" | ||
> | ||
<div className="relative w-full h-full"> | ||
<div className="flex flex-col h-full z-10 justify-center items-center kofi-button"> | ||
<div className="gap-1 flex my-auto items-center"> | ||
<div className="flex flex-col gap-2"> | ||
<img | ||
src="https://ko-fi.com/img/cup-border.png" | ||
className="kofiimg !h-[auto] !w-[27px] mx-auto animate-[kofi-wiggle_3s_infinite]" | ||
alt="Ko-Fi button" | ||
/> | ||
<div className="mx-auto text-sm text-gray-600">Loading...</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div className="z-20 absolute top-0 left-0 w-full h-full"> | ||
<iframe | ||
id="kofiframe" | ||
src="https://ko-fi.com/prototypr/?hidefeed=true&widget=true&embed=true&preview=true" | ||
style={{ | ||
border: "none", | ||
width: "100%", | ||
background: "transparent", | ||
}} | ||
height="712" | ||
title="prototypr" | ||
/> | ||
</div> | ||
</div> | ||
<Dialog.Close asChild> | ||
<button className="absolute z-30 top-2 bg-gray-200 right-2 p-1 rounded-full hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200"> | ||
<Cross2Icon className="w-4 h-4 text-gray-500" /> | ||
</button> | ||
</Dialog.Close> | ||
</Dialog.Content> | ||
</Dialog.Portal> | ||
</Dialog.Root> | ||
); | ||
}; | ||
|
||
export default KoFiDialog; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
"use client"; | ||
import { NAV_OFFSET } from "@/lib/constants"; | ||
// import Meta from "../meta"; | ||
import Navbar from "@/components/Navbar/NavbarApp"; | ||
// import { PlausibleProvider } from "next-plausible"; | ||
import { IntlProvider } from "react-intl"; | ||
// import { useRouter } from "next/navigation"; | ||
import { useMemo } from "react"; | ||
import { Inter } from "next/font/google"; | ||
import { getCssText } from "../../stitches.config"; | ||
import Head from "next/head"; | ||
import "../../styles/index.scss"; | ||
|
||
import EN from "locales/en-US"; | ||
import ES from "locales/es-ES"; | ||
const font = Inter({ | ||
// weight: '400', | ||
weight: ["300", "400", "500", "600", "700", "800", "900"], | ||
subsets: ["latin"], | ||
display: "swap", | ||
}); | ||
|
||
export default function Layout({ | ||
preview, | ||
children, | ||
sponsor, | ||
activeNav, | ||
background, | ||
padding, | ||
seo, | ||
navType, | ||
navOffset, | ||
navBackground, | ||
sessionUser | ||
}) { | ||
// const { locale } = useRouter(); | ||
const [shortLocale] = ["en"]; | ||
|
||
const messages = useMemo(() => { | ||
switch (shortLocale) { | ||
case "es": | ||
return ES; | ||
case "en": | ||
return EN; | ||
default: | ||
return EN; | ||
} | ||
}, [shortLocale]); | ||
|
||
// console.log(getCssText()) | ||
return ( | ||
<div className={`${font.className}`}> | ||
{/* <Head> */} | ||
|
||
<Head> | ||
<style | ||
id="stitches" | ||
dangerouslySetInnerHTML={{ __html:getCssText() }} | ||
/> | ||
</Head> | ||
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png"/> | ||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png"/> | ||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png"/> | ||
<link rel="manifest" href="/favicon/site.webmanifest"/> | ||
<meta name="msapplication-TileColor" content="#da532c"/> | ||
<meta name="theme-color" content="#ffffff"/> | ||
{/* </Head> */} | ||
|
||
{/* <PlausibleProvider customDomain="https://analytics.prototypr.io" selfHosted={true} domain="4.prototypr.io"> */} | ||
<IntlProvider | ||
key={"en-US"} | ||
defaultLocale="en-US" | ||
locale={"en-US"} | ||
messages={messages} | ||
> | ||
{/* <Navbar activeNav={activeNav} /> */} | ||
{/* <div className="fixed w-full z-50"> */} | ||
<Navbar | ||
sessionUser={sessionUser} | ||
background={navBackground} | ||
navType={'full'} | ||
sponsor={sponsor} | ||
maxWidth={"calc(100vw-24px)"} | ||
/> | ||
{/* </div> */} | ||
|
||
<div | ||
className={`min-h-screen overflow-hidden`} | ||
style={{ background: background ? background : "#fbfcff" }} | ||
> | ||
<main | ||
className={`mx-auto`} | ||
// style={{ maxWidth: padding == false ? "" : "1200px" }} | ||
> | ||
{children} | ||
</main> | ||
</div> | ||
{/* <Footer /> */} | ||
</IntlProvider> | ||
{/* </PlausibleProvider> */} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import React from "react"; | ||
import * as RadixCheckbox from "@radix-ui/react-checkbox"; | ||
import { CheckIcon } from "@radix-ui/react-icons"; | ||
|
||
const CustomPostStatusesCheckbox = ({ customPostStatuses, onCustomPostStatusesChange }) => ( | ||
<div className="mb-4"> | ||
<label className="block text-sm font-medium text-gray-700 mb-2"> | ||
Custom Post Statuses: | ||
</label> | ||
<RadixCheckbox.Root | ||
checked={customPostStatuses} | ||
onCheckedChange={onCustomPostStatusesChange} | ||
className="w-6 h-6 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500" | ||
> | ||
<RadixCheckbox.Indicator> | ||
<CheckIcon className="w-4 h-4 text-indigo-600" /> | ||
</RadixCheckbox.Indicator> | ||
</RadixCheckbox.Root> | ||
</div> | ||
); | ||
|
||
export default CustomPostStatusesCheckbox; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import React, { useState } from "react"; | ||
import * as Dialog from "@radix-ui/react-dialog"; | ||
|
||
const DemoCodeDialog = ({ isDialogOpen, setIsDialogOpen, demoCode, theme }) => { | ||
const [copyButtonText, setCopyButtonText] = useState("Copy"); | ||
|
||
const copyToClipboard = () => { | ||
navigator.clipboard.writeText(demoCode).then(() => { | ||
setCopyButtonText("Copied!"); | ||
setTimeout(() => { | ||
setCopyButtonText("Copy"); | ||
}, 2000); | ||
}); | ||
}; | ||
|
||
return ( | ||
<Dialog.Root open={isDialogOpen} onOpenChange={setIsDialogOpen}> | ||
<Dialog.Trigger asChild> | ||
<button className="hidden">Open Dialog</button> | ||
</Dialog.Trigger> | ||
<Dialog.Portal> | ||
<Dialog.Overlay className="fixed inset-0 bg-black bg-opacity-50 z-[98]" /> | ||
<Dialog.Content className="fixed m-6 top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white p-6 rounded-md shadow-lg max-w-[680px] w-full z-[9999]"> | ||
<Dialog.Title className="text-lg font-semibold mb-4"> | ||
Demo Code | ||
</Dialog.Title> | ||
<Dialog.Description className="mb-4"> | ||
Here is the demo code with the current props: | ||
</Dialog.Description> | ||
<pre className="bg-gray-100 p-4 h-[500px] max-h-[90%] text-gray-600 rounded-md overflow-auto"> | ||
<code>{demoCode}</code> | ||
</pre> | ||
<div className="mt-4 flex justify-end"> | ||
<button | ||
onClick={copyToClipboard} | ||
className={`py-2 px-4 ${ | ||
theme === "blue" ? "bg-blue-600" : "bg-gray-600" | ||
} text-white rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 ${ | ||
theme === "blue" ? "focus:ring-blue-500" : "focus:ring-gray-500" | ||
} mr-2`} | ||
> | ||
{copyButtonText} | ||
</button> | ||
<Dialog.Close asChild> | ||
<button className="py-2 px-4 bg-transparent border border-gray-300 text-gray-700 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"> | ||
Close | ||
</button> | ||
</Dialog.Close> | ||
</div> | ||
</Dialog.Content> | ||
</Dialog.Portal> | ||
</Dialog.Root> | ||
); | ||
}; | ||
|
||
export default DemoCodeDialog; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React from "react"; | ||
import * as RadixSwitch from "@radix-ui/react-switch"; | ||
|
||
const EnablePublishingFlowCheckbox = ({ enablePublishingFlow, onEnablePublishingFlowChange }) => ( | ||
<div className="flex items-center justify-between w-full"> | ||
<label className="text-sm font-medium text-gray-700">Enable Publishing Flow</label> | ||
<RadixSwitch.Root | ||
checked={enablePublishingFlow} | ||
onCheckedChange={onEnablePublishingFlowChange} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
enablePublishingFlow ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
enablePublishingFlow ? "translate-x-5" : "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</div> | ||
); | ||
|
||
export default EnablePublishingFlowCheckbox; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import React, { useState } from "react"; | ||
import * as Select from "@radix-ui/react-select"; | ||
import { TrashIcon, PlusIcon } from "@radix-ui/react-icons"; | ||
|
||
const GeneralPanel = ({ generalMenu, onValueChange, theme }) => { | ||
const [entries, setEntries] = useState(generalMenu); | ||
|
||
const handleAddEntry = () => { | ||
const newEntries = [ | ||
...entries, | ||
{ type: "", field: "", label: "", initialValue: "" }, | ||
]; | ||
setEntries(newEntries); | ||
onValueChange(newEntries); | ||
}; | ||
|
||
const handleChange = (index, field, value) => { | ||
const newEntries = entries.map((entry, i) => | ||
i === index ? { ...entry, [field]: value } : entry | ||
); | ||
setEntries(newEntries); | ||
onValueChange(newEntries); | ||
}; | ||
|
||
const handleRemoveEntry = (index) => { | ||
if (window.confirm("Are you sure you want to remove this field?")) { | ||
const newEntries = entries.filter((_, i) => i !== index); | ||
setEntries(newEntries); | ||
onValueChange(newEntries); | ||
} | ||
}; | ||
|
||
return ( | ||
<div className="relative flex flex-col gap-3"> | ||
{entries?.length ? | ||
entries.map((entry, index) => ( | ||
<div key={index} className="rounded-lg border border-gray-200 rounded-lg p-3"> | ||
<div className="flex justify-between items-center mb-2"> | ||
<h3 className="block text-sm my-auto font-semibold text-gray-700 "> | ||
Field {index + 1} | ||
{/* {entry.label || "New Entry"} */} | ||
</h3> | ||
<button | ||
onClick={() => handleRemoveEntry(index)} | ||
className="text-red-600 hover:text-red-700 focus:outline-none my-auto" | ||
> | ||
<TrashIcon className="h-4 w-4" /> | ||
</button> | ||
</div> | ||
<div className="flex flex-col gap-2"> | ||
<div className="flex justify-between items-center"> | ||
<label className="block text-sm font-medium text-gray-700">Type</label> | ||
<Select.Root | ||
value={entry.type} | ||
onValueChange={value => { | ||
handleChange(index, "type", value); | ||
}} | ||
> | ||
<Select.Trigger className="w-full max-w-[140px] h-[32px] px-2 text-sm border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 flex items-center"> | ||
<Select.Value placeholder="Choose type" /> | ||
</Select.Trigger> | ||
<Select.Portal avoidCollisions={false}> | ||
<Select.Content className="bg-white border border-gray-300 rounded-md shadow-sm"> | ||
<Select.Viewport> | ||
<Select.Item | ||
value="text" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>text</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="description" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>description</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="number" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>number</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="date" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>date</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="select" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>select</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="url" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>url</Select.ItemText> | ||
</Select.Item> | ||
</Select.Viewport> | ||
</Select.Content> | ||
</Select.Portal> | ||
</Select.Root> | ||
</div> | ||
<div className="flex justify-between items-center"> | ||
<label className="block text-sm font-medium text-gray-700">Field</label> | ||
<input | ||
type="text" | ||
placeholder="Field" | ||
value={entry.field} | ||
onChange={(e) => handleChange(index, "field", e.target.value)} | ||
className="w-full max-w-[140px] h-[32px] px-2 border border-gray-300 text-sm bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 truncate" | ||
/> | ||
</div> | ||
<div className="flex justify-between items-center"> | ||
<label className="block text-sm font-medium text-gray-700">Label</label> | ||
<input | ||
type="text" | ||
placeholder="Label" | ||
value={entry.label} | ||
onChange={(e) => handleChange(index, "label", e.target.value)} | ||
className="w-full max-w-[140px] h-[32px] px-2 border border-gray-300 text-sm bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 truncate" | ||
/> | ||
</div> | ||
{/* <div className="flex justify-between items-center"> | ||
<label className="block text-sm font-medium text-gray-700">Initial Value</label> | ||
<input | ||
type="text" | ||
placeholder="Initial Value" | ||
value={entry.initialValue} | ||
onChange={(e) => handleChange(index, "initialValue", e.target.value)} | ||
className="w-full max-w-[140px] h-[32px] px-2 border border-gray-300 text-sm bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 truncate" | ||
/> | ||
</div> */} | ||
<div className="flex justify-between items-center"> | ||
<label className="block text-sm font-medium text-gray-700">Admin Only</label> | ||
<input | ||
type="checkbox" | ||
checked={entry.adminOnly} | ||
onChange={(e) => handleChange(index, "adminOnly", e.target.checked)} | ||
className="h-4 w-4 text-indigo-600 focus:ring-indigo-500 border-gray-300 rounded" | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
)):null} | ||
<button | ||
onClick={handleAddEntry} | ||
className={`h-[26px] px-3 w-fit text-xs font-medium ${ | ||
theme === 'blue' ? 'bg-blue-600 hover:bg-blue-700 focus:ring-blue-500' : | ||
theme === 'gray' ? 'bg-gray-600 hover:bg-gray-700 focus:ring-gray-500' : | ||
'bg-indigo-600 hover:bg-indigo-700 focus:ring-indigo-500' | ||
} text-white rounded-full shadow-sm focus:outline-none focus:ring-2 flex items-center`} | ||
> | ||
<PlusIcon className="h-4 w-4 mr-1" /> | ||
Add field | ||
</button> | ||
</div> | ||
); | ||
}; | ||
|
||
export default GeneralPanel; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import React, { useState, useEffect } from "react"; | ||
import { openDB } from "idb"; | ||
import { DB_NAME, STORE_NAME } from "@/lib/typr-demo/indexedDB"; // Import the IndexedDB utility | ||
import { TrashIcon } from "@radix-ui/react-icons"; // Import the Radix TrashIcon | ||
import { PlusIcon } from "@radix-ui/react-icons"; // Import the Radix PlusIcon | ||
|
||
const IndexedDBBrowser = ({ data, onDelete, router, searchParams }) => { | ||
const deleteRow = async id => { | ||
// const db = await openDB(DB_NAME, 1); | ||
const db = await openDB(DB_NAME); | ||
const tx = db.transaction(STORE_NAME, "readwrite"); | ||
const store = tx.objectStore(STORE_NAME); | ||
await store.delete(id); | ||
tx.done; | ||
onDelete(); // Fetch data again after deletion | ||
}; | ||
|
||
const handleCreateNew = () => { | ||
router.push("/typr"); | ||
}; | ||
|
||
return ( | ||
<div id="dbbrowser" className="p-4 pt-2 pb-[150px] overflow-y-auto"> | ||
<div className="space-y-4"> | ||
{data.length === 0 ? ( | ||
<p className="text-gray-500 text-center mt-2">No posts found.</p> | ||
) : ( | ||
<> | ||
{data.map(entry => ( | ||
<Card key={entry.id} entry={entry} router={router} searchParams={searchParams} onDelete={deleteRow} /> | ||
))} | ||
<div | ||
className="bg-gradient-to-b group from-slate-100 transition transition-all duration-600 to-slate-50 hover:shadow border border-dotted border-gray-300/70 rounded-lg p-2 mb-4 relative group cursor-pointer flex items-center justify-center" | ||
onClick={handleCreateNew} | ||
> | ||
<PlusIcon className="text-gray-500" /> | ||
<span className="ml-2 text-sm group-hover:text-gray-800 text-gray-500">Start New</span> | ||
</div> | ||
</> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default IndexedDBBrowser; | ||
|
||
const Card = ({ entry, onDelete, router, searchParams }) => { | ||
const { id, versioned_title, title, versioned_content, content } = entry; | ||
const [displayTitle, setDisplayTitle] = useState(versioned_title || title); | ||
const [displayContent, setDisplayContent] = useState( | ||
versioned_content || content | ||
); | ||
|
||
useEffect(() => { | ||
setDisplayTitle(versioned_title || title); | ||
setDisplayContent(versioned_content || content); | ||
}, [versioned_title, title, versioned_content, content]); | ||
|
||
const handleClick = () => { | ||
const params = new URLSearchParams(searchParams); | ||
params.set("id", id); | ||
router.push(`?${params.toString()}`, undefined, { | ||
shallow: false, | ||
scroll: false, | ||
}); | ||
}; | ||
|
||
const currentId = new URLSearchParams(searchParams).get("id"); | ||
const isActive = currentId === id.toString(); | ||
|
||
return ( | ||
<div | ||
className={`bg-gradient-to-b from-slate-100 transition transition-all duration-600 to-slate-50 hover:shadow border border-gray-300/70 rounded-lg p-2 mb-4 relative group hover:from-white hover:to-white cursor-pointer ${isActive ? 'border-gray-500 from-white to-white' : ''}`} | ||
onClick={handleClick} | ||
> | ||
<div className="flex justify-between items-start"> | ||
<h2 className="text-base p-1 font-bold text-wrap line-clamp-2 truncate"> | ||
{displayTitle} | ||
</h2> | ||
<button | ||
onClick={e => { | ||
e.stopPropagation(); | ||
onDelete(id); | ||
}} | ||
className="text-gray-500 h-6 w-6 hover:bg-slate-200 rounded-lg hover:text-red-500 ml-2 hidden group-hover:flex items-center justify-center" | ||
> | ||
<TrashIcon /> | ||
</button> | ||
</div> | ||
<div className="p-1"> | ||
<div | ||
className="text-gray-700 mb-2 truncate line-clamp-2 truncate text-wrap text-xs" | ||
dangerouslySetInnerHTML={{ __html: `${displayContent}` }} | ||
></div> | ||
<p className="text-gray-500 text-[11px] mt-3">#{id}</p> | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
import React from "react"; | ||
import * as Select from "@radix-ui/react-select"; | ||
import * as RadixSwitch from "@radix-ui/react-switch"; | ||
|
||
const NavSettings = ({ nav, onNavChange, avatarOptions }) => ( | ||
<div className="mb-4 flex flex-col gap-4"> | ||
<div className="flex items-center justify-between w-full"> | ||
<label className="text-sm font-medium text-gray-700 my-auto"> | ||
Show Nav | ||
</label> | ||
<RadixSwitch.Root | ||
checked={nav.show} | ||
onCheckedChange={checked => onNavChange({ ...nav, show: checked })} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
nav.show ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
nav.show ? "translate-x-5" : "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</div> | ||
|
||
<div className="flex flex-row justify-between"> | ||
<label className="block text-sm font-medium text-gray-700 my-auto"> | ||
Avatar Placeholder | ||
</label> | ||
<Select.Root | ||
value={nav.userBadge.avatarPlaceholder} | ||
onValueChange={value => | ||
onNavChange({ | ||
...nav, | ||
userBadge: { ...nav.userBadge, avatarPlaceholder: value }, | ||
}) | ||
} | ||
> | ||
<Select.Trigger className="max-w-[110px] truncate text-nowrap overflow-hidden h-[32px] px-2 pl-1 text-sm border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 flex items-center"> | ||
<img | ||
src={nav.userBadge.avatarPlaceholder} | ||
alt="Avatar" | ||
className="w-6 h-6 border border-gray-300 flex-none rounded-full object-contain mr-1.5" | ||
/> | ||
<Select.Value placeholder="Select an avatar" /> | ||
</Select.Trigger> | ||
<Select.Portal> | ||
<Select.Content className="bg-white border border-gray-300 rounded-md shadow-sm"> | ||
<Select.Viewport> | ||
{avatarOptions.map(({ name, imgSrc }) => ( | ||
<Select.Item | ||
key={name} | ||
value={imgSrc} | ||
className="h-[32px] px-2 text-sm hover:bg-gray-100 cursor-pointer flex items-center" | ||
> | ||
<img | ||
src={imgSrc} | ||
alt="Avatar" | ||
className="w-6 h-6 border border-gray-300 rounded-full mr-2 object-contain" | ||
/> | ||
<Select.ItemText className="truncate text-nowrap overflow-hidden"> | ||
{name ? name : "Avatartion"} | ||
</Select.ItemText> | ||
</Select.Item> | ||
))} | ||
</Select.Viewport> | ||
</Select.Content> | ||
</Select.Portal> | ||
</Select.Root> | ||
</div> | ||
|
||
<div className="flex flex-row justify-between"> | ||
<label className="block my-auto text-sm font-medium text-gray-700 mb-2"> | ||
Nav Position | ||
</label> | ||
<Select.Root | ||
value={nav.position} | ||
onValueChange={value => onNavChange({ ...nav, position: value })} | ||
> | ||
<Select.Trigger className="w-full max-w-[110px] truncate text-nowrap overflow-hidden h-[32px] px-2 text-sm border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 flex items-center"> | ||
<Select.Value /> | ||
</Select.Trigger> | ||
<Select.Portal> | ||
<Select.Content className="bg-white border border-gray-300 rounded-md shadow-sm"> | ||
<Select.Viewport> | ||
<Select.Item | ||
value="sticky" | ||
className="h-[32px] px-2 text-sm hover:bg-gray-100 cursor-pointer flex items-center" | ||
> | ||
<Select.ItemText>Sticky</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="relative" | ||
className="h-[32px] px-2 text-sm hover:bg-gray-100 cursor-pointer flex items-center" | ||
> | ||
<Select.ItemText>Relative</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="fixed" | ||
className="h-[32px] px-2 text-sm hover:bg-gray-100 cursor-pointer flex items-center" | ||
> | ||
<Select.ItemText>Fixed</Select.ItemText> | ||
</Select.Item> | ||
</Select.Viewport> | ||
</Select.Content> | ||
</Select.Portal> | ||
</Select.Root> | ||
</div> | ||
|
||
<div className="flex flex-row justify-between"> | ||
<label className="block my-auto text-sm font-medium text-gray-700 mb-2"> | ||
Logo URL | ||
</label> | ||
<div className="relative"> | ||
<input | ||
type="text" | ||
value={nav.logo.url} | ||
onChange={e => | ||
onNavChange({ ...nav, logo: { image: e.target.value, ...nav.url } }) | ||
} | ||
className="w-full pl-[26px] pr-2 max-w-[110px] truncate text-nowrap overflow-hidden h-[32px] text-sm border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500" | ||
/> | ||
{nav.logo.url?.length > 2 ? ( | ||
<img | ||
src={nav.logo.url} | ||
alt="Logo" | ||
className="absolute left-1 top-1/2 transform -translate-y-1/2 w-5 h-5 border border-gray-300 rounded-sm object-contain" | ||
/> | ||
) : ( | ||
<svg | ||
className={"absolute left-1 top-1/2 transform -translate-y-1/2 w-5 h-5"} | ||
width="164" | ||
height="164" | ||
viewBox="0 0 164 164" | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
> | ||
<g clip-path="url(#clip0_1_12)"> | ||
<rect width="164" height="164" fill="white" /> | ||
<rect | ||
x="6" | ||
y="6" | ||
width="152" | ||
height="152" | ||
rx="6" | ||
stroke="black" | ||
stroke-width="12" | ||
/> | ||
<path | ||
d="M111.138 45.058L89.022 45.446V121.688L104.736 124.986C104.736 128.995 103.637 131 101.438 131L82.62 129.836L63.414 131C60.9567 131 59.728 128.995 59.728 124.986L75.442 121.688V45.446L53.52 45.058L51.58 58.638C51.58 60.578 48.9933 61.548 43.82 61.548L41.88 38.656C42.1387 36.9747 44.0787 36.134 47.7 36.134L82.62 36.91L116.958 36.134C120.579 36.134 122.519 36.9747 122.778 38.656L120.838 61.548C115.665 61.548 113.078 60.578 113.078 58.638L111.138 45.058Z" | ||
fill="black" | ||
/> | ||
</g> | ||
<defs> | ||
<clipPath id="clip0_1_12"> | ||
<rect width="164" height="164" fill="white" /> | ||
</clipPath> | ||
</defs> | ||
</svg> | ||
)} | ||
</div> | ||
</div> | ||
<div className="flex items-center justify-between w-full"> | ||
<label className="text-sm my-auto font-medium text-gray-700"> | ||
Undo/Redo Buttons | ||
</label> | ||
<RadixSwitch.Root | ||
checked={nav.undoRedoButtons.show} | ||
onCheckedChange={checked => | ||
onNavChange({ | ||
...nav, | ||
undoRedoButtons: { ...nav.undoRedoButtons, show: checked }, | ||
}) | ||
} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
nav.undoRedoButtons.show ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
nav.undoRedoButtons.show ? "translate-x-5" : "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</div> | ||
|
||
<div className="flex items-center justify-between w-full"> | ||
<label className="text-sm my-auto font-medium text-gray-700"> | ||
Publish status | ||
</label> | ||
<RadixSwitch.Root | ||
checked={nav.postStatus.show} | ||
onCheckedChange={checked => | ||
onNavChange({ | ||
...nav, | ||
postStatus: { | ||
...nav.postStatus, | ||
show: checked, | ||
}, | ||
}) | ||
} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
nav.postStatus.show ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
nav.postStatus.show ? "translate-x-5" : "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</div> | ||
|
||
<div className="flex items-center justify-between w-full"> | ||
<label className="text-sm my-auto font-medium text-gray-700"> | ||
User Badge | ||
</label> | ||
<RadixSwitch.Root | ||
checked={nav.userBadge.show} | ||
onCheckedChange={checked => | ||
onNavChange({ | ||
...nav, | ||
userBadge: { ...nav.userBadge, show: checked }, | ||
}) | ||
} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
nav.userBadge.show ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
nav.userBadge.show ? "translate-x-5" : "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</div> | ||
</div> | ||
); | ||
|
||
export default NavSettings; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import React from "react"; | ||
import * as RadixSwitch from "@radix-ui/react-switch"; | ||
|
||
const RequireLoginCheckbox = ({ requireLogin, onRequireLoginChange }) => ( | ||
<div className="flex items-center justify-between w-full"> | ||
<label className="text-sm font-medium text-gray-700">Require Login</label> | ||
<RadixSwitch.Root | ||
checked={requireLogin} | ||
onCheckedChange={onRequireLoginChange} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
requireLogin ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
requireLogin ? "translate-x-5" : "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</div> | ||
); | ||
|
||
export default RequireLoginCheckbox; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
import React, { useState } from "react"; | ||
import * as Select from "@radix-ui/react-select"; | ||
import { TrashIcon, PlusIcon } from "@radix-ui/react-icons"; | ||
|
||
const SeoPanel = ({ seoMenu, onValueChange, theme }) => { | ||
const [entries, setEntries] = useState(seoMenu); | ||
|
||
const handleAddEntry = () => { | ||
const newEntries = [ | ||
...entries, | ||
{ type: "", field: "", label: "", initialValue: "" }, | ||
]; | ||
setEntries(newEntries); | ||
onValueChange(newEntries); | ||
}; | ||
|
||
const handleChange = (index, field, value) => { | ||
const newEntries = entries.map((entry, i) => | ||
i === index ? { ...entry, [field]: value } : entry | ||
); | ||
setEntries(newEntries); | ||
onValueChange(newEntries); | ||
}; | ||
|
||
const handleRemoveEntry = index => { | ||
if (window.confirm("Are you sure you want to remove this field?")) { | ||
const newEntries = entries.filter((_, i) => i !== index); | ||
setEntries(newEntries); | ||
onValueChange(newEntries); | ||
} | ||
}; | ||
|
||
return ( | ||
<div className="relative flex flex-col gap-3"> | ||
{entries?.length | ||
? entries.map((entry, index) => ( | ||
<div | ||
key={index} | ||
className="rounded-lg border border-gray-200 rounded-lg p-3" | ||
> | ||
<div className="flex justify-between items-center mb-2"> | ||
<h3 className="block text-sm my-auto font-semibold text-gray-700 "> | ||
Field {index + 1} | ||
{/* {entry.label || "New Entry"} */} | ||
</h3> | ||
<button | ||
onClick={() => handleRemoveEntry(index)} | ||
className="text-red-600 hover:text-red-700 focus:outline-none my-auto" | ||
> | ||
<TrashIcon className="h-4 w-4" /> | ||
</button> | ||
</div> | ||
<div className="flex flex-col gap-2"> | ||
<div className="flex justify-between items-center"> | ||
<label className="block text-sm font-medium text-gray-700">Type</label> | ||
<Select.Root | ||
value={entry.type} | ||
onValueChange={value => { | ||
handleChange(index, "type", value); | ||
}} | ||
> | ||
<Select.Trigger className="w-full max-w-[140px] h-[32px] px-2 text-sm border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 flex items-center"> | ||
<Select.Value placeholder="Choose type" /> | ||
</Select.Trigger> | ||
<Select.Portal avoidCollisions={false}> | ||
<Select.Content className="bg-white border border-gray-300 rounded-md shadow-sm"> | ||
<Select.Viewport> | ||
<Select.Item | ||
value="text" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>text</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="description" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>description</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="number" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>number</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="date" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>date</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="select" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>select</Select.ItemText> | ||
</Select.Item> | ||
<Select.Item | ||
value="url" | ||
className="h-[32px] text-xs px-2 cursor-pointer hover:bg-gray-100 focus:bg-gray-200 flex flex-col justify-center" | ||
> | ||
<Select.ItemText>url</Select.ItemText> | ||
</Select.Item> | ||
</Select.Viewport> | ||
</Select.Content> | ||
</Select.Portal> | ||
</Select.Root> | ||
</div> | ||
<div className="flex justify-between items-center"> | ||
<label className="block text-sm font-medium text-gray-700">Field</label> | ||
<input | ||
type="text" | ||
placeholder="Field" | ||
value={entry.field} | ||
onChange={e => handleChange(index, "field", e.target.value)} | ||
className="w-full max-w-[140px] h-[32px] px-2 border border-gray-300 text-sm bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 truncate" | ||
/> | ||
</div> | ||
<div className="flex justify-between items-center"> | ||
<label className="block text-sm font-medium text-gray-700">Label</label> | ||
<input | ||
type="text" | ||
placeholder="Label" | ||
value={entry.label} | ||
onChange={e => handleChange(index, "label", e.target.value)} | ||
className="w-full max-w-[140px] h-[32px] px-2 border border-gray-300 text-sm bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 truncate" | ||
/> | ||
</div> | ||
{/* <div className="flex justify-between items-center"> | ||
<label className="block text-sm font-medium text-gray-700">Initial Value</label> | ||
<input | ||
type="text" | ||
placeholder="Initial Value" | ||
value={entry.initialValue} | ||
onChange={e => handleChange(index, "initialValue", e.target.value)} | ||
className="w-full max-w-[140px] h-[32px] px-2 border border-gray-300 text-sm bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 truncate" | ||
/> | ||
</div> */} | ||
</div> | ||
</div> | ||
)) | ||
: null} | ||
<button | ||
onClick={handleAddEntry} | ||
className={`h-[26px] px-3 w-fit text-xs font-medium ${ | ||
theme === "blue" | ||
? "bg-blue-600 hover:bg-blue-700 focus:ring-blue-500" | ||
: theme === "gray" | ||
? "bg-gray-600 hover:bg-gray-700 focus:ring-gray-500" | ||
: "bg-indigo-600 hover:bg-indigo-700 focus:ring-indigo-500" | ||
} text-white rounded-full shadow-sm focus:outline-none focus:ring-2 flex items-center`} | ||
> | ||
<PlusIcon className="h-4 w-4 mr-1" /> | ||
Add field | ||
</button> | ||
</div> | ||
); | ||
}; | ||
|
||
export default SeoPanel; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import React from "react"; | ||
import * as Dialog from "@radix-ui/react-dialog"; | ||
import * as RadixSwitch from "@radix-ui/react-switch"; | ||
|
||
const SimulatorDialog = ({ isOpen, onOpenChange, simulatorSettings, onSimulatorChange }) => ( | ||
<Dialog.Root open={isOpen} onOpenChange={onOpenChange}> | ||
<Dialog.Portal> | ||
<Dialog.Overlay className="fixed inset-0 bg-black bg-opacity-30 z-[999]" /> | ||
<Dialog.Content className="z-[9999] fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white p-6 rounded-lg shadow-lg"> | ||
<Dialog.Title className="text-lg font-medium">Simulator Settings</Dialog.Title> | ||
<div className="mt-4 flex flex-col gap-4"> | ||
<div className="flex items-center justify-between w-full"> | ||
<label className="text-sm font-medium text-gray-700">Simulate onSave</label> | ||
<RadixSwitch.Root | ||
checked={simulatorSettings.onSave} | ||
onCheckedChange={checked => onSimulatorChange({ ...simulatorSettings, onSave: checked })} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
simulatorSettings.onSave ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
simulatorSettings.onSave ? "translate-x-5" : "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</div> | ||
<div className="flex items-center justify-between w-full"> | ||
<label className="text-sm font-medium text-gray-700">Simulate onCreate</label> | ||
<RadixSwitch.Root | ||
checked={simulatorSettings.onCreate} | ||
onCheckedChange={checked => onSimulatorChange({ ...simulatorSettings, onCreate: checked })} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
simulatorSettings.onCreate ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
simulatorSettings.onCreate ? "translate-x-5" : "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</div> | ||
<div className="flex items-center justify-between w-full"> | ||
<label className="text-sm font-medium text-gray-700">Simulate onPublish</label> | ||
<RadixSwitch.Root | ||
checked={simulatorSettings.onPublish} | ||
onCheckedChange={checked => onSimulatorChange({ ...simulatorSettings, onPublish: checked })} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
simulatorSettings.onPublish ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
simulatorSettings.onPublish ? "translate-x-5" : "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</div> | ||
</div> | ||
<Dialog.Close className="absolute top-2 right-2">X</Dialog.Close> | ||
</Dialog.Content> | ||
</Dialog.Portal> | ||
</Dialog.Root> | ||
); | ||
|
||
export default SimulatorDialog; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import React from "react"; | ||
import * as ToggleGroup from "@radix-ui/react-toggle-group"; | ||
|
||
const ThemeSelector = ({ theme, onThemeChange, themeOptions }) => ( | ||
<div className="flex flex-row justify-between"> | ||
<label className="block text-sm font-medium text-gray-700"> | ||
Theme | ||
</label> | ||
<ToggleGroup.Root | ||
type="single" | ||
value={theme} | ||
onValueChange={onThemeChange} | ||
className="flex space-x-2" | ||
> | ||
{themeOptions.map(option => ( | ||
<ToggleGroup.Item | ||
key={option.value} | ||
value={option.value} | ||
className={`w-6 h-6 rounded-full ${option.value=='blue' ? 'bg-blue-600': option.value=='gray'?'bg-gray-400':''} ${theme === option.value ? 'border border-2 border-blue-400 shadow-lg' : ''}`} | ||
/> | ||
))} | ||
</ToggleGroup.Root> | ||
</div> | ||
); | ||
|
||
export default ThemeSelector; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import React, { useState, useEffect } from "react"; | ||
import * as Popover from "@radix-ui/react-popover"; | ||
import * as RadixSwitch from "@radix-ui/react-switch"; | ||
|
||
export default function UserPopover({ editorProps, handleUserChange }) { | ||
const [open, setOpen] = useState(true); | ||
|
||
const toggleOpen = isOpen => { | ||
if (open !== isOpen) { | ||
setOpen(isOpen); | ||
} | ||
}; | ||
|
||
return ( | ||
<Popover.Root open={open} onOpenChange={toggleOpen}> | ||
<Popover.Trigger asChild> | ||
<button className="absolute bottom-12 right-4 md:right-12 md:bottom-6 md:right-6 z-[999] shadow-lg rounded-full overflow-hidden"> | ||
<img | ||
src={editorProps?.components?.nav?.userBadge?.avatarPlaceholder} | ||
alt="User Avatar" | ||
className="w-14 h-14 rounded-full bg-white object-contain border border-gray-300" | ||
/> | ||
</button> | ||
</Popover.Trigger> | ||
<Popover.Content | ||
onFocusOutside={e => e.preventDefault()} | ||
onInteractOutside={e => e.preventDefault()} | ||
className="p-4 mb-2 mr-3 bg-white rounded shadow-md z-[999] min-w-[200px]" | ||
> | ||
<h3 className="mb-4 tracking-tight font-medium">User state</h3> | ||
<div className="flex flex-col space-y-4"> | ||
<label className="flex items-center justify-between"> | ||
<div className="text-sm text-gray-600">Logged In</div> | ||
<RadixSwitch.Root | ||
checked={editorProps?.user?.isLoggedIn} | ||
onCheckedChange={checked => | ||
handleUserChange("isLoggedIn", checked) | ||
} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
editorProps?.user?.isLoggedIn ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
editorProps?.user?.isLoggedIn | ||
? "translate-x-5" | ||
: "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</label> | ||
<label className="flex items-center justify-between"> | ||
<div className="text-sm text-gray-600">Admin</div> | ||
<RadixSwitch.Root | ||
checked={editorProps?.user?.isAdmin} | ||
onCheckedChange={checked => handleUserChange("isAdmin", checked)} | ||
className={`w-10 h-5 rounded-full relative shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 ${ | ||
editorProps?.user?.isAdmin ? "bg-blue-500/90" : "bg-gray-300" | ||
}`} | ||
> | ||
<RadixSwitch.Thumb | ||
className={`block w-4 h-4 bg-white rounded-full shadow-md transform transition-transform ${ | ||
editorProps?.user?.isAdmin ? "translate-x-5" : "translate-x-1" | ||
}`} | ||
/> | ||
</RadixSwitch.Root> | ||
</label> | ||
{/* <label> | ||
Username: | ||
<input | ||
type="text" | ||
value={editorProps.user.username || ""} | ||
onChange={e => handleUserChange("username", e.target.value)} | ||
className="w-full h-[32px] px-2 text-sm border border-gray-300 bg-white rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500" | ||
/> | ||
</label> */} | ||
</div> | ||
</Popover.Content> | ||
</Popover.Root> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import React from 'react' | ||
// Custom deep merge function | ||
export function customDeepMerge(target, source) { | ||
if (typeof source !== "object" || source === null) { | ||
return source; | ||
} | ||
|
||
const output = Array.isArray(target) ? [...target] : { ...target }; | ||
|
||
if (Array.isArray(target) && Array.isArray(source)) { | ||
return [...source]; | ||
} | ||
|
||
Object.keys(source).forEach(key => { | ||
if (source[key] !== undefined) { | ||
if ( | ||
typeof source[key] === "object" && | ||
!React.isValidElement(source[key]) && | ||
key in target && | ||
typeof target[key] === "object" | ||
) { | ||
output[key] = customDeepMerge(target[key], source[key]); | ||
} else { | ||
output[key] = source[key]; | ||
} | ||
} | ||
}); | ||
|
||
return output; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
export const DB_NAME = 'DemoTyprDB'; | ||
// export const DB_VERSION = 1; | ||
export const STORE_NAME = 'posts'; | ||
|
||
export const openDB = () => { | ||
return new Promise((resolve, reject) => { | ||
const request = indexedDB.open(DB_NAME); | ||
|
||
request.onupgradeneeded = (event) => { | ||
const db = event.target.result; | ||
if (!db.objectStoreNames.contains(STORE_NAME)) { | ||
db.createObjectStore(STORE_NAME, { keyPath: 'id', autoIncrement: true }); | ||
} | ||
}; | ||
|
||
request.onsuccess = (event) => { | ||
const db = event.target.result; | ||
// Check if the object store exists, if not, close and reopen with a new version | ||
if (!db.objectStoreNames.contains(STORE_NAME)) { | ||
const currentVersion = db.version; | ||
db.close(); | ||
const reopenRequest = indexedDB.open(DB_NAME, currentVersion + 1); | ||
reopenRequest.onupgradeneeded = (event) => { | ||
const db = event.target.result; | ||
db.createObjectStore(STORE_NAME, { keyPath: 'id', autoIncrement: true }); | ||
}; | ||
reopenRequest.onsuccess = (event) => { | ||
resolve(event.target.result); | ||
}; | ||
reopenRequest.onerror = (event) => { | ||
reject(event.target.error); | ||
}; | ||
} else { | ||
resolve(db); | ||
} | ||
}; | ||
|
||
request.onerror = (event) => { | ||
reject(event.target.error); | ||
}; | ||
}); | ||
}; | ||
|
||
export const savePost = async (post, id) => { | ||
const db = await openDB(); | ||
return new Promise((resolve, reject) => { | ||
const transaction = db.transaction([STORE_NAME], 'readwrite'); | ||
const store = transaction.objectStore(STORE_NAME); | ||
|
||
// Add the id to the post object if provided | ||
if (id !== undefined) { | ||
post.id = id; | ||
} | ||
|
||
const request = store.put(post); // Use put instead of add | ||
|
||
request.onsuccess = async () => { | ||
try { | ||
const savedPost = await loadPostById(request.result); | ||
resolve(savedPost); | ||
} catch (error) { | ||
reject(error); | ||
} | ||
}; | ||
|
||
request.onerror = (event) => { | ||
reject(event.target.error); | ||
}; | ||
}); | ||
}; | ||
|
||
export const loadPosts = async () => { | ||
const db = await openDB(); | ||
return new Promise((resolve, reject) => { | ||
const transaction = db.transaction([STORE_NAME], 'readonly'); | ||
const store = transaction.objectStore(STORE_NAME); | ||
const request = store.getAll(); | ||
|
||
request.onsuccess = () => { | ||
resolve(request.result); | ||
}; | ||
|
||
request.onerror = (event) => { | ||
reject(event.target.error); | ||
}; | ||
}); | ||
}; | ||
|
||
export const createPost = async (post) => { | ||
return savePost(post); | ||
}; | ||
|
||
export const loadPostById = async (id) => { | ||
const db = await openDB(); | ||
return new Promise((resolve, reject) => { | ||
const transaction = db.transaction([STORE_NAME], 'readonly'); | ||
const store = transaction.objectStore(STORE_NAME); | ||
const request = store.get(id); | ||
|
||
|
||
request.onsuccess = () => { | ||
resolve(request.result); | ||
}; | ||
|
||
request.onerror = (event) => { | ||
reject(event.target.error); | ||
}; | ||
}); | ||
}; |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters