@@ -178,6 +205,13 @@
+
+
diff --git a/package.json b/package.json
index 1515e6c..cc5f11c 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,8 @@
"build:example:vue": "npm --prefix examples/vue run build",
"build:vue": "gulp vue",
"dev": "gulp serve",
- "start": "gulp serve"
+ "start": "gulp serve",
+ "test:vue-adapter": "npm run build:vue && npm run build:example:vue"
},
"peerDependencies": {
"vue": "^3.4.0"
diff --git a/src/vue/components/GnActionCard.js b/src/vue/components/GnActionCard.js
new file mode 100644
index 0000000..fcb3f93
--- /dev/null
+++ b/src/vue/components/GnActionCard.js
@@ -0,0 +1,20 @@
+import { defineComponent, h } from "vue";
+
+export default defineComponent({
+ name: "GnActionCard",
+ props: {
+ kicker: { type: String, default: "" },
+ title: { type: String, required: true },
+ text: { type: String, default: "" }
+ },
+ setup(props, { slots }) {
+ return () => h("article", { class: "card action-card" }, [
+ h("div", { class: "card-content" }, [
+ (props.kicker || slots.kicker) && h("span", { class: "action-card-kicker" }, slots.kicker?.() || props.kicker),
+ h("h3", { class: "action-card-title" }, slots.title?.() || props.title),
+ (props.text || slots.default) && h("p", { class: "action-card-text" }, slots.default?.() || props.text),
+ slots.actions && h("div", { class: "action-card-actions" }, slots.actions())
+ ])
+ ]);
+ }
+});
diff --git a/src/vue/components/GnActionList.js b/src/vue/components/GnActionList.js
new file mode 100644
index 0000000..5062904
--- /dev/null
+++ b/src/vue/components/GnActionList.js
@@ -0,0 +1,20 @@
+import { defineComponent, h } from "vue";
+import { cx } from "../utils.js";
+
+export default defineComponent({
+ name: "GnActionList",
+ props: {
+ items: { type: Array, default: () => [] }
+ },
+ setup(props, { attrs, slots }) {
+ return () => h("ul", { ...attrs, class: cx("list list-actions", attrs.class) }, props.items.map(item => h("li", {
+ class: cx("list-item", item.muted && "list-item-muted")
+ }, [
+ h("div", { class: "list-content" }, [
+ h("div", { class: "list-title" }, slots.title?.({ item }) || item.title),
+ (item.subtitle || slots.subtitle) && h("div", { class: "list-subtitle" }, slots.subtitle?.({ item }) || item.subtitle)
+ ]),
+ slots.controls && h("div", { class: "list-controls" }, slots.controls({ item }))
+ ])));
+ }
+});
diff --git a/src/vue/components/GnDefinitionList.js b/src/vue/components/GnDefinitionList.js
new file mode 100644
index 0000000..e66bc7b
--- /dev/null
+++ b/src/vue/components/GnDefinitionList.js
@@ -0,0 +1,17 @@
+import { defineComponent, h } from "vue";
+import { cx } from "../utils.js";
+
+export default defineComponent({
+ name: "GnDefinitionList",
+ props: {
+ items: { type: Array, default: () => [] }
+ },
+ setup(props, { attrs, slots }) {
+ return () => h("dl", { ...attrs, class: cx("list list-definition", attrs.class) }, props.items.map(item => h("div", {
+ class: "list-row"
+ }, [
+ h("dt", { class: "list-term" }, item.term || item.label),
+ h("dd", { class: "list-desc" }, slots[item.key]?.({ item }) || item.description || item.value)
+ ])));
+ }
+});
diff --git a/src/vue/components/GnList.js b/src/vue/components/GnList.js
new file mode 100644
index 0000000..e17fc46
--- /dev/null
+++ b/src/vue/components/GnList.js
@@ -0,0 +1,25 @@
+import { defineComponent, h } from "vue";
+import { cx, iconNode } from "../utils.js";
+
+export default defineComponent({
+ name: "GnList",
+ props: {
+ items: { type: Array, default: () => [] },
+ ordered: { type: Boolean, default: false },
+ icons: { type: Boolean, default: false }
+ },
+ setup(props, { attrs, slots }) {
+ const tag = props.ordered ? "ol" : "ul";
+
+ return () => h(tag, {
+ ...attrs,
+ class: cx("list", {
+ "list-ordered": props.ordered,
+ "with-icons": props.icons
+ }, attrs.class)
+ }, props.items.map(item => h("li", { class: "list-item" }, [
+ iconNode(item.icon),
+ slots.item?.({ item }) || item.label || item
+ ])));
+ }
+});
diff --git a/src/vue/components/GnLoader.js b/src/vue/components/GnLoader.js
new file mode 100644
index 0000000..0025dbf
--- /dev/null
+++ b/src/vue/components/GnLoader.js
@@ -0,0 +1,18 @@
+import { defineComponent, h } from "vue";
+import { cx, iconNode } from "../utils.js";
+
+export default defineComponent({
+ name: "GnLoader",
+ props: {
+ circle: { type: Boolean, default: false },
+ label: { type: String, default: "Loading" }
+ },
+ setup(props, { attrs }) {
+ return () => props.circle
+ ? h("div", { ...attrs, class: cx("circle-loader", attrs.class) }, [
+ iconNode("ph-bold ph-spinner normalize"),
+ props.label
+ ])
+ : h("div", { ...attrs, class: cx("loader", attrs.class), role: "status", "aria-label": props.label });
+ }
+});
diff --git a/src/vue/components/GnMetricCard.js b/src/vue/components/GnMetricCard.js
new file mode 100644
index 0000000..f3bd776
--- /dev/null
+++ b/src/vue/components/GnMetricCard.js
@@ -0,0 +1,31 @@
+import { defineComponent, h } from "vue";
+import { cx, iconNode } from "../utils.js";
+
+export default defineComponent({
+ name: "GnMetricCard",
+ props: {
+ label: { type: String, required: true },
+ value: { type: [String, Number], required: true },
+ icon: { type: String, default: "ph-chart-line-up" },
+ delta: { type: String, default: "" },
+ negative: { type: Boolean, default: false },
+ meta: { type: String, default: "" }
+ },
+ setup(props, { attrs, slots }) {
+ return () => h("article", { ...attrs, class: cx("card metric-card", attrs.class) }, [
+ h("div", { class: "card-content" }, [
+ h("div", { class: "metric-card-header" }, [
+ h("p", { class: "metric-card-label" }, slots.label?.() || props.label),
+ h("span", { class: "metric-card-icon" }, [iconNode(props.icon)])
+ ]),
+ h("p", { class: "metric-card-value" }, slots.value?.() || props.value),
+ (props.delta || props.meta || slots.meta) && h("div", { class: "metric-card-meta" }, [
+ props.delta && h("span", {
+ class: cx("metric-card-delta", { "metric-card-delta-negative": props.negative })
+ }, props.delta),
+ slots.meta?.() || props.meta
+ ])
+ ])
+ ]);
+ }
+});
diff --git a/src/vue/components/GnProgressStages.js b/src/vue/components/GnProgressStages.js
new file mode 100644
index 0000000..d4ef2d3
--- /dev/null
+++ b/src/vue/components/GnProgressStages.js
@@ -0,0 +1,17 @@
+import { defineComponent, h } from "vue";
+import { cx } from "../utils.js";
+
+export default defineComponent({
+ name: "GnProgressStages",
+ props: {
+ items: { type: Array, default: () => [] }
+ },
+ setup(props, { attrs }) {
+ return () => h("div", { ...attrs, class: cx("progress-stages", attrs.class) }, props.items.map(item => h("div", {
+ class: cx("progress-stage", {
+ "progress-stage-complete": item.status === "complete",
+ "progress-stage-current": item.status === "current"
+ })
+ }, item.label || item)));
+ }
+});
diff --git a/src/vue/components/GnStatusCard.js b/src/vue/components/GnStatusCard.js
new file mode 100644
index 0000000..3b26707
--- /dev/null
+++ b/src/vue/components/GnStatusCard.js
@@ -0,0 +1,25 @@
+import { defineComponent, h } from "vue";
+import { cx, iconNode, normalizeVariant } from "../utils.js";
+
+export default defineComponent({
+ name: "GnStatusCard",
+ props: {
+ title: { type: String, required: true },
+ text: { type: String, default: "" },
+ icon: { type: String, default: "ph-stack" },
+ variant: { type: String, default: "primary" }
+ },
+ setup(props, { attrs, slots }) {
+ const variant = normalizeVariant(props.variant);
+
+ return () => h("article", { ...attrs, class: cx("card status-card", `card-${variant}`, attrs.class) }, [
+ h("span", { class: "card-title" }, slots.title?.() || props.title),
+ h("div", { class: "card-content" }, [
+ h("div", { class: "status-icon-container" }, [
+ h("div", { class: "status-icon" }, slots.icon?.() || [iconNode(props.icon)])
+ ]),
+ (props.text || slots.default) && h("p", { class: "status-name" }, slots.default?.() || props.text)
+ ])
+ ]);
+ }
+});
diff --git a/src/vue/components/GnUsageMeter.js b/src/vue/components/GnUsageMeter.js
new file mode 100644
index 0000000..03d3471
--- /dev/null
+++ b/src/vue/components/GnUsageMeter.js
@@ -0,0 +1,26 @@
+import { defineComponent, h } from "vue";
+import GnProgress from "./GnProgress.js";
+
+export default defineComponent({
+ name: "GnUsageMeter",
+ props: {
+ title: { type: String, required: true },
+ value: { type: Number, required: true },
+ max: { type: Number, default: 100 },
+ meta: { type: String, default: "" }
+ },
+ setup(props, { slots }) {
+ return () => {
+ const percent = Math.max(0, Math.min(100, Math.round((props.value / props.max) * 100)));
+
+ return h("section", { class: "usage-meter" }, [
+ h("h3", { class: "usage-meter-title" }, [
+ slots.title?.() || props.title,
+ h("span", { class: "usage-meter-value" }, `${percent}%`)
+ ]),
+ h(GnProgress, { value: props.value, max: props.max }),
+ (props.meta || slots.meta) && h("p", { class: "usage-meter-meta" }, slots.meta?.() || props.meta)
+ ]);
+ };
+ }
+});
diff --git a/src/vue/index.js b/src/vue/index.js
index 2e872f9..7541b3f 100644
--- a/src/vue/index.js
+++ b/src/vue/index.js
@@ -1,4 +1,6 @@
export { default as GnAccordion } from "./components/GnAccordion.js";
+export { default as GnActionCard } from "./components/GnActionCard.js";
+export { default as GnActionList } from "./components/GnActionList.js";
export { default as GnActivityLog } from "./components/GnActivityLog.js";
export { default as GnAlert } from "./components/GnAlert.js";
export { default as GnAvatar } from "./components/GnAvatar.js";
@@ -12,6 +14,7 @@
export { default as GnCombobox } from "./components/GnCombobox.js";
export { default as GnConfirmDialog } from "./components/GnConfirmDialog.js";
export { default as GnDescriptionList } from "./components/GnDescriptionList.js";
+export { default as GnDefinitionList } from "./components/GnDefinitionList.js";
export { default as GnDropdown } from "./components/GnDropdown.js";
export { default as GnDrawer } from "./components/GnDrawer.js";
export { default as GnEmptyState } from "./components/GnEmptyState.js";
@@ -20,6 +23,9 @@
export { default as GnIdentity } from "./components/GnIdentity.js";
export { default as GnInput } from "./components/GnInput.js";
export { default as GnInputGroup } from "./components/GnInputGroup.js";
+export { default as GnList } from "./components/GnList.js";
+export { default as GnLoader } from "./components/GnLoader.js";
+export { default as GnMetricCard } from "./components/GnMetricCard.js";
export { default as GnModal } from "./components/GnModal.js";
export { default as GnNavList } from "./components/GnNavList.js";
export { default as GnNavigationShell } from "./components/GnNavigationShell.js";
@@ -27,6 +33,7 @@
export { default as GnPagination } from "./components/GnPagination.js";
export { default as GnPopover } from "./components/GnPopover.js";
export { default as GnProgress } from "./components/GnProgress.js";
+export { default as GnProgressStages } from "./components/GnProgressStages.js";
export { default as GnRadio } from "./components/GnRadio.js";
export { default as GnRadioGroup } from "./components/GnRadioGroup.js";
export { default as GnRange } from "./components/GnRange.js";
@@ -34,6 +41,7 @@
export { default as GnSelect } from "./components/GnSelect.js";
export { default as GnSkeleton } from "./components/GnSkeleton.js";
export { default as GnSteps } from "./components/GnSteps.js";
+export { default as GnStatusCard } from "./components/GnStatusCard.js";
export { default as GnSwitch } from "./components/GnSwitch.js";
export { default as GnTable } from "./components/GnTable.js";
export { default as GnTabs } from "./components/GnTabs.js";
@@ -42,5 +50,6 @@
export { default as GnTooltip } from "./components/GnTooltip.js";
export { default as GnToolbar } from "./components/GnToolbar.js";
export { default as GnToastProvider } from "./components/GnToastProvider.js";
+export { default as GnUsageMeter } from "./components/GnUsageMeter.js";
export { useToast } from "./composables/useToast.js";
export { components, default as GnexusUiVue } from "./plugin.js";
diff --git a/src/vue/plugin.js b/src/vue/plugin.js
index 5aa61c1..c11d739 100644
--- a/src/vue/plugin.js
+++ b/src/vue/plugin.js
@@ -1,4 +1,6 @@
import GnAccordion from "./components/GnAccordion.js";
+import GnActionCard from "./components/GnActionCard.js";
+import GnActionList from "./components/GnActionList.js";
import GnActivityLog from "./components/GnActivityLog.js";
import GnAlert from "./components/GnAlert.js";
import GnAvatar from "./components/GnAvatar.js";
@@ -12,6 +14,7 @@
import GnCombobox from "./components/GnCombobox.js";
import GnConfirmDialog from "./components/GnConfirmDialog.js";
import GnDescriptionList from "./components/GnDescriptionList.js";
+import GnDefinitionList from "./components/GnDefinitionList.js";
import GnDropdown from "./components/GnDropdown.js";
import GnDrawer from "./components/GnDrawer.js";
import GnEmptyState from "./components/GnEmptyState.js";
@@ -20,6 +23,9 @@
import GnIdentity from "./components/GnIdentity.js";
import GnInput from "./components/GnInput.js";
import GnInputGroup from "./components/GnInputGroup.js";
+import GnList from "./components/GnList.js";
+import GnLoader from "./components/GnLoader.js";
+import GnMetricCard from "./components/GnMetricCard.js";
import GnModal from "./components/GnModal.js";
import GnNavList from "./components/GnNavList.js";
import GnNavigationShell from "./components/GnNavigationShell.js";
@@ -27,6 +33,7 @@
import GnPagination from "./components/GnPagination.js";
import GnPopover from "./components/GnPopover.js";
import GnProgress from "./components/GnProgress.js";
+import GnProgressStages from "./components/GnProgressStages.js";
import GnRadio from "./components/GnRadio.js";
import GnRadioGroup from "./components/GnRadioGroup.js";
import GnRange from "./components/GnRange.js";
@@ -34,6 +41,7 @@
import GnSelect from "./components/GnSelect.js";
import GnSkeleton from "./components/GnSkeleton.js";
import GnSteps from "./components/GnSteps.js";
+import GnStatusCard from "./components/GnStatusCard.js";
import GnSwitch from "./components/GnSwitch.js";
import GnTable from "./components/GnTable.js";
import GnTabs from "./components/GnTabs.js";
@@ -42,9 +50,12 @@
import GnTooltip from "./components/GnTooltip.js";
import GnToolbar from "./components/GnToolbar.js";
import GnToastProvider from "./components/GnToastProvider.js";
+import GnUsageMeter from "./components/GnUsageMeter.js";
export const components = {
GnAccordion,
+ GnActionCard,
+ GnActionList,
GnActivityLog,
GnAlert,
GnAvatar,
@@ -58,6 +69,7 @@
GnCombobox,
GnConfirmDialog,
GnDescriptionList,
+ GnDefinitionList,
GnDropdown,
GnDrawer,
GnEmptyState,
@@ -66,6 +78,9 @@
GnIdentity,
GnInput,
GnInputGroup,
+ GnList,
+ GnLoader,
+ GnMetricCard,
GnModal,
GnNavList,
GnNavigationShell,
@@ -73,6 +88,7 @@
GnPagination,
GnPopover,
GnProgress,
+ GnProgressStages,
GnRadio,
GnRadioGroup,
GnRange,
@@ -80,6 +96,7 @@
GnSelect,
GnSkeleton,
GnSteps,
+ GnStatusCard,
GnSwitch,
GnTable,
GnTabs,
@@ -87,7 +104,8 @@
GnTimeline,
GnTooltip,
GnToolbar,
- GnToastProvider
+ GnToastProvider,
+ GnUsageMeter
};
export default {