feat(docs): add data script
* fetches npm & github info * add vite plugin icons
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
.data.json
|
||||||
@@ -1,97 +1,11 @@
|
|||||||
html,
|
:root {
|
||||||
body {
|
--primary: #BB86FC;
|
||||||
position: relative;
|
--secondary: #03dac5;
|
||||||
margin: 0;
|
|
||||||
height: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
color: #111;
|
|
||||||
background-color: #31475e;
|
|
||||||
background-position: center;
|
|
||||||
background-size: cover;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-image: url('./polygon-scatter.svg');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.backround-img {
|
.home-content {
|
||||||
background-position: center;
|
max-width: 100% !important;
|
||||||
background-size: cover;
|
padding: 0 !important;
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-image: url('./polygon-scatter.svg');
|
|
||||||
}
|
|
||||||
|
|
||||||
.overview-example__add {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-flow__node a {
|
|
||||||
font-weight: 700;
|
|
||||||
color: #111;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-flow__node.dark-node {
|
|
||||||
background: #0041d0;
|
|
||||||
color: #f8f8f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-flow__node.dark {
|
|
||||||
background: #557;
|
|
||||||
color: #f8f8f8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-flow__node-selector {
|
|
||||||
font-size: 14px;
|
|
||||||
background: #f0f2f3;
|
|
||||||
border: 1px solid #555;
|
|
||||||
border-radius: 5px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.vue-flow__node-selector .vue-flow__handle {
|
|
||||||
border-color: #f0f2f3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (min-width: 768px) {
|
|
||||||
.overview-example__add {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.font-mono {
|
|
||||||
font-family: 'JetBrains Mono', monospace;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
|
|
||||||
#vue-flow-examples {
|
|
||||||
width: calc(100% - 280px);
|
|
||||||
overflow: scroll;
|
|
||||||
@apply flex m-0 flex-col uppercase;
|
|
||||||
font-family: 'JetBrains Mono', monospace;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
|
|
||||||
.vue-flow {
|
|
||||||
@apply bg-white h-[80vh];
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
@apply p-0 md:p-6 text-left gap-2 flex flex-col justify-center items-center text-white normal-case leading-tight md:leading-normal;
|
|
||||||
|
|
||||||
.content {
|
|
||||||
@apply w-full md:w-5/6 xl:w-11/12 p-6 md:rounded-xl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#vue-flow-docs {
|
|
||||||
@apply flex m-0 p-0 lg:p-6 bg-gray-800 text-white overflow-scroll max-w-full;
|
|
||||||
}
|
|
||||||
|
|
||||||
#vue-flow-docs, #vue-flow-examples,
|
|
||||||
.home-page {
|
|
||||||
a {
|
|
||||||
@apply text-green-500 font-semibold hover:text-green-300;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
@@ -120,28 +34,41 @@ li {
|
|||||||
list-style-type: circle;
|
list-style-type: circle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.backround-img {
|
||||||
@apply bg-gray-200 hover:bg-gray-300 focus:outline-none font-bold mr-2 border-2 p-2 rounded-xl;
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-image: url('./polygon-scatter.svg');
|
||||||
}
|
}
|
||||||
|
|
||||||
.md {
|
.overview-example__add {
|
||||||
@apply prose prose-sm m-auto text-left flex flex-col gap-4;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.attention-box {
|
.vue-flow__node.dark-node {
|
||||||
@apply text-gray-800 p-4 bg-yellow-300 rounded-xl mb-4;
|
background: #0041d0;
|
||||||
|
color: #f8f8f8;
|
||||||
.title {
|
|
||||||
@apply text-lg font-bold;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.demo-flow {
|
.vue-flow__node.dark {
|
||||||
@apply bg-white border-1 solid border-gray-300 rounded-xl;
|
background: #557;
|
||||||
|
color: #f8f8f8;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
.vue-flow__node-selector {
|
||||||
@apply !text-xs !md:text-lg;
|
font-size: 14px;
|
||||||
|
background: #f0f2f3;
|
||||||
|
border: 1px solid #555;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-flow__node-selector .vue-flow__handle {
|
||||||
|
border-color: #f0f2f3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-flow {
|
||||||
|
@apply bg-white h-[80vh];
|
||||||
}
|
}
|
||||||
|
|
||||||
.slider {
|
.slider {
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import data from '../../../.data.json'
|
||||||
|
import Star from '~icons/carbon/star'
|
||||||
|
import Download from '~icons/carbon/download'
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="w-full bg-gray-900 text-white">
|
||||||
|
<div class="max-w-9/12 md:max-w-3/4 lg:max-w-4xl m-auto py-4 md:py-12">
|
||||||
|
<div class="grid md:grid-cols-3 gap-3 md:gap-0 text-center">
|
||||||
|
<div class="grid grid-rows-2 gap-2 pb-6 md:pb-0 border-b-1 border-gray-400 md:border-b-0">
|
||||||
|
<div class="text-gray-400 font-semibold text-lg">Stargazers</div>
|
||||||
|
<div class="font-bold text-3xl flex gap-2 items-center justify-center">
|
||||||
|
<Star /> {{ data.stargazers_count }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-rows-2 gap-2 pb-6 md:pb-0 border-b-1 border-gray-400 md:border-b-0">
|
||||||
|
<div class="text-gray-400 font-semibold text-lg">Downloads (last month)</div>
|
||||||
|
<div class="font-bold text-3xl flex gap-2 items-center justify-center">
|
||||||
|
<Download /> {{ data.downloads }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-rows-2 gap-2">
|
||||||
|
<div class="text-gray-400 font-semibold text-lg">License</div>
|
||||||
|
<div class="font-bold text-3xl">
|
||||||
|
{{ data.license.key.toUpperCase() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import { VueFlow, Background, Elements, isNode, MarkerType, useVueFlow } from '@braks/vue-flow'
|
|
||||||
|
|
||||||
const elements = ref<Elements>([
|
|
||||||
{ id: '1', type: 'input', label: 'Input Node', position: { x: 250, y: 15 } },
|
|
||||||
{ id: '2', label: 'Default Node', position: { x: 100, y: 150 } },
|
|
||||||
{ id: '3', label: 'Default Node', position: { x: 400, y: 150 } },
|
|
||||||
{ id: '4', type: 'button', position: { x: 240, y: 300 }, style: { borderRadius: '50%' } },
|
|
||||||
{ id: 'e1-2', type: 'step', source: '1', target: '2', markerEnd: MarkerType.Arrow },
|
|
||||||
{ id: 'e2-4', type: 'smoothstep', source: '2', target: '4', animated: true, style: { strokeWidth: 2, stroke: '#3b82f6' } },
|
|
||||||
{ id: 'e3-4', type: 'smoothstep', source: '3', target: '4', animated: true, style: { strokeWidth: 2, stroke: '#3b82f6' } },
|
|
||||||
{ id: 'e1-3', type: 'step', source: '1', target: '3', markerEnd: MarkerType.Arrow },
|
|
||||||
])
|
|
||||||
|
|
||||||
const { onConnect, onPaneReady, addEdges } = useVueFlow()
|
|
||||||
onConnect((connection) => addEdges([connection]))
|
|
||||||
onPaneReady(({ fitView }) => {
|
|
||||||
fitView({ padding: 0.3, offset: { y: 30 } })
|
|
||||||
})
|
|
||||||
|
|
||||||
const toggleClassnames = () => {
|
|
||||||
elements.value = elements.value.map((el) => {
|
|
||||||
if (isNode(el)) el.class = el.class === 'dark' ? 'light' : 'dark'
|
|
||||||
return el
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<div class="relative w-[100vw] h-[80vh] flex flex-col-reverse md:flex-row font-mono border-1 border-white bg-white">
|
|
||||||
<div class="flex bg-light-800 flex-col justify-center gap-2 md:gap-4 p-6 w-full md:w-1/3">
|
|
||||||
<h1 class="pointer-events-none text-xl lg:text-4xl">Easy to use</h1>
|
|
||||||
<h2 class="pointer-events-none text-sm lg:text-xl text-black font-normal">
|
|
||||||
Getting started is simple. All you need are some <strong>elements</strong> and you're ready to go.
|
|
||||||
<span class="font-bold">Each element needs a unique id.</span> A node also needs a <strong>position (x and y)</strong>. An
|
|
||||||
edge needs <strong>a source and a target</strong>.
|
|
||||||
</h2>
|
|
||||||
<div class="!pointer-events-auto transform scale-75 lg:scale-100 flex flex-row justify-center items-center gap-4">
|
|
||||||
<a class="p-4 bg-green-500 hover:bg-black rounded-xl !text-white font-semibold text-lg" href="/docs">
|
|
||||||
Documentation
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class="!pointer-events-auto p-4 bg-white hover:bg-black rounded-xl bg-blue-500 !text-white font-semibold text-lg"
|
|
||||||
href="/examples"
|
|
||||||
>
|
|
||||||
Examples
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<VueFlow
|
|
||||||
id="basic-flow"
|
|
||||||
v-model="elements"
|
|
||||||
class="vue-flow-basic-example"
|
|
||||||
:default-zoom="1.5"
|
|
||||||
:min-zoom="0.2"
|
|
||||||
:max-zoom="4"
|
|
||||||
:zoom-on-scroll="false"
|
|
||||||
>
|
|
||||||
<Background variant="dots" color="black" />
|
|
||||||
<template #node-button>
|
|
||||||
<slot></slot>
|
|
||||||
</template>
|
|
||||||
<div class="absolute right-[10px] top-[10px] z-4">
|
|
||||||
<button class="button" @click="toggleClassnames">toggle class</button>
|
|
||||||
</div>
|
|
||||||
</VueFlow>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<style>
|
|
||||||
.vue-flow__node.dark {
|
|
||||||
@apply !bg-black;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,60 +1,233 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from "vue";
|
||||||
import { VueFlow, MiniMap, Background, Controls, Elements, MarkerType, FlowEvents } from '@braks/vue-flow'
|
import { Elements, VueFlow, MiniMap, Controls, Background, FlowInstance, Position } from "@braks/vue-flow";
|
||||||
|
import { useBreakpoints, whenever } from "@vueuse/core";
|
||||||
|
|
||||||
interface Props {
|
const breakpoints = useBreakpoints({
|
||||||
next: (node: string[], duration: number) => void
|
mobile: 360,
|
||||||
}
|
tablet: 640,
|
||||||
const props = defineProps<Props>()
|
laptop: 1024,
|
||||||
|
desktop: 1280
|
||||||
|
});
|
||||||
|
|
||||||
const elements = ref<Elements>([
|
const elements = ref<Elements>([
|
||||||
{ id: '1', type: 'input', label: 'Back To The Start', position: { x: 200, y: 0 } },
|
{
|
||||||
{ id: '2', label: 'Node 2', position: { x: 0, y: 130 } },
|
id: "1",
|
||||||
{ id: '3', label: 'Node 3', position: { x: 400, y: 130 } },
|
type: "input",
|
||||||
{ id: 'e1-2', source: '1', target: '2', markerEnd: MarkerType.Arrow },
|
label: "input",
|
||||||
{ id: 'e1-3', source: '1', target: '3', markerEnd: MarkerType.Arrow },
|
position: { x: 250, y: 5 },
|
||||||
])
|
class: "font-semibold",
|
||||||
|
style: { border: "2px solid var(--primary)" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
label: "default",
|
||||||
|
position: { x: 100, y: 100 },
|
||||||
|
class: "font-semibold !border-2 !border-secondary/80",
|
||||||
|
style: (el) => el.selected ? { boxShadow: "none" } : undefined
|
||||||
|
},
|
||||||
|
{ id: "3", label: "default", position: { x: 400, y: 100 }, class: "font-semibold !border-2 !border-red-500" },
|
||||||
|
{ id: "4", type: "output", label: "output", position: { x: 250, y: 225 }, class: "font-semibold" },
|
||||||
|
{
|
||||||
|
id: "e1-2",
|
||||||
|
source: "1",
|
||||||
|
label: "animated edge",
|
||||||
|
target: "2",
|
||||||
|
animated: true,
|
||||||
|
style: { stroke: "var(--secondary)" }
|
||||||
|
},
|
||||||
|
{ id: "e1-3", source: "1", label: "default edge", target: "3", style: { stroke: "red" } },
|
||||||
|
{ id: "e2-4", source: "2", type: "step", target: "4", animated: true, style: { stroke: "var(--secondary)" } }
|
||||||
|
]);
|
||||||
|
|
||||||
const onLoad = ({ fitView }) => fitView({ padding: 0.5 })
|
const customizableElements = ref<Elements>([
|
||||||
const onNodeClick = ({ node }: FlowEvents['nodeClick']) => {
|
{ id: "1", type: "text-input", label: "First Name", position: { x: 0, y: 0 } },
|
||||||
if (node.type === 'input') props.next(['intro', 'examples', 'tour', 'documentation'], 4000)
|
{ id: "2", type: "text-input", label: "Last Name", position: { x: 400, y: 0 } },
|
||||||
}
|
{ id: "3", type: "text-output", label: "Node 3", position: { x: 240, y: 200 } },
|
||||||
|
{ id: "e1-3", source: "1", target: "3", animated: true },
|
||||||
|
{ id: "e2-3", source: "2", target: "3", animated: true }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const additionalElements = ref<Elements>([
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
type: "input",
|
||||||
|
sourcePosition: Position.Right,
|
||||||
|
label: "input",
|
||||||
|
style: { width: "75px" },
|
||||||
|
position: { x: 25, y: 120 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
label: "A",
|
||||||
|
targetPosition: Position.Left,
|
||||||
|
sourcePosition: Position.Right,
|
||||||
|
position: { x: 150, y: 25 },
|
||||||
|
style: { width: "75px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "3",
|
||||||
|
label: "B",
|
||||||
|
targetPosition: Position.Left,
|
||||||
|
sourcePosition: Position.Right,
|
||||||
|
position: { x: 250, y: 25 },
|
||||||
|
style: { width: "75px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "4",
|
||||||
|
label: "C",
|
||||||
|
targetPosition: Position.Left,
|
||||||
|
sourcePosition: Position.Right,
|
||||||
|
position: { x: 350, y: 25 },
|
||||||
|
style: { width: "75px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "5",
|
||||||
|
label: "D",
|
||||||
|
targetPosition: Position.Left,
|
||||||
|
sourcePosition: Position.Right,
|
||||||
|
position: { x: 150, y: 220 },
|
||||||
|
style: { width: "75px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "6",
|
||||||
|
label: "E",
|
||||||
|
targetPosition: Position.Left,
|
||||||
|
sourcePosition: Position.Right,
|
||||||
|
position: { x: 250, y: 220 },
|
||||||
|
style: { width: "75px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "7",
|
||||||
|
label: "F",
|
||||||
|
targetPosition: Position.Left,
|
||||||
|
sourcePosition: Position.Right,
|
||||||
|
position: { x: 350, y: 220 },
|
||||||
|
style: { width: "75px" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "8",
|
||||||
|
type: "output",
|
||||||
|
label: "Output",
|
||||||
|
targetPosition: Position.Left,
|
||||||
|
position: { x: 500, y: 120 },
|
||||||
|
style: { width: "75px" }
|
||||||
|
},
|
||||||
|
{ id: "e1-2", type: "step", source: "1", target: "2" },
|
||||||
|
{ id: "e2-3", type: "step", source: "2", target: "3" },
|
||||||
|
{ id: "e3-4", type: "step", source: "3", target: "4" },
|
||||||
|
{ id: "e4-8", type: "step", source: "4", target: "8" },
|
||||||
|
{ id: "e1-5", type: "step", source: "1", target: "5", animated: true },
|
||||||
|
{ id: "e5-6", type: "step", source: "5", target: "6", animated: true },
|
||||||
|
{ id: "e6-7", type: "step", source: "6", target: "7", animated: true },
|
||||||
|
{ id: "e6-8", type: "step", source: "7", target: "8", animated: true }
|
||||||
|
]);
|
||||||
|
|
||||||
|
const label = ref({
|
||||||
|
first: "",
|
||||||
|
last: ""
|
||||||
|
});
|
||||||
|
const instance = ref<FlowInstance>();
|
||||||
|
const onChange = ({ name, val }: { name: "first" | "last"; val: string }) => (label.value[name] = val);
|
||||||
|
const onLoad = (vf: FlowInstance) => {
|
||||||
|
if (!instance.value) instance.value = vf;
|
||||||
|
vf.fitView();
|
||||||
|
};
|
||||||
|
whenever(breakpoints.greater("tablet"), () => onLoad(instance.value));
|
||||||
|
whenever(breakpoints.smaller("tablet"), () => onLoad(instance.value));
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
ref="page"
|
class="
|
||||||
class="!pointer-events-auto font-mono flex flex flex-col md:flex-row bg-white w-[100vw] h-[80vh]"
|
p-4
|
||||||
:style="{ borderRadius: 0 }"
|
py-8
|
||||||
|
md:p-8 md:py-12
|
||||||
|
lg:p-16 lg:py-24
|
||||||
|
w-full
|
||||||
|
h-full
|
||||||
|
min-h-full
|
||||||
|
bg-gray-100
|
||||||
|
text-black
|
||||||
|
normal-case
|
||||||
|
flex flex-col
|
||||||
|
gap-12
|
||||||
|
md:gap-24
|
||||||
|
lg:gap-48
|
||||||
|
"
|
||||||
>
|
>
|
||||||
<VueFlow
|
<div class="flex flex-col md:flex-row gap-12">
|
||||||
id="features-flow"
|
<div class="gap-2 md:w-2/3 lg:w-[unset] flex flex-col justify-center items-center">
|
||||||
v-model="elements"
|
<h1>Feature-rich</h1>
|
||||||
class="relative font-mono"
|
<p class="w-2/3">
|
||||||
:pane-moveable="true"
|
Vue Flow comes with seamless zooming & panning, different edge and node types, single and multi-selection,
|
||||||
@pane-ready="onLoad"
|
controls,
|
||||||
@node-click="onNodeClick"
|
several event handlers and more.
|
||||||
>
|
</p>
|
||||||
<Controls />
|
<a class="button" href="/docs">
|
||||||
<Background />
|
|
||||||
<MiniMap />
|
|
||||||
</VueFlow>
|
|
||||||
<div class="flex bg-light-800 flex-col justify-center gap-2 md:gap-4 p-6 w-full md:w-1/3">
|
|
||||||
<h1 class="pointer-events-none text-xl lg:text-4xl">Everything you need</h1>
|
|
||||||
<h2 class="pointer-events-none text-sm lg:text-xl text-black font-normal">
|
|
||||||
Vue Flow ships with a <strong>Minimap-, Background- and Controls-Component</strong>. On top of that we add
|
|
||||||
<strong>Zoom & Pan utilities</strong> with which you can create the exact same transitions that are used on this site!
|
|
||||||
</h2>
|
|
||||||
<div class="!pointer-events-auto transform scale-75 lg:scale-100 flex flex-row justify-center items-center gap-4">
|
|
||||||
<a class="p-4 bg-green-500 hover:bg-black rounded-xl !text-white font-semibold text-lg" href="/docs">
|
|
||||||
Documentation
|
Documentation
|
||||||
</a>
|
</a>
|
||||||
<a
|
</div>
|
||||||
class="!pointer-events-auto p-4 bg-white hover:bg-black rounded-xl bg-blue-500 !text-white font-semibold text-lg"
|
<div class="w-full min-h-[300px] shadow-xl rounded-xl font-mono uppercase">
|
||||||
href="/examples"
|
<VueFlow v-model="elements" @pane-ready="onLoad">
|
||||||
|
<Controls />
|
||||||
|
<Background color="#aaa" :gap="8" />
|
||||||
|
</VueFlow>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col-reverse md:flex-row flex-unwrap gap-12">
|
||||||
|
<div
|
||||||
|
class="w-full h-[300px] shadow-xl bg-gray-800 border-1 border-solid border-gray-300 rounded-xl font-mono uppercase">
|
||||||
|
<VueFlow
|
||||||
|
v-model="customizableElements"
|
||||||
|
:snap-grid="[25, 25]"
|
||||||
|
:snap-to-grid="true"
|
||||||
|
:zoom-on-scroll="false"
|
||||||
|
:pane-moveable="false"
|
||||||
|
@pane-ready="onLoad"
|
||||||
>
|
>
|
||||||
Examples
|
<template #node-text-output="props">
|
||||||
</a>
|
<TextOutputNode v-bind="props" :label="`${label.first} ${label.last}`" />
|
||||||
|
</template>
|
||||||
|
<template #node-text-input="props">
|
||||||
|
<TextInputNode v-bind="props" @change="onChange" />
|
||||||
|
</template>
|
||||||
|
<Background variant="lines" color="#aaa" :gap="46" />
|
||||||
|
</VueFlow>
|
||||||
|
</div>
|
||||||
|
<div class="md:w-2/3 lg:w-[unset] gap-2 flex flex-col justify-center items-center">
|
||||||
|
<h1>Customizable</h1>
|
||||||
|
<p class="w-2/3">
|
||||||
|
You can create your own node and edge types or just pass a custom style. You can implement custom UIs inside
|
||||||
|
your nodes
|
||||||
|
and add functionality to your edges.
|
||||||
|
</p>
|
||||||
|
<a class="button" href="/docs">Documentation</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col md:flex-row gap-12">
|
||||||
|
<div class="md:w-2/3 lg:w-[unset] gap-2 flex flex-col justify-center items-center">
|
||||||
|
<h1>Additional Components</h1>
|
||||||
|
<p class="w-2/3">
|
||||||
|
Vue Flow includes a MiniMap, Controls and Background, as well as a ton of utilities to control the internal
|
||||||
|
state
|
||||||
|
outside the Vue Flow component.
|
||||||
|
</p>
|
||||||
|
<a class="button" href="/docs">Documentation</a>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="w-full h-[300px] shadow-xl bg-white border-1 border-solid border-gray-300 rounded-xl font-mono uppercase">
|
||||||
|
<VueFlow v-model="additionalElements" :zoom-on-scroll="false" :pane-moveable="false" @pane-ready="onLoad">
|
||||||
|
<Controls :show-interactive="false" />
|
||||||
|
<MiniMap mask-color="rgba(16, 185, 129, 0.5)" class="transform scale-60 origin-bottom-right opacity-75" />
|
||||||
|
<Background variant="lines" color="#aaa" :gap="46" />
|
||||||
|
</VueFlow>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
.button {
|
||||||
|
@apply
|
||||||
|
shadow-lg transition-colors duration-200 hover:bg-black font-semibold text-lg mt-4 px-5 py-3 rounded-xl bg-green-500 text-white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { VueFlow, Handle, Position, useVueFlow } from "@braks/vue-flow";
|
import { VueFlow, Handle, Position, useVueFlow } from "@braks/vue-flow";
|
||||||
import { useBreakpoints } from "@vueuse/core";
|
import { useBreakpoints } from "@vueuse/core";
|
||||||
|
import Book from "~icons/codicon/book";
|
||||||
import BoxNode from "./nodes/Box.vue";
|
import BoxNode from "./nodes/Box.vue";
|
||||||
import RGBFlow from "./RGB.vue";
|
|
||||||
import BasicFlow from "./Basic.vue";
|
|
||||||
import FeaturesFlow from "./Features.vue";
|
|
||||||
|
|
||||||
const breakpoints = useBreakpoints({
|
const breakpoints = useBreakpoints({
|
||||||
mobile: 320,
|
mobile: 320,
|
||||||
@@ -15,13 +13,11 @@ const breakpoints = useBreakpoints({
|
|||||||
|
|
||||||
const desktop = breakpoints.greater("tablet");
|
const desktop = breakpoints.greater("tablet");
|
||||||
|
|
||||||
const { dimensions, instance, onPaneReady } = useVueFlow({
|
const { dimensions, instance, onPaneReady, getNode } = useVueFlow({
|
||||||
nodes: [
|
nodes: [
|
||||||
{ id: "intro", type: "box", position: { x: 480, y: 50 }, draggable: true, extent: [[0, -100], [1000, 300]] },
|
{ id: "intro", type: "box", position: { x: 0, y: 0 }, draggable: true, extent: [[-150, 0], [150, 100]] },
|
||||||
{ id: "examples", type: "box", position: { x: 800, y: 400 } },
|
{ id: "examples", type: "box", position: { x: -50, y: 400 } },
|
||||||
{ id: "tour", type: "box", position: { x: 650, y: 550 } },
|
{ id: "documentation", type: "box", position: { x: 300, y: 400 } }
|
||||||
{ id: "documentation", type: "box", position: { x: 400, y: 400 } },
|
|
||||||
{ id: 'basic', type: 'basic', position: { x: 250, y: 2500 }, style: { cursor: 'default' } },
|
|
||||||
],
|
],
|
||||||
edges: [
|
edges: [
|
||||||
{
|
{
|
||||||
@@ -33,24 +29,6 @@ const { dimensions, instance, onPaneReady } = useVueFlow({
|
|||||||
animated: true,
|
animated: true,
|
||||||
style: { strokeWidth: 2, stroke: "#8b5cf6" }
|
style: { strokeWidth: 2, stroke: "#8b5cf6" }
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "eexamples-tour",
|
|
||||||
type: "smoothstep",
|
|
||||||
sourceHandle: "a",
|
|
||||||
source: "examples",
|
|
||||||
target: "tour",
|
|
||||||
animated: true,
|
|
||||||
style: { strokeWidth: 3, stroke: "#3b82f6" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "edocumentation-tour",
|
|
||||||
type: "smoothstep",
|
|
||||||
sourceHandle: "a",
|
|
||||||
source: "documentation",
|
|
||||||
target: "tour",
|
|
||||||
animated: true,
|
|
||||||
style: { strokeWidth: 3, stroke: "#3b82f6" }
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "eintro-documentation",
|
id: "eintro-documentation",
|
||||||
type: "smoothstep",
|
type: "smoothstep",
|
||||||
@@ -84,125 +62,63 @@ const nextNode = (id: string[], duration = 2000, padding = 0) => instance.value.
|
|||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="home-page">
|
<div class="home-page">
|
||||||
<div class="flex h-[60vh] md:h-[80vh] w-full gap-4" style="border-radius: 0">
|
<VueFlow>
|
||||||
<VueFlow>
|
<template #node-box="props">
|
||||||
<template #node-box="props">
|
<template v-if="props.id === 'intro'">
|
||||||
<template v-if="props.id === 'intro'">
|
<div class="max-w-[500px]">
|
||||||
<div class="max-w-[500px]">
|
<BoxNode class="bg-green-500 text-white">
|
||||||
<BoxNode class="bg-green-500 text-white">
|
<div class="font-mono flex flex-col gap-4 p-4 items-center">
|
||||||
<div class="font-mono flex flex-col gap-4 p-4 items-center">
|
<h1 class="pointer-events-none text-2xl lg:text-4xl text-center">Visualize your ideas with Vue
|
||||||
<h1 class="pointer-events-none text-2xl lg:text-4xl">Visualize your ideas with Vue Flow</h1>
|
Flow</h1>
|
||||||
<h2 class="pointer-events-none text-lg lg:text-xl font-normal">
|
<h2 class="pointer-events-none text-lg lg:text-xl font-normal">
|
||||||
A customizable Vue.js library for building node-based editors and diagrams.
|
A customizable Vue.js library for building node-based editors and diagrams.
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</BoxNode>
|
</BoxNode>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
|
||||||
<template v-else-if="props.id === 'documentation'">
|
|
||||||
<div class="flex">
|
|
||||||
<a
|
|
||||||
class="
|
|
||||||
flex flex-row
|
|
||||||
gap-3
|
|
||||||
items-center
|
|
||||||
p-4
|
|
||||||
shadow-lg
|
|
||||||
bg-orange-500
|
|
||||||
hover:bg-black
|
|
||||||
rounded-xl
|
|
||||||
!text-white
|
|
||||||
font-semibold
|
|
||||||
text-lg
|
|
||||||
"
|
|
||||||
href="/docs"
|
|
||||||
>
|
|
||||||
<i class="icon-sm icon-file-document !text-blue-700" />Read The Documentation
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<Handle type="target" :position="Position.Top" />
|
|
||||||
<Handle type="source" :position="Position.Bottom" />
|
|
||||||
</template>
|
|
||||||
<template v-else-if="props.id === 'tour'">
|
|
||||||
<button
|
|
||||||
class="
|
|
||||||
flex flex-row
|
|
||||||
gap-3
|
|
||||||
items-center
|
|
||||||
p-4
|
|
||||||
shadow-lg
|
|
||||||
hover:bg-black
|
|
||||||
bg-blue-500
|
|
||||||
rounded-xl
|
|
||||||
!text-white
|
|
||||||
font-semibold
|
|
||||||
text-lg
|
|
||||||
"
|
|
||||||
@click="nextNode(['basic'])"
|
|
||||||
>
|
|
||||||
<i class="icon-sm icon-heart !text-red-300" />Start the Tour
|
|
||||||
</button>
|
|
||||||
<Handle type="target" :position="Position.Top" />
|
|
||||||
<Handle type="source" :position="Position.Bottom" />
|
|
||||||
</template>
|
|
||||||
<template v-else-if="props.id === 'examples'">
|
|
||||||
<div class="flex">
|
|
||||||
<a
|
|
||||||
class="
|
|
||||||
flex flex-row
|
|
||||||
gap-3
|
|
||||||
items-center
|
|
||||||
p-4
|
|
||||||
shadow-lg
|
|
||||||
hover:bg-black
|
|
||||||
bg-purple-500
|
|
||||||
rounded-xl
|
|
||||||
!text-white
|
|
||||||
font-semibold
|
|
||||||
text-lg
|
|
||||||
"
|
|
||||||
href="/examples"
|
|
||||||
>
|
|
||||||
<i class="icon-sun icon-sm !text-yellow-300" />Check The Examples
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<Handle type="target" :position="Position.Top" />
|
|
||||||
<Handle type="source" :position="Position.Bottom" />
|
|
||||||
</template>
|
|
||||||
</template>
|
</template>
|
||||||
<template #node-basic>
|
<template v-else-if="props.id === 'documentation'">
|
||||||
<BasicFlow>
|
<div class="flex">
|
||||||
<button
|
<a class="link group bg-orange-500" href="/docs">
|
||||||
class="
|
<Book class="text-blue-700 group-hover:text-emerald-500" />
|
||||||
flex flex-row
|
Read The Documentation
|
||||||
gap-3
|
</a>
|
||||||
items-center
|
</div>
|
||||||
p-4
|
<Handle type="target" :position="Position.Top" />
|
||||||
shadow-lg
|
<Handle type="source" :position="Position.Bottom" />
|
||||||
hover:bg-black
|
|
||||||
dark:(bg-black) dark:hover:bg-blue-500
|
|
||||||
bg-blue-500
|
|
||||||
rounded-xl
|
|
||||||
!text-white
|
|
||||||
font-semibold
|
|
||||||
text-lg
|
|
||||||
"
|
|
||||||
@click="nextNode(['rgb'], 3500)"
|
|
||||||
>
|
|
||||||
<i class="icon-sm icon-heart !text-red-300" />Continue Demo
|
|
||||||
</button>
|
|
||||||
<Handle type="target" :position="Position.Top" />
|
|
||||||
</BasicFlow>
|
|
||||||
<Handle id="basic-a" type="source" :position="Position.Right" />
|
|
||||||
<Handle id="basic-b" type="target" :position="Position.Top" />
|
|
||||||
</template>
|
</template>
|
||||||
</VueFlow>
|
<template v-else-if="props.id === 'examples'">
|
||||||
</div>
|
<div class="flex">
|
||||||
|
<a class="link group bg-purple-500" href="/examples">
|
||||||
|
<i class="icon-sun icon-sm !text-yellow-300" />Check The Examples
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<Handle type="target" :position="Position.Top" />
|
||||||
|
<Handle type="source" :position="Position.Bottom" />
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</VueFlow>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style scoped>
|
<style scoped>
|
||||||
a {
|
.link {
|
||||||
@apply text-green-500 font-semibold hover:text-green-300;
|
@apply node
|
||||||
|
flex
|
||||||
|
gap-3
|
||||||
|
items-center
|
||||||
|
p-4
|
||||||
|
shadow-lg
|
||||||
|
transform
|
||||||
|
transition-transform
|
||||||
|
duration-300
|
||||||
|
hover:scale-102
|
||||||
|
transition-colors
|
||||||
|
ease-in-out
|
||||||
|
rounded-lg
|
||||||
|
hover:bg-black
|
||||||
|
text-white
|
||||||
|
font-semibold
|
||||||
|
text-lg;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:focus {
|
button:focus {
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { config } from 'dotenv'
|
import { config } from 'dotenv'
|
||||||
import { resolve } from 'path'
|
import { resolve } from 'path'
|
||||||
import { defineConfig, HeadConfig } from 'vitepress'
|
import { defineConfig, HeadConfig } from 'vitepress'
|
||||||
import head from './head'
|
|
||||||
import WindiCSS from 'vite-plugin-windicss'
|
import WindiCSS from 'vite-plugin-windicss'
|
||||||
|
import Icons from 'unplugin-icons/vite'
|
||||||
import Components from 'unplugin-vue-components/vite'
|
import Components from 'unplugin-vue-components/vite'
|
||||||
import svgLoader from 'vite-svg-loader'
|
import svgLoader from 'vite-svg-loader'
|
||||||
|
import { demoPlugin } from './plugins/demo'
|
||||||
|
import head from './head'
|
||||||
|
|
||||||
config({ path: resolve(__dirname, '.env') })
|
config({ path: resolve(__dirname, '.env') })
|
||||||
|
|
||||||
@@ -26,9 +28,7 @@ export default defineConfig({
|
|||||||
config: resolve(__dirname, './windi.config.ts'),
|
config: resolve(__dirname, './windi.config.ts'),
|
||||||
}) as any,
|
}) as any,
|
||||||
Components({
|
Components({
|
||||||
dirs: [
|
dirs: [resolve(__dirname, './components')],
|
||||||
resolve(__dirname, './components')
|
|
||||||
],
|
|
||||||
deep: true,
|
deep: true,
|
||||||
// allow auto load markdown components under `./src/components/`
|
// allow auto load markdown components under `./src/components/`
|
||||||
extensions: ['vue', 'md'],
|
extensions: ['vue', 'md'],
|
||||||
@@ -36,6 +36,10 @@ export default defineConfig({
|
|||||||
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
|
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
|
||||||
dts: false,
|
dts: false,
|
||||||
}),
|
}),
|
||||||
|
Icons({
|
||||||
|
// expiremental
|
||||||
|
autoInstall: true,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -54,15 +58,16 @@ export default defineConfig({
|
|||||||
nav: [
|
nav: [
|
||||||
{ text: 'Guide', link: '/', activeMatch: '^/$|^/guide/' },
|
{ text: 'Guide', link: '/', activeMatch: '^/$|^/guide/' },
|
||||||
{
|
{
|
||||||
text: 'Config Reference',
|
text: 'Examples',
|
||||||
link: '/config/basics',
|
link: '/examples/basic',
|
||||||
activeMatch: '^/config/',
|
activeMatch: '^/examples/',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
markdown: {
|
markdown: {
|
||||||
config(md) {
|
config(md) {
|
||||||
|
md.use(demoPlugin)
|
||||||
return md
|
return md
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import windiColors from 'windicss/colors'
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
extract: {
|
extract: {
|
||||||
include: [resolve(__dirname, 'components/**/*.{ts,md,vue}')],
|
include: [resolve(__dirname, 'components/**/*.{ts,md,vue}'), resolve(__dirname, '../src/**/*.{ts,md,vue}')],
|
||||||
},
|
},
|
||||||
|
|
||||||
attributify: true,
|
attributify: true,
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const { $fetch } = require('ohmyfetch')
|
||||||
|
|
||||||
|
const run = async () => {
|
||||||
|
const githubData = await $fetch('https://api.github.com/repos/bcakmakoglu/vue-flow?page=$i&per_page=100')
|
||||||
|
const npmData = await $fetch('https://api.npmjs.org/downloads/point/last-month/@braks/vue-flow')
|
||||||
|
fs.writeFileSync(path.resolve(__dirname, './.data.json'), JSON.stringify({ ...githubData, ...npmData }))
|
||||||
|
}
|
||||||
|
|
||||||
|
run().then(() => console.log('done'))
|
||||||
+5
-1
@@ -7,9 +7,11 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vitepress dev",
|
"dev": "vitepress dev",
|
||||||
"build": "vitepress build",
|
"build": "vitepress build",
|
||||||
"serve": "vitepress serve"
|
"serve": "vitepress serve",
|
||||||
|
"data": "node data.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@iconify/json": "^2.1.22",
|
||||||
"@types/escape-html": "^1.0.1",
|
"@types/escape-html": "^1.0.1",
|
||||||
"@types/markdown-it": "^12.2.3",
|
"@types/markdown-it": "^12.2.3",
|
||||||
"@types/node": "^17.0.23",
|
"@types/node": "^17.0.23",
|
||||||
@@ -18,7 +20,9 @@
|
|||||||
"dotenv": "^16.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"markdown-it": "^12.3.2",
|
"markdown-it": "^12.3.2",
|
||||||
|
"ohmyfetch": "^0.4.15",
|
||||||
"prismjs": "^1.27.0",
|
"prismjs": "^1.27.0",
|
||||||
|
"unplugin-icons": "^0.14.1",
|
||||||
"unplugin-vue-components": "^0.18.5",
|
"unplugin-vue-components": "^0.18.5",
|
||||||
"vite-plugin-windicss": "^1.8.3",
|
"vite-plugin-windicss": "^1.8.3",
|
||||||
"vite-svg-loader": "^3.2.0",
|
"vite-svg-loader": "^3.2.0",
|
||||||
|
|||||||
+4
-2
@@ -1,7 +1,9 @@
|
|||||||
---
|
---
|
||||||
home: true
|
home: true
|
||||||
navbar: false
|
|
||||||
footer: MIT Licensed | Copyright © 2021-present Burak Cakmakoglu
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Home />
|
<Home />
|
||||||
|
|
||||||
|
<Banner />
|
||||||
|
|
||||||
|
<Features />
|
||||||
|
|||||||
+6
-2
@@ -20,9 +20,13 @@
|
|||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"types": [
|
"types": [
|
||||||
"vite/client",
|
"vite/client",
|
||||||
"@types/node"
|
"@types/node",
|
||||||
],
|
"unplugin-icons/types/vue"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
"include": [
|
||||||
|
"**/*"
|
||||||
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"dist"
|
"dist"
|
||||||
|
|||||||
Reference in New Issue
Block a user