update css, js links depending on the output code
This commit is contained in:
parent
ed3dbc9c59
commit
b6a804e234
@ -18,7 +18,7 @@ import { Button } from "@/components/ui/button";
|
|||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./components/ui/tabs";
|
||||||
import SettingsDialog from "./components/SettingsDialog";
|
import SettingsDialog from "./components/SettingsDialog";
|
||||||
import { Settings, EditorTheme, AppState } from "./types";
|
import { Settings, EditorTheme, AppState, ComponentLibrary } from "./types";
|
||||||
import { IS_RUNNING_ON_CLOUD } from "./config";
|
import { IS_RUNNING_ON_CLOUD } from "./config";
|
||||||
import { PicoBadge } from "./components/PicoBadge";
|
import { PicoBadge } from "./components/PicoBadge";
|
||||||
import { OnboardingNote } from "./components/OnboardingNote";
|
import { OnboardingNote } from "./components/OnboardingNote";
|
||||||
@ -43,6 +43,7 @@ function App() {
|
|||||||
isImageGenerationEnabled: true,
|
isImageGenerationEnabled: true,
|
||||||
editorTheme: EditorTheme.COBALT,
|
editorTheme: EditorTheme.COBALT,
|
||||||
isTermOfServiceAccepted: false,
|
isTermOfServiceAccepted: false,
|
||||||
|
componentLibrary: ComponentLibrary.HTML,
|
||||||
},
|
},
|
||||||
"setting"
|
"setting"
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { FaCopy } from "react-icons/fa";
|
import { FaCopy } from "react-icons/fa";
|
||||||
import CodeMirror from "./CodeMirror";
|
import CodeMirror from "./CodeMirror";
|
||||||
import { Button } from "./ui/button";
|
import { ComponentLibrary, Settings } from "../types";
|
||||||
import { Settings } from "../types";
|
|
||||||
import copy from "copy-to-clipboard";
|
import copy from "copy-to-clipboard";
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
|
import OpenInCodepenio from "./OpenInCodepenio";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
code: string;
|
code: string;
|
||||||
@ -18,41 +18,6 @@ function CodeTab({ code, setCode, settings }: Props) {
|
|||||||
toast.success("Copied to clipboard");
|
toast.success("Copied to clipboard");
|
||||||
}, [code]);
|
}, [code]);
|
||||||
|
|
||||||
const doOpenInCodepenio = useCallback(async () => {
|
|
||||||
// TODO: Update CSS and JS external links depending on the framework being used
|
|
||||||
const data = {
|
|
||||||
html: code,
|
|
||||||
editors: "100", // 1: Open HTML, 0: Close CSS, 0: Close JS
|
|
||||||
layout: "left",
|
|
||||||
css_external:
|
|
||||||
"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" +
|
|
||||||
(code.includes("<ion-")
|
|
||||||
? ",https://cdn.jsdelivr.net/npm/@ionic/core/css/ionic.bundle.css"
|
|
||||||
: ""),
|
|
||||||
js_external:
|
|
||||||
"https://cdn.tailwindcss.com " +
|
|
||||||
(code.includes("<ion-")
|
|
||||||
? ",https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.esm.js,https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.js"
|
|
||||||
: ""),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a hidden form and submit it to open the code in CodePen
|
|
||||||
// Can't use fetch API directly because we want to open the URL in a new tab
|
|
||||||
const input = document.createElement("input");
|
|
||||||
input.setAttribute("type", "hidden");
|
|
||||||
input.setAttribute("name", "data");
|
|
||||||
input.setAttribute("value", JSON.stringify(data));
|
|
||||||
|
|
||||||
const form = document.createElement("form");
|
|
||||||
form.setAttribute("method", "POST");
|
|
||||||
form.setAttribute("action", "https://codepen.io/pen/define");
|
|
||||||
form.setAttribute("target", "_blank");
|
|
||||||
form.appendChild(input);
|
|
||||||
|
|
||||||
document.body.appendChild(form);
|
|
||||||
form.submit();
|
|
||||||
}, [code]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="flex justify-start items-center px-4 mb-2">
|
<div className="flex justify-start items-center px-4 mb-2">
|
||||||
@ -63,17 +28,7 @@ function CodeTab({ code, setCode, settings }: Props) {
|
|||||||
>
|
>
|
||||||
Copy Code <FaCopy className="ml-2" />
|
Copy Code <FaCopy className="ml-2" />
|
||||||
</span>
|
</span>
|
||||||
<Button
|
<OpenInCodepenio code={code} support={settings.componentLibrary || ComponentLibrary.HTML}></OpenInCodepenio>
|
||||||
onClick={doOpenInCodepenio}
|
|
||||||
className="bg-gray-100 text-black ml-2 py-2 px-4 border border-black rounded-md hover:bg-gray-400 focus:outline-none"
|
|
||||||
>
|
|
||||||
Open in{" "}
|
|
||||||
<img
|
|
||||||
src="https://assets.codepen.io/t-1/codepen-logo.svg"
|
|
||||||
alt="codepen.io"
|
|
||||||
className="h-4 ml-1"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
<CodeMirror
|
<CodeMirror
|
||||||
code={code}
|
code={code}
|
||||||
|
|||||||
@ -1,83 +1,27 @@
|
|||||||
import { Component } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { Button } from './ui/button';
|
import { Button } from './ui/button';
|
||||||
|
import { libraries, LibraryType } from '@/lib/support';
|
||||||
|
import { ComponentLibrary } from '@/types';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
enum SupportType {
|
export interface OpenInProps {
|
||||||
HTML = 'html',
|
|
||||||
IONIC = 'ionic'
|
|
||||||
}
|
|
||||||
|
|
||||||
enum LibraryType {
|
|
||||||
css = 'css',
|
|
||||||
js = 'js',
|
|
||||||
}
|
|
||||||
|
|
||||||
interface OpenInCodepenioProps {
|
|
||||||
code: string;
|
code: string;
|
||||||
support?: SupportType;
|
support?: ComponentLibrary;
|
||||||
onDoOpen?: () => void;
|
onDoOpen?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Library {
|
|
||||||
[LibraryType.css]: string[],
|
|
||||||
[LibraryType.js]: string[],
|
|
||||||
validate: (support: SupportType, code: String) => Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component show button do open in new windows to CodePen Editor, this component add support
|
* Component show button do open in new windows to CodePen Editor, this component add support
|
||||||
* of diferrent tecnologies do use `libraries` property.
|
* of diferrent tecnologies do use `libraries` property.
|
||||||
* @component
|
* @component
|
||||||
* Redirect to codepen.io
|
* Redirect to codepen.io
|
||||||
* @param { OpenInCodepenioProps } props
|
* @param { OpenInProps } props
|
||||||
* @property {string} code - this generated code.
|
* @property {string} code - this generated code.
|
||||||
* @property {Function} onDoOpen - handle after open and redirect to Codepen Editor
|
* @property {Function} onDoOpen - handle after open and redirect to Codepen Editor
|
||||||
* @property {Function} libraries[SupportType].css: [array style sheets libraries]
|
|
||||||
* @property {Function} libraries[SupportType].js: [array javascript libraries]
|
|
||||||
* @property {Function} libraries[SupportType].validate: return Boolean the result of custom validating
|
|
||||||
* @property {Function} libraries[SupportType].css: [array style sheets libraries]
|
|
||||||
* @property {Function} libraries[SupportType].js: [array javascript libraries]
|
|
||||||
* @property {Function} libraries[SupportType].validate: return Boolean the result of custom validating
|
|
||||||
*/
|
*/
|
||||||
class OpenInCodepenio extends Component<OpenInCodepenioProps> {
|
function OpenInCodepenio({ code, support, onDoOpen }: OpenInProps) {
|
||||||
|
|
||||||
libraries: Record<string, Library> = {
|
const doOpenInCodepenio = useCallback(async () => {
|
||||||
[SupportType.HTML] : {
|
|
||||||
css: ['https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css'],
|
|
||||||
js: ['https://cdn.tailwindcss.com'],
|
|
||||||
validate: (support) => {
|
|
||||||
return support == SupportType.HTML
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[SupportType.IONIC] : {
|
|
||||||
css: [
|
|
||||||
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css',
|
|
||||||
'https://cdn.jsdelivr.net/npm/@ionic/core/css/ionic.bundle.css'],
|
|
||||||
js: [
|
|
||||||
'https://cdn.tailwindcss.com',
|
|
||||||
'https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.esm.js',
|
|
||||||
'https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.js'
|
|
||||||
],
|
|
||||||
validate: (support, code) => {
|
|
||||||
return support == SupportType.IONIC || code.includes('<ion-')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
getExternalLibraries = (type: LibraryType): string => {
|
|
||||||
let library: string[] = []
|
|
||||||
const { code, support = SupportType.HTML } = this.props;
|
|
||||||
|
|
||||||
Object.values(this.libraries).forEach((value: Library) => {
|
|
||||||
if( value.validate(support, code)){
|
|
||||||
library = value[type]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return library.join(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
doOpenInCodepenio = () => {
|
|
||||||
const { code, onDoOpen } = this.props;
|
|
||||||
var form = document.createElement('form');
|
var form = document.createElement('form');
|
||||||
form.setAttribute('method', 'POST');
|
form.setAttribute('method', 'POST');
|
||||||
form.setAttribute('action', 'https://codepen.io/pen/define');
|
form.setAttribute('action', 'https://codepen.io/pen/define');
|
||||||
@ -87,15 +31,10 @@ class OpenInCodepenio extends Component<OpenInCodepenioProps> {
|
|||||||
html: code,
|
html: code,
|
||||||
editors: "100", // 1:Open html, 0:close CSS, 0:Close Js
|
editors: "100", // 1:Open html, 0:close CSS, 0:Close Js
|
||||||
layout: "left",
|
layout: "left",
|
||||||
css_external: this.getExternalLibraries(LibraryType.css),
|
css_external: libraries.getLibraries(LibraryType.css, { code , support }),
|
||||||
js_external: this.getExternalLibraries(LibraryType.js),
|
js_external: libraries.getLibraries(LibraryType.js, {code , support }),
|
||||||
}
|
|
||||||
// test have html to json
|
|
||||||
try {
|
|
||||||
JSON.stringify({ html: data.html })
|
|
||||||
} catch (error) {
|
|
||||||
data.html = "<!-- Copy your code here -->"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var input = document.createElement('input');
|
var input = document.createElement('input');
|
||||||
input.setAttribute('type', 'hidden');
|
input.setAttribute('type', 'hidden');
|
||||||
input.setAttribute('name', 'data');
|
input.setAttribute('name', 'data');
|
||||||
@ -106,18 +45,25 @@ class OpenInCodepenio extends Component<OpenInCodepenioProps> {
|
|||||||
form.submit();
|
form.submit();
|
||||||
if (onDoOpen) {
|
if (onDoOpen) {
|
||||||
onDoOpen();
|
onDoOpen();
|
||||||
|
} else {
|
||||||
|
toast.success("Will Opening codepen.io, need enable popup windows");
|
||||||
}
|
}
|
||||||
}
|
}, [code, support])
|
||||||
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Button
|
||||||
<Button onClick={this.doOpenInCodepenio} className="bg-gray-100 text-black ml-2 py-2 px-4 border border-black rounded-md hover:bg-gray-400 focus:outline-none">
|
onClick={doOpenInCodepenio}
|
||||||
Open in <img src="https://assets.codepen.io/t-1/codepen-logo.svg" alt="codepen.io" className="h-4 ml-1" />
|
className="bg-gray-100 text-black ml-2 py-2 px-4 border border-black rounded-md hover:bg-gray-400 focus:outline-none"
|
||||||
|
>
|
||||||
|
Open in{" "}
|
||||||
|
<img
|
||||||
|
src="https://assets.codepen.io/t-1/codepen-logo.svg"
|
||||||
|
alt="codepen.io"
|
||||||
|
className="h-4 ml-1"
|
||||||
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export default OpenInCodepenio;
|
export default OpenInCodepenio;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import {
|
|||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import { FaCog } from "react-icons/fa";
|
import { FaCog } from "react-icons/fa";
|
||||||
import { EditorTheme, Settings } from "../types";
|
import { EditorTheme, Settings, ComponentLibrary } from "../types";
|
||||||
import { Switch } from "./ui/switch";
|
import { Switch } from "./ui/switch";
|
||||||
import { Label } from "./ui/label";
|
import { Label } from "./ui/label";
|
||||||
import { Input } from "./ui/input";
|
import { Input } from "./ui/input";
|
||||||
@ -120,6 +120,25 @@ function SettingsDialog({ settings, setSettings }: Props) {
|
|||||||
<option value="espresso">Espresso</option>
|
<option value="espresso">Espresso</option>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<Label htmlFor="output-code">
|
||||||
|
<div>Output Code</div>
|
||||||
|
</Label>
|
||||||
|
<div>
|
||||||
|
<Select
|
||||||
|
id="output-code"
|
||||||
|
value={settings.componentLibrary}
|
||||||
|
onChange={(e: React.ChangeEvent<HTMLSelectElement>) =>
|
||||||
|
setSettings((s) => ({
|
||||||
|
...s,
|
||||||
|
componentLibrary: e.target.value as ComponentLibrary,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<option disabled>Default</option>
|
||||||
|
<option value={ComponentLibrary.HTML}>{ComponentLibrary.HTML.toUpperCase()}</option>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
|
|||||||
56
frontend/src/lib/support.ts
Normal file
56
frontend/src/lib/support.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { ComponentLibrary } from "@/types"
|
||||||
|
|
||||||
|
export enum LibraryType {
|
||||||
|
css = 'css',
|
||||||
|
js = 'js',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Library {
|
||||||
|
[LibraryType.css]: string[],
|
||||||
|
[LibraryType.js]: string[],
|
||||||
|
validate: (support: ComponentLibrary, code: String) => Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
class SupportLibraries {
|
||||||
|
|
||||||
|
libraries: Record<string, Library> = {
|
||||||
|
[ComponentLibrary.HTML] : {
|
||||||
|
css: ['https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css'],
|
||||||
|
js: ['https://cdn.tailwindcss.com'],
|
||||||
|
validate: (support) => {
|
||||||
|
return support == ComponentLibrary.HTML
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[ComponentLibrary.IONIC] : {
|
||||||
|
css: [
|
||||||
|
'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css',
|
||||||
|
'https://cdn.jsdelivr.net/npm/@ionic/core/css/ionic.bundle.css'],
|
||||||
|
js: [
|
||||||
|
'https://cdn.tailwindcss.com',
|
||||||
|
'https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.esm.js',
|
||||||
|
'https://cdn.jsdelivr.net/npm/@ionic/core/dist/ionic/ionic.js'
|
||||||
|
],
|
||||||
|
validate: (support, code) => {
|
||||||
|
return support == ComponentLibrary.IONIC || code.includes('<ion-')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
getLibraries = (type: LibraryType, { code = '', support = ComponentLibrary.HTML} ): string => {
|
||||||
|
let library: string[] = []
|
||||||
|
debugger
|
||||||
|
Object.values(this.libraries).forEach((value: Library) => {
|
||||||
|
if( value.validate(support, code)){
|
||||||
|
library = value[type]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return library.join(',');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const libraries = new SupportLibraries()
|
||||||
|
|
||||||
|
export {
|
||||||
|
libraries
|
||||||
|
}
|
||||||
@ -1,3 +1,11 @@
|
|||||||
|
export enum ComponentLibrary {
|
||||||
|
HTML = 'html',
|
||||||
|
IONIC = 'ionic',
|
||||||
|
// TODO: add support to FLUTTER = 'flutter',
|
||||||
|
// TODO: add support to REACT = 'react',
|
||||||
|
// TODO: add support to VUE = 'vue',
|
||||||
|
}
|
||||||
|
|
||||||
export enum EditorTheme {
|
export enum EditorTheme {
|
||||||
ESPRESSO = "espresso",
|
ESPRESSO = "espresso",
|
||||||
COBALT = "cobalt",
|
COBALT = "cobalt",
|
||||||
@ -9,6 +17,7 @@ export interface Settings {
|
|||||||
isImageGenerationEnabled: boolean;
|
isImageGenerationEnabled: boolean;
|
||||||
editorTheme: EditorTheme;
|
editorTheme: EditorTheme;
|
||||||
isTermOfServiceAccepted: boolean; // Only relevant for hosted version
|
isTermOfServiceAccepted: boolean; // Only relevant for hosted version
|
||||||
|
componentLibrary: ComponentLibrary;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AppState {
|
export enum AppState {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user