Skip to content

Commit

Permalink
Add data component to ui package (#447)
Browse files Browse the repository at this point in the history
* feat: add data component to ui package

* feat: add data component demo to ui page

* feat: add separator slot and direction props to data

* chore: sort demo  variables alphabetically

* chore: add slot for data value
  • Loading branch information
KabinKhandThakuri authored Jan 6, 2025
1 parent 51e3adc commit 21b41e0
Show file tree
Hide file tree
Showing 8 changed files with 356 additions and 0 deletions.
13 changes: 13 additions & 0 deletions apps/demo/src/locales/en/ui.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,19 @@
"withI18n": "With i18n"
}
},
"data": {
"label": {
"email": "Email",
"name": "Name"
},
"title": "Data",
"usage": {
"basic": "Basic",
"displayObject": "Display value from object",
"separatorSlot": "With separator slot",
"structuredData": "Rendering structured data"
}
},
"divider": {
"title": "Divider",
"usage": {
Expand Down
13 changes: 13 additions & 0 deletions apps/demo/src/locales/fr/ui.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,19 @@
"withI18n": "With i18n"
}
},
"data": {
"label": {
"email": "Email",
"name": "Name"
},
"title": "Data",
"usage": {
"basic": "Basic",
"displayObject": "Display value from object",
"separatorSlot": "With separator slot",
"structuredData": "Rendering structured data"
}
},
"divider": {
"title": "Divider",
"usage": {
Expand Down
6 changes: 6 additions & 0 deletions apps/demo/src/router/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const Button = () => import("@/views/UI/button/Index.vue");
const Card = () => import("@/views/UI/card/Index.vue");
const ConfirmationModal = () =>
import("@/views/UI/confirmationModal/Index.vue");
const Data = () => import("@/views/UI/data/Index.vue");
const Divider = () => import("@/views/UI/divider/Index.vue");
const Dropdown = () => import("@/views/UI/dropdown/Index.vue");
const GridContainer = () => import("@/views/UI/gridContainer/Index.vue");
Expand Down Expand Up @@ -64,6 +65,11 @@ const routes = [
name: "confirmationModal",
path: "confirmation-modal",
},
{
component: Data,
name: "data",
path: "data",
},
{
component: GridContainer,
name: "gridContainer",
Expand Down
4 changes: 4 additions & 0 deletions apps/demo/src/views/UI/UiPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ const menu = [
name: "Confirmation modal",
routeName: "confirmationModal",
},
{
name: "Data",
routeName: "data",
},
{
name: "Divider",
routeName: "divider",
Expand Down
216 changes: 216 additions & 0 deletions apps/demo/src/views/UI/data/Index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
<template>
<UiPage :title="$t('ui.data.title')" class="demo">
<template #toolbar>
<router-link :to="{ name: 'ui' }" class="back">
{{ $t("common.back") }}
</router-link>
</template>

<section>
<h2>{{ $t("ui.data.usage.basic") }}</h2>

<div class="section-content">
<!-- eslint-disable -->
<SshPre language="html-vue">
&lt;template&gt;
&lt;Data label="Name" value="John Doe" /&gt;
&lt;/template&gt;

&lt;script setup lang="ts"&gt;
import { Data } from "@dzangolab/vue3-ui";
&lt;/script&gt;
</SshPre>
<!-- eslint-enable -->

<Data :label="$t('ui.data.label.name')" :value="userData.name" />
</div>
</section>

<section>
<h2>{{ $t("ui.data.usage.displayObject") }}</h2>

<div class="section-content">
<!-- eslint-disable -->
<SshPre language="html-vue">
&lt;template&gt;
&lt;Data
:value="userData"
data-key="email"
label="Email"
/&gt;
&lt;/template&gt;

&lt;script setup lang="ts"&gt;
import { Data } from "@dzangolab/vue3-ui";

const userData = {
email: "john.doe@example.com",
name: "John Doe",
};
&lt;/script&gt;
</SshPre>
<!-- eslint-enable -->

<Data
:label="$t('ui.data.label.email')"
:value="userData"
data-key="email"
/>
</div>
</section>

<section>
<h2>{{ $t("ui.data.usage.structuredData") }}</h2>

<div class="section-content">
<!-- eslint-disable -->
<SshPre language="html-vue">
&lt;template&gt;
&lt;GridContainer&gt;
&lt;Data v-for="(data, index) in data" :key="index" v-bind="data" /&gt;
&lt;/GridContainer&gt;
&lt;/template&gt;

&lt;script setup lang="ts"&gt;
import { Data, GridContainer } from "@dzangolab/vue3-ui";

const data = [
{
label: "Name",
value: "John Doe",
},
{
label: "Age",
value: 30,
},
{
label: "Email",
value: {
email: "john.doe@example.com",
user: "John Doe",
},
dataKey: "email",
},
{
label: "Address",
value: "123 Main St, Springfield, USA",
},
{
label: "Status",
value: "Active",
},
];
&lt;/script&gt;
</SshPre>
<!-- eslint-enable -->

<GridContainer>
<Data
v-for="(data, index) in structuredData"
:key="index"
v-bind="data"
/>
</GridContainer>
</div>
</section>

<section>
<h2>{{ $t("ui.data.usage.separatorSlot") }}</h2>

<div class="section-content">
<!-- eslint-disable -->
<SshPre language="html-vue">
&lt;template&gt;
&lt;Data
v-for="(data, index) in data"
:key="index"
v-bind="data"
direction="horizontal"
&gt;
&lt;template #separator&gt;:&lt;/template&gt;
&lt;/Data&gt;
&lt;/template&gt;

&lt;script setup lang="ts"&gt;
import { Data } from "@dzangolab/vue3-ui";

const data = [
{
label: "Name",
value: "John Doe",
},
{
label: "Age",
value: 30,
},
{
label: "Email",
value: {
email: "john.doe@example.com",
user: "John Doe",
},
dataKey: "email",
},
{
label: "Address",
value: "123 Main St, Springfield, USA",
},
{
label: "Status",
value: "Active",
},
];
&lt;/script&gt;
</SshPre>
<!-- eslint-enable -->

<Data
v-for="(data, index) in structuredData"
:key="index"
v-bind="data"
direction="horizontal"
>
<template #separator>:</template>
</Data>
</div>
</section>
</UiPage>
</template>

<script setup lang="ts">
import { Data, GridContainer } from "@dzangolab/vue3-ui";
import UiPage from "../UiPage.vue";
const structuredData = [
{
label: "Name",
value: "John Doe",
},
{
label: "Age",
value: 30,
},
{
label: "Email",
value: {
email: "john.doe@example.com",
user: "John Doe",
},
dataKey: "email",
},
{
label: "Address",
value: "123 Main St, Springfield, USA",
},
{
label: "Status",
value: "Active",
},
];
const userData = {
email: "john.doe@example.com",
name: "John Doe",
};
</script>
63 changes: 63 additions & 0 deletions packages/vue-ui/src/Data/Index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<template>
<div :class="`data direction-${direction}`">
<span class="data-label">{{ label }}</span>
<span v-if="slots.separator" class="separator">
<slot name="separator"></slot>
</span>
<span class="data-value">
<slot name="value">
{{ displayValue }}
</slot>
</span>
</div>
</template>

<script lang="ts">
export default {
name: "DataElement",
};
</script>

<script setup lang="ts">
import { computed, useSlots } from "vue";
import type { PropType } from "vue";
const props = defineProps({
dataKey: {
default: undefined,
type: String,
},
direction: {
default: "vertical",
type: String,
validator: (value: string) => ["horizontal", "vertical"].includes(value),
},
label: {
type: [String, Number, Object] as PropType<string | number>,
required: true,
},
value: {
type: [Object, String, Number] as PropType<string | number | object>,
required: true,
},
});
const slots = useSlots();
const displayValue = computed(() => {
if (
props.dataKey &&
typeof props.value === "object" &&
props.value !== null &&
props.dataKey in props.value
) {
return props.value[props.dataKey as keyof typeof props.value];
}
return props.value;
});
</script>

<style lang="css">
@import "../assets/css/data.css";
</style>
39 changes: 39 additions & 0 deletions packages/vue-ui/src/assets/css/data.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.data {
display: flex;
flex-direction: column;
gap: 0.25rem;
}

.data.direction-horizontal > .data-label {
--_width: var(--data-label-width, 8rem);

overflow-x: hidden;
text-overflow: ellipsis;
width: var(--_width);
}

.data > .data-label {
font-size: 0.875rem;
line-height: 1.5;
}

.data > .data-value {
font-weight: 500;
line-height: 1.5;
}

.data > .separator {
display: none;
}

@media screen and (min-width: 576px) {
.data.direction-horizontal {
align-items: center;
flex-direction: row;
gap: 1rem;
}

.data > .separator {
display: block;
}
}
Loading

0 comments on commit 21b41e0

Please sign in to comment.