mirror of
https://github.com/severian-dev/sucker.severian.dev.git
synced 2026-01-06 15:32:23 +00:00
Merge pull request #7 from chill-protocol/webp-link
Option for webp file name or character image URL inputs
This commit is contained in:
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/types/routes.d.ts";
|
import "./.next/dev/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
9
package-lock.json
generated
9
package-lock.json
generated
@@ -1296,6 +1296,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
||||||
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
}
|
}
|
||||||
@@ -1305,6 +1306,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
|
||||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
}
|
}
|
||||||
@@ -1464,6 +1466,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@@ -2075,6 +2078,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
||||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
@@ -2372,6 +2376,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.11",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@@ -2540,6 +2545,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz",
|
||||||
"integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
|
"integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -2549,6 +2555,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz",
|
||||||
"integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==",
|
"integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
@@ -2844,6 +2851,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.18.tgz",
|
||||||
"integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==",
|
"integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@alloc/quick-lru": "^5.2.0",
|
"@alloc/quick-lru": "^5.2.0",
|
||||||
"arg": "^5.0.2",
|
"arg": "^5.0.2",
|
||||||
@@ -2953,6 +2961,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
|
|||||||
343
src/app/page.tsx
343
src/app/page.tsx
@@ -258,12 +258,11 @@ export default function Home() {
|
|||||||
const cardData = JSON.stringify(pngData);
|
const cardData = JSON.stringify(pngData);
|
||||||
|
|
||||||
const newImageData = Png.Generate(arrayBuffer, cardData);
|
const newImageData = Png.Generate(arrayBuffer, cardData);
|
||||||
const newFileName = `${
|
const newFileName = `${(card.initialVersion?.name || card.data.name).replace(
|
||||||
(card.initialVersion?.name || card.data.name).replace(
|
/[^a-zA-Z0-9\-_]/g,
|
||||||
/[^a-zA-Z0-9\-_]/g,
|
"_"
|
||||||
"_"
|
) || "character"
|
||||||
) || "character"
|
}.png`;
|
||||||
}.png`;
|
|
||||||
const newFile = new File([new Uint8Array(newImageData)], newFileName, {
|
const newFile = new File([new Uint8Array(newImageData)], newFileName, {
|
||||||
type: "image/png",
|
type: "image/png",
|
||||||
});
|
});
|
||||||
@@ -290,14 +289,44 @@ export default function Home() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleOpenMetadata = () => {
|
const handleOpenMetadata = () => {
|
||||||
const match = characterUrl.match(/characters\/([\w-]+)/);
|
// Check if the input is a character metadata URL (janitorai.com/characters/...)
|
||||||
if (match && match[1]) {
|
const isCharacterUrl = /janitorai\.com\/characters\//.test(characterUrl);
|
||||||
const characterId = match[1].split("_")[0];
|
|
||||||
window.open(
|
if (isCharacterUrl) {
|
||||||
`https://janitorai.com/hampter/characters/${characterId}`,
|
// Extract character ID and open metadata page, then show second input
|
||||||
"_blank"
|
const match = characterUrl.match(/characters\/([\w-]+)/);
|
||||||
);
|
if (match && match[1]) {
|
||||||
setIsMetadataOpen(true);
|
const characterId = match[1].split("_")[0];
|
||||||
|
window.open(
|
||||||
|
`https://janitorai.com/hampter/characters/${characterId}`,
|
||||||
|
"_blank"
|
||||||
|
);
|
||||||
|
setIsMetadataOpen(true);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the input is a direct image link (webp filename or full image URL)
|
||||||
|
const isImagePath = /\.(webp|png|jpg|jpeg|gif)(\?.*)?$/i.test(characterUrl);
|
||||||
|
const isFullImageUrl = (characterUrl.startsWith("http://") || characterUrl.startsWith("https://")) && isImagePath;
|
||||||
|
const isWebpFilename = /^[\w-]+\.(webp|png|jpg|jpeg|gif)$/i.test(characterUrl);
|
||||||
|
|
||||||
|
if (isFullImageUrl || isWebpFilename) {
|
||||||
|
// Directly set the avatar URL without opening metadata
|
||||||
|
if (selectedCardIndex === null) return;
|
||||||
|
|
||||||
|
const avatarUrl = isFullImageUrl
|
||||||
|
? characterUrl
|
||||||
|
: `https://ella.janitorai.com/bot-avatars/${characterUrl}`;
|
||||||
|
|
||||||
|
const updatedCards = [...cards];
|
||||||
|
updatedCards[selectedCardIndex] = {
|
||||||
|
...updatedCards[selectedCardIndex],
|
||||||
|
avatarUrl,
|
||||||
|
};
|
||||||
|
setCards(updatedCards);
|
||||||
|
setDialogOpen(false);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -588,71 +617,70 @@ export default function Home() {
|
|||||||
<div id={`card-${index}`} className="space-y-4 mt-4">
|
<div id={`card-${index}`} className="space-y-4 mt-4">
|
||||||
{(card.initialVersion?.description ||
|
{(card.initialVersion?.description ||
|
||||||
card.data?.description) && (
|
card.data?.description) && (
|
||||||
<Accordion type="single" collapsible>
|
<Accordion type="single" collapsible>
|
||||||
<AccordionItem value="description">
|
<AccordionItem value="description">
|
||||||
<AccordionTrigger>Description</AccordionTrigger>
|
<AccordionTrigger>Description</AccordionTrigger>
|
||||||
<AccordionContent>
|
<AccordionContent>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<pre className="whitespace-pre-wrap font-sans text-sm">
|
<pre className="whitespace-pre-wrap font-sans text-sm">
|
||||||
{card.initialVersion?.description ||
|
{card.initialVersion?.description ||
|
||||||
card.data.description}
|
card.data.description}
|
||||||
</pre>
|
</pre>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
copyToClipboard(
|
copyToClipboard(
|
||||||
card.initialVersion?.description ||
|
card.initialVersion?.description ||
|
||||||
card.data.description
|
card.data.description
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Copy className="h-4 w-4" />
|
<Copy className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
)}
|
)}
|
||||||
{(card.initialVersion?.first_mes ||
|
{(card.initialVersion?.first_mes ||
|
||||||
card.data?.first_mes) && (
|
card.data?.first_mes) && (
|
||||||
<Accordion type="single" collapsible>
|
<Accordion type="single" collapsible>
|
||||||
<AccordionItem value="first-message">
|
<AccordionItem value="first-message">
|
||||||
<AccordionTrigger>
|
<AccordionTrigger>
|
||||||
First Message
|
First Message
|
||||||
</AccordionTrigger>
|
</AccordionTrigger>
|
||||||
<AccordionContent>
|
<AccordionContent>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<pre className="whitespace-pre-wrap font-sans text-sm">
|
<pre className="whitespace-pre-wrap font-sans text-sm">
|
||||||
{card.initialVersion?.first_mes ||
|
{card.initialVersion?.first_mes ||
|
||||||
card.data.first_mes}
|
card.data.first_mes}
|
||||||
</pre>
|
</pre>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
copyToClipboard(
|
copyToClipboard(
|
||||||
card.initialVersion?.first_mes ||
|
card.initialVersion?.first_mes ||
|
||||||
card.data.first_mes
|
card.data.first_mes
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Copy className="h-4 w-4" />
|
<Copy className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
)}
|
)}
|
||||||
{card.alternate_greetings &&
|
{card.alternate_greetings &&
|
||||||
card.alternate_greetings.length > 0 && (
|
card.alternate_greetings.length > 0 && (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<h4 className="font-medium">{`Alternate Greetings (${
|
<h4 className="font-medium">{`Alternate Greetings (${card.alternate_greetings?.length || 0
|
||||||
card.alternate_greetings?.length || 0
|
})`}</h4>
|
||||||
})`}</h4>
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@@ -721,93 +749,93 @@ export default function Home() {
|
|||||||
)}
|
)}
|
||||||
{(card.initialVersion?.scenario ||
|
{(card.initialVersion?.scenario ||
|
||||||
card.data?.scenario) && (
|
card.data?.scenario) && (
|
||||||
<Accordion type="single" collapsible>
|
<Accordion type="single" collapsible>
|
||||||
<AccordionItem value="scenario">
|
<AccordionItem value="scenario">
|
||||||
<AccordionTrigger>Scenario</AccordionTrigger>
|
<AccordionTrigger>Scenario</AccordionTrigger>
|
||||||
<AccordionContent>
|
<AccordionContent>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<pre className="whitespace-pre-wrap font-sans text-sm">
|
<pre className="whitespace-pre-wrap font-sans text-sm">
|
||||||
{card.initialVersion?.scenario ||
|
{card.initialVersion?.scenario ||
|
||||||
card.data.scenario}
|
card.data.scenario}
|
||||||
</pre>
|
</pre>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
copyToClipboard(
|
copyToClipboard(
|
||||||
card.initialVersion?.scenario ||
|
card.initialVersion?.scenario ||
|
||||||
card.data.scenario
|
card.data.scenario
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Copy className="h-4 w-4" />
|
<Copy className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
)}
|
)}
|
||||||
{(card.initialVersion?.mes_example ||
|
{(card.initialVersion?.mes_example ||
|
||||||
card.data?.mes_example) && (
|
card.data?.mes_example) && (
|
||||||
<Accordion type="single" collapsible>
|
<Accordion type="single" collapsible>
|
||||||
<AccordionItem value="example-messages">
|
<AccordionItem value="example-messages">
|
||||||
<AccordionTrigger>
|
<AccordionTrigger>
|
||||||
Example Messages
|
Example Messages
|
||||||
</AccordionTrigger>
|
</AccordionTrigger>
|
||||||
<AccordionContent>
|
<AccordionContent>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<pre className="whitespace-pre-wrap font-sans text-sm">
|
<pre className="whitespace-pre-wrap font-sans text-sm">
|
||||||
{card.initialVersion?.mes_example ||
|
{card.initialVersion?.mes_example ||
|
||||||
card.data.mes_example}
|
card.data.mes_example}
|
||||||
</pre>
|
</pre>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
copyToClipboard(
|
copyToClipboard(
|
||||||
card.initialVersion?.mes_example ||
|
card.initialVersion?.mes_example ||
|
||||||
card.data.mes_example
|
card.data.mes_example
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Copy className="h-4 w-4" />
|
<Copy className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
)}
|
)}
|
||||||
{(card.initialVersion?.personality ||
|
{(card.initialVersion?.personality ||
|
||||||
card.data?.personality) && (
|
card.data?.personality) && (
|
||||||
<Accordion type="single" collapsible>
|
<Accordion type="single" collapsible>
|
||||||
<AccordionItem value="personality">
|
<AccordionItem value="personality">
|
||||||
<AccordionTrigger>Personality</AccordionTrigger>
|
<AccordionTrigger>Personality</AccordionTrigger>
|
||||||
<AccordionContent>
|
<AccordionContent>
|
||||||
<div className="flex justify-between">
|
<div className="flex justify-between">
|
||||||
<pre className="whitespace-pre-wrap font-sans text-sm">
|
<pre className="whitespace-pre-wrap font-sans text-sm">
|
||||||
{card.initialVersion?.personality ||
|
{card.initialVersion?.personality ||
|
||||||
card.data.personality}
|
card.data.personality}
|
||||||
</pre>
|
</pre>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
copyToClipboard(
|
copyToClipboard(
|
||||||
card.initialVersion?.personality ||
|
card.initialVersion?.personality ||
|
||||||
card.data.personality
|
card.data.personality
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Copy className="h-4 w-4" />
|
<Copy className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
@@ -863,12 +891,12 @@ export default function Home() {
|
|||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>
|
<DialogTitle>
|
||||||
{isMetadataOpen ? "Enter Avatar Path" : "Enter Character URL"}
|
{isMetadataOpen ? "Enter Avatar Path" : "Fetch Avatar"}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
{isMetadataOpen
|
{isMetadataOpen
|
||||||
? "Look for the avatar field in the opened tab and paste the value here."
|
? "Look for the avatar field in the opened tab and paste the value here."
|
||||||
: "Enter the Janitor character URL (https://janitorai.com/characters/...)."}
|
: "Enter a character URL (janitorai.com/characters/...) to open metadata, or paste an image filename (id.webp) or full image URL directly."}
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
@@ -888,19 +916,18 @@ export default function Home() {
|
|||||||
) : (
|
) : (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<Input
|
<Input
|
||||||
placeholder="https://janitorai.com/characters/..."
|
placeholder="URL or id.webp"
|
||||||
value={characterUrl}
|
value={characterUrl}
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
setCharacterUrl(e.target.value)
|
setCharacterUrl(e.target.value)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Upon clicking this button, a new tab will open with the
|
For character URLs, a new tab will open with metadata. For image
|
||||||
character's metadata. Look for the avatar field and copy the
|
filenames or full image URLs, the avatar will be set directly.
|
||||||
value before returning to this page.
|
|
||||||
</p>
|
</p>
|
||||||
<Button onClick={handleOpenMetadata} className="w-full">
|
<Button onClick={handleOpenMetadata} className="w-full">
|
||||||
Open Metadata
|
Fetch Avatar
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user