- )}
+ )}
- {(promptData.provider || promptData.modelType || media.createdAt) && (
+ {(promptData.provider ||
+ promptData.modelType ||
+ media.createdAt) && (
Information
-
+
-
-
{promptData.modelType && (
{getModelCreatorIcon(promptData.modelType)}
- {getModelDisplayName(promptData.modelType)}
+
+ {getModelDisplayName(
+ promptData.modelType,
+ )}
+
>
}
/>
@@ -460,8 +505,15 @@ export default function MediaPage() {
label="Provider"
value={
<>
- {getProviderIconByName(promptData.provider, "h-4 w-4 invert")}
- {getProviderDisplayName(promptData.provider)}
+ {getProviderIconByName(
+ promptData.provider,
+ "h-4 w-4 invert",
+ )}
+
+ {getProviderDisplayName(
+ promptData.provider,
+ )}
+
>
}
/>
@@ -473,11 +525,13 @@ export default function MediaPage() {
value={`${media.width} × ${media.height}`}
/>
)}
-
+
{media.createdAt && (
)}
@@ -504,11 +558,15 @@ export default function MediaPage() {
"w-full inline-flex items-center justify-center gap-2 rounded-md px-3 py-2 text-sm font-medium transition-colors border border-ui-panel-border",
media.url
? "bg-ui-controls/40 hover:bg-ui-controls/60 text-white"
- : "bg-ui-controls/20 text-white/60 cursor-not-allowed pointer-events-none"
+ : "bg-ui-controls/20 text-white/60 cursor-not-allowed pointer-events-none",
)}
- href={media.url ? addCorsParam(media.url) || media.url : undefined}
+ href={
+ media.url ? addCorsParam(media.url) || media.url : undefined
+ }
download={
- media.url ? `artcraft-${media.token || (media.isVideo ? "video" : "image")}` : undefined
+ media.url
+ ? `artcraft-${media.token || (media.isVideo ? "video" : "image")}`
+ : undefined
}
aria-disabled={!media.url}
target="_blank"
diff --git a/frontend/apps/artcraft-website/src/pages/news/news-index.tsx b/frontend/apps/artcraft-website/src/pages/news/news-index.tsx
new file mode 100644
index 0000000000..ce5379fd3a
--- /dev/null
+++ b/frontend/apps/artcraft-website/src/pages/news/news-index.tsx
@@ -0,0 +1,16 @@
+import { NewsIndex as LibNewsIndex } from "@storyteller/markdown-content";
+import Seo from "../../components/seo";
+
+const NewsIndex = ({ basePath }: { basePath: string }) => {
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default NewsIndex;
diff --git a/frontend/apps/artcraft-website/src/pages/news/news-post.tsx b/frontend/apps/artcraft-website/src/pages/news/news-post.tsx
new file mode 100644
index 0000000000..4eca168303
--- /dev/null
+++ b/frontend/apps/artcraft-website/src/pages/news/news-post.tsx
@@ -0,0 +1,25 @@
+import {
+ NewsPost as LibNewsPost,
+ getNewsPostBySlug,
+} from "@storyteller/markdown-content";
+import Seo from "../../components/seo";
+import { useParams } from "react-router-dom";
+
+const NewsPost = ({ basePath }: { basePath: string }) => {
+ const { slug } = useParams();
+ const post = slug ? getNewsPostBySlug(slug) : null;
+
+ const title = post
+ ? `${post.title} - ArtCraft`
+ : "Article Not Found - ArtCraft";
+ const desc = post ? post.description : "";
+
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default NewsPost;
diff --git a/frontend/apps/artcraft-website/src/pages/pricing/index.ts b/frontend/apps/artcraft-website/src/pages/pricing/index.ts
new file mode 100644
index 0000000000..0d05fe37de
--- /dev/null
+++ b/frontend/apps/artcraft-website/src/pages/pricing/index.ts
@@ -0,0 +1,2 @@
+import Pricing from "./pricing";
+export default Pricing;
diff --git a/frontend/apps/artcraft-website/src/pages/pricing/pricing.tsx b/frontend/apps/artcraft-website/src/pages/pricing/pricing.tsx
new file mode 100644
index 0000000000..296c63485a
--- /dev/null
+++ b/frontend/apps/artcraft-website/src/pages/pricing/pricing.tsx
@@ -0,0 +1,33 @@
+import Footer from "../../components/footer";
+import Seo from "../../components/seo";
+import { PricingTable } from "../../components/pricing-table";
+
+const Pricing = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+ Note: Pricing table is wrong, but we'll fix this shortly.
+
+
+
+
+ );
+};
+
+export default Pricing;
diff --git a/frontend/apps/artcraft-website/src/pages/signup/index.ts b/frontend/apps/artcraft-website/src/pages/signup/index.ts
new file mode 100644
index 0000000000..53aa30bc54
--- /dev/null
+++ b/frontend/apps/artcraft-website/src/pages/signup/index.ts
@@ -0,0 +1,2 @@
+import SignUp from "./signup";
+export default SignUp;
diff --git a/frontend/apps/artcraft-website/src/pages/signup/signup.tsx b/frontend/apps/artcraft-website/src/pages/signup/signup.tsx
new file mode 100644
index 0000000000..c1db425f21
--- /dev/null
+++ b/frontend/apps/artcraft-website/src/pages/signup/signup.tsx
@@ -0,0 +1,47 @@
+import { Link, useNavigate } from "react-router-dom";
+import { SignupForm } from "../../components/auth";
+import Seo from "../../components/seo";
+
+const Signup = () => {
+ const navigate = useNavigate();
+
+ return (
+
+
+
+
+
+
+
+
Create an Account
+
Join thousands of creators
+
+
+
navigate("/welcome")}
+ signupSource="artcraft"
+ />
+
+
+ Already have an account?{" "}
+
+ Log in
+
+
+
+
+
+
+ © {new Date().getFullYear()} ArtCraft. All rights reserved.
+
+
+ );
+};
+
+export default Signup;
diff --git a/frontend/apps/artcraft-website/src/pages/welcome/index.ts b/frontend/apps/artcraft-website/src/pages/welcome/index.ts
new file mode 100644
index 0000000000..00ff1ec952
--- /dev/null
+++ b/frontend/apps/artcraft-website/src/pages/welcome/index.ts
@@ -0,0 +1,2 @@
+import Welcome from "./welcome";
+export default Welcome;
diff --git a/frontend/apps/artcraft-website/src/pages/welcome/welcome.tsx b/frontend/apps/artcraft-website/src/pages/welcome/welcome.tsx
new file mode 100644
index 0000000000..de7aedc1e2
--- /dev/null
+++ b/frontend/apps/artcraft-website/src/pages/welcome/welcome.tsx
@@ -0,0 +1,161 @@
+import {
+ faCheckCircle,
+ faDownload,
+ faDesktop,
+ faRocket,
+} from "@fortawesome/pro-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { Button } from "@storyteller/ui-button";
+import { Link } from "react-router-dom";
+import { isMobile, isMacOs } from "react-device-detect";
+import { DOWNLOAD_LINKS } from "../../config/downloads";
+import Seo from "../../components/seo";
+import { PricingTable } from "../../components/pricing-table";
+
+const Welcome = () => {
+ const downloadUrl = isMacOs ? DOWNLOAD_LINKS.MACOS : DOWNLOAD_LINKS.WINDOWS;
+
+ return (
+
+
+
+ {/* Background gradient */}
+
+
+
+ {/* Success Header */}
+
+
+
+
+ Account created successfully!
+
+
+
+
+ Welcome to ArtCraft
+
+
+ Support open-source development and unlock premium AI art features.
+ Your subscription keeps ArtCraft free for everyone.
+
+
+
+ {/* Pricing Table */}
+
+
+ {/* Next Steps Section */}
+
+
+
+
+
+
+
Getting Started
+
+
+
+ Your download should have started automatically. Follow these
+ steps to begin creating:
+
+
+
+ {[
+ { step: 1, text: "Open the installer" },
+ { step: 2, text: "Follow setup instructions" },
+ { step: 3, text: "Log in to your account" },
+ { step: 4, text: "Start creating!" },
+ ].map((item) => (
+
+
+ {item.step}
+
+
{item.text}
+
+ ))}
+
+
+ {/* Download Contingency */}
+ {!isMobile && (
+
+
+
+ Download didn't start?
+
+
+
+
+
+
+
+ )}
+
+ {isMobile && (
+
+
+
+
+ ArtCraft is a powerful desktop experience.
+ Please head to your computer to download and install.
+
+ )}
+
+
+ {/* Footer Link */}
+
+
+ Back to Home
+
+
+
+
+
+ );
+};
+
+export default Welcome;
diff --git a/frontend/apps/artcraft-website/src/styles.css b/frontend/apps/artcraft-website/src/styles.css
index 3882cbe23b..3475c9dbcf 100644
--- a/frontend/apps/artcraft-website/src/styles.css
+++ b/frontend/apps/artcraft-website/src/styles.css
@@ -3,8 +3,27 @@
@tailwind utilities;
@layer base {
+ h1,
+ h2,
+ h3,
+ h4,
+ h5,
+ h6 {
+ font-family: "Outfit", sans-serif;
+ }
body {
- font-family: "Poppins", sans-serif;
+ font-family:
+ system-ui,
+ -apple-system,
+ BlinkMacSystemFont,
+ "Segoe UI",
+ Roboto,
+ Oxygen,
+ Ubuntu,
+ Cantarell,
+ "Open Sans",
+ "Helvetica Neue",
+ sans-serif;
color: #ffffff;
background-color: #1b1b1f;
}
diff --git a/frontend/apps/artcraft-website/tailwind.config.js b/frontend/apps/artcraft-website/tailwind.config.js
index 13f05a4542..338f8fca06 100644
--- a/frontend/apps/artcraft-website/tailwind.config.js
+++ b/frontend/apps/artcraft-website/tailwind.config.js
@@ -7,7 +7,7 @@ module.exports = {
content: [
join(
__dirname,
- "{src,pages,components,app}/**/*!(*.stories|*.spec).{ts,tsx,html}"
+ "{src,pages,components,app}/**/*!(*.stories|*.spec).{ts,tsx,html}",
),
...createGlobPatternsForDependencies(__dirname),
"./app/index.html",
@@ -23,6 +23,7 @@ module.exports = {
white: colors.white,
gray: colors.gray,
black: colors.black,
+ red: colors.red,
blue: colors.blue,
orange: colors.orange,
green: colors.green,
diff --git a/frontend/apps/artcraft-website/tsconfig.app.json b/frontend/apps/artcraft-website/tsconfig.app.json
index 0e82a67661..00a86d267e 100644
--- a/frontend/apps/artcraft-website/tsconfig.app.json
+++ b/frontend/apps/artcraft-website/tsconfig.app.json
@@ -37,6 +37,12 @@
"src/components/footer"
],
"references": [
+ {
+ "path": "../../libs/components/tab-selector/tsconfig.lib.json"
+ },
+ {
+ "path": "../../libs/state/subscription/tsconfig.lib.json"
+ },
{
"path": "../../libs/model-list/tsconfig.lib.json"
},
@@ -52,14 +58,14 @@
{
"path": "../../libs/components/loading-spinner/tsconfig.lib.json"
},
+ {
+ "path": "../../libs/markdown-content/tsconfig.lib.json"
+ },
{
"path": "../../libs/api/tsconfig.lib.json"
},
{
"path": "../../libs/components/button/tsconfig.lib.json"
- },
- {
- "path": "../../libs/markdown-content/tsconfig.lib.json"
}
]
}
diff --git a/frontend/apps/artcraft-website/tsconfig.json b/frontend/apps/artcraft-website/tsconfig.json
index 48053db779..9b1b3cdf03 100644
--- a/frontend/apps/artcraft-website/tsconfig.json
+++ b/frontend/apps/artcraft-website/tsconfig.json
@@ -2,6 +2,12 @@
"files": [],
"include": [],
"references": [
+ {
+ "path": "../../libs/components/tab-selector"
+ },
+ {
+ "path": "../../libs/state/subscription"
+ },
{
"path": "../../libs/model-list"
},
@@ -17,15 +23,15 @@
{
"path": "../../libs/components/loading-spinner"
},
+ {
+ "path": "../../libs/markdown-content"
+ },
{
"path": "../../libs/api"
},
{
"path": "../../libs/components/button"
},
- {
- "path": "../../libs/markdown-content"
- },
{
"path": "./tsconfig.app.json"
},
diff --git a/frontend/apps/artcraft-website/vite.config.ts b/frontend/apps/artcraft-website/vite.config.ts
index 0c25fe6437..4df77c2536 100644
--- a/frontend/apps/artcraft-website/vite.config.ts
+++ b/frontend/apps/artcraft-website/vite.config.ts
@@ -32,6 +32,9 @@ export default defineConfig(() => ({
target: 'https://api.storyteller.ai',
changeOrigin: true,
secure: true,
+ headers: {
+ Origin: 'https://api.storyteller.ai',
+ },
},
},
},
diff --git a/frontend/apps/artcraft/app/src/enums/Billing.ts b/frontend/apps/artcraft/app/src/enums/Billing.ts
index c602de1b8a..08ea1d95fc 100644
--- a/frontend/apps/artcraft/app/src/enums/Billing.ts
+++ b/frontend/apps/artcraft/app/src/enums/Billing.ts
@@ -1,5 +1,6 @@
export enum SubscriptionNamespace {
FAKEYOU = "fakeyou",
+ ARTCRAFT = "artcraft",
}
export enum SubscriptionProduct {
PLUS = "fakeyou_plus",
diff --git a/frontend/libs/api/src/lib/UsersApi.ts b/frontend/libs/api/src/lib/UsersApi.ts
index 72ce5e9aaf..1bfc1e880d 100644
--- a/frontend/libs/api/src/lib/UsersApi.ts
+++ b/frontend/libs/api/src/lib/UsersApi.ts
@@ -8,7 +8,7 @@ interface SignupRequest {
password: string;
password_confirmation: string;
signup_source?: string;
-};
+}
export class UsersApi extends ApiManager {
private async authFetch
(
@@ -19,7 +19,7 @@ export class UsersApi extends ApiManager {
}: {
method: string;
body?: B;
- }
+ },
): Promise {
const bodyInString = JSON.stringify(body);
@@ -33,8 +33,14 @@ export class UsersApi extends ApiManager {
body: bodyInString,
});
- const responseData = await response.json();
- return responseData as T;
+ const text = await response.text();
+ try {
+ const responseData = JSON.parse(text);
+ return responseData as T;
+ } catch (e) {
+ console.error("Failed to parse response as JSON:", text);
+ throw new Error(text || `Request failed with status ${response.status}`);
+ }
}
public GetSession(): Promise<
@@ -164,7 +170,7 @@ export class UsersApi extends ApiManager {
signupSource?: string;
}): Promise> {
const endpoint = `${this.getApiSchemeAndHost()}/v1/create_account`;
- const body : SignupRequest = {
+ const body: SignupRequest = {
email_address: email,
password,
password_confirmation: passwordConfirmation,
@@ -207,4 +213,4 @@ export class UsersApi extends ApiManager {
}
}
-(window as any).UsersApi = new UsersApi();
\ No newline at end of file
+(window as any).UsersApi = new UsersApi();
diff --git a/frontend/libs/api/src/lib/enums/Billing.ts b/frontend/libs/api/src/lib/enums/Billing.ts
index c602de1b8a..08ea1d95fc 100644
--- a/frontend/libs/api/src/lib/enums/Billing.ts
+++ b/frontend/libs/api/src/lib/enums/Billing.ts
@@ -1,5 +1,6 @@
export enum SubscriptionNamespace {
FAKEYOU = "fakeyou",
+ ARTCRAFT = "artcraft",
}
export enum SubscriptionProduct {
PLUS = "fakeyou_plus",
diff --git a/frontend/libs/state/subscription/src/lib/subscription-plans.ts b/frontend/libs/state/subscription/src/lib/subscription-plans.ts
index 8b12330089..cf1dce0695 100644
--- a/frontend/libs/state/subscription/src/lib/subscription-plans.ts
+++ b/frontend/libs/state/subscription/src/lib/subscription-plans.ts
@@ -26,10 +26,10 @@ export const SUBSCRIPTION_PLANS: SubscriptionPlanDetails[] = [
originalMonthlyPrice: 10,
originalYearlyPrice: 120,
features: [
- { text: "~1,000 Flux images", included: true },
- { text: "~100 GPT-Image-1 images", included: true },
- { text: "~10 minutes Kling video", included: true },
- { text: "Commercial license", included: true },
+ { text: "~10,000 Nano Banana Pro 4K images", included: true },
+ { text: "~10,000 GPT-Image-1.5 images", included: true },
+ { text: "~60 minutes Kling video", included: true },
+ { text: "You Own ArtCraft Forever", included: true },
],
colorScheme: "green" as const,
},
@@ -42,10 +42,10 @@ export const SUBSCRIPTION_PLANS: SubscriptionPlanDetails[] = [
originalMonthlyPrice: 35,
originalYearlyPrice: 420,
features: [
- { text: "~5,000 Flux images", included: true },
- { text: "~300 GPT-Image-1 images", included: true },
- { text: "~30 minutes Kling video", included: true },
- { text: "Commercial license", included: true },
+ { text: "~50,000 Nano Banana Pro 4K images", included: true },
+ { text: "~50,000 GPT-Image-1.5 images", included: true },
+ { text: "~2 hours Kling video", included: true },
+ { text: "You Own ArtCraft Forever", included: true },
],
colorScheme: "purple" as const,
},
@@ -58,10 +58,10 @@ export const SUBSCRIPTION_PLANS: SubscriptionPlanDetails[] = [
originalMonthlyPrice: 60,
originalYearlyPrice: 720,
features: [
- { text: "~15,000 Flux images", included: true },
- { text: "~500 GPT-Image-1 images", included: true },
- { text: "~60 minutes Kling video", included: true },
- { text: "Commercial license", included: true },
+ { text: "~100,000 Nano Banana Pro 4K images", included: true },
+ { text: "~100,000 GPT-Image-1.5 images", included: true },
+ { text: "~6 hours Kling video", included: true },
+ { text: "You Own ArtCraft Forever", included: true },
],
colorScheme: "orange" as const,
},