764 lines
26 KiB
Vue
Executable File
764 lines
26 KiB
Vue
Executable File
<template>
|
|
<div class="">
|
|
<!-- Header: جستجو -->
|
|
<div class="mb-6 flex items-center gap-2" v-if="props.showSearch">
|
|
<UInput
|
|
v-model="searchQuery"
|
|
placeholder="...جستجو"
|
|
class="w-full max-w-xs bg-gray-100 dark:bg-dark-primary-800 border border-gray-300 dark:border-dark-primary-700 rounded px-3 py-2 text-dark-primary-800 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
/>
|
|
<UButton
|
|
v-if="searchQuery"
|
|
icon="heroicons:x-mark"
|
|
size="sm"
|
|
color="gray"
|
|
variant="ghost"
|
|
@click="searchQuery = ''"
|
|
class="px-2 py-1 rounded bg-gray-200 dark:bg-dark-primary-700 hover:bg-gray-300 dark:hover:bg-dark-primary-600 text-dark-primary-800 dark:text-gray-100 transition-colors"
|
|
/>
|
|
</div>
|
|
|
|
<!-- جدول / کارتها -->
|
|
<div
|
|
class="bg-white dark:bg-dark-primary-800 rounded-lg overflow-hidden shadow-md border border-gray-200 dark:border-dark-primary-700"
|
|
>
|
|
<!-- حالت دسکتاپ: جدول -->
|
|
<div class="hidden md:block">
|
|
<div
|
|
class="bg-white dark:bg-dark-primary-800 rounded-lg overflow-hidden shadow-md border border-gray-200 dark:border-dark-primary-700"
|
|
>
|
|
<table
|
|
class="w-full text-sm min-w-full"
|
|
style="table-layout: fixed; border-collapse: collapse"
|
|
>
|
|
<thead
|
|
class="bg-gray-50 dark:bg-dark-primary text-dark-primary-700 dark:text-gray-300"
|
|
style="display: table; width: 100%; table-layout: fixed"
|
|
>
|
|
<tr>
|
|
<th
|
|
class="px-4 py-3 text-right text-xs font-medium uppercase tracking-wider whitespace-nowrap"
|
|
style="width: 3rem"
|
|
>
|
|
#
|
|
</th>
|
|
<th
|
|
v-for="col in tableColumns"
|
|
:key="col.key"
|
|
:style="{ width: col.width ? col.width : 'auto' }"
|
|
class="px-4 py-3 text-right text-xs font-medium uppercase tracking-wider"
|
|
>
|
|
{{ col.title }}
|
|
</th>
|
|
<th
|
|
class="px-4 py-3 text-right text-xs font-medium uppercase tracking-wider whitespace-nowrap"
|
|
style="width: 6rem"
|
|
v-if="props.actionButtons?.length"
|
|
>
|
|
عملیات
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
</table>
|
|
|
|
<!-- بدنه جدول با اسکرول عمودی -->
|
|
<div
|
|
class="overflow-y-auto"
|
|
:style="
|
|
props.tableBodyMaxHeight
|
|
? { maxHeight: props.tableBodyMaxHeight }
|
|
: {}
|
|
"
|
|
>
|
|
<table
|
|
class="w-full text-sm min-w-full"
|
|
style="table-layout: fixed; border-collapse: collapse"
|
|
>
|
|
<tbody style="display: block; width: 100%">
|
|
<tr
|
|
v-for="(item, index) in searchedItems"
|
|
:key="item.id"
|
|
class="border-t border-gray-200 dark:border-dark-primary-700 cursor-move"
|
|
:class="index % 2 === 0 ? 'even-row' : 'odd-row'"
|
|
style="display: table; width: 100%; table-layout: fixed"
|
|
:draggable="props.draggableRows"
|
|
@dragstart="props.draggableRows && onRowDragStart(item)"
|
|
>
|
|
<!-- شماره ردیف -->
|
|
<td class="p-0" style="width: 3rem">
|
|
<div
|
|
class="w-full h-full flex items-center justify-center px-4 text-sm font-medium"
|
|
:style="{
|
|
paddingTop: pyClassValue,
|
|
paddingBottom: pyClassValue,
|
|
}"
|
|
>
|
|
{{ item.rowNumber }}
|
|
</div>
|
|
</td>
|
|
|
|
<!-- سلولهای داده -->
|
|
<td
|
|
v-for="col in tableColumns"
|
|
:key="col.key"
|
|
:style="{ width: col.width ? col.width : 'auto' }"
|
|
class="p-0"
|
|
>
|
|
<UContextMenu
|
|
v-if="col.contextmenu"
|
|
:items="getMenuItemsWithHandler(col, item, index)"
|
|
:ui="{ content: 'w-48' }"
|
|
>
|
|
<div
|
|
class="w-full h-full flex items-center px-4 text-right break-words text-sm"
|
|
:style="{
|
|
paddingTop: pyClassValue,
|
|
paddingBottom: pyClassValue,
|
|
}"
|
|
@click="
|
|
!col.isLink &&
|
|
handleInteraction({
|
|
type: 'click',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
@dblclick="
|
|
handleInteraction({
|
|
type: 'dblclick',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
>
|
|
<span
|
|
v-if="col.isLink"
|
|
@click.stop="
|
|
handleInteraction({
|
|
type: 'link',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
class="text-blue-600 dark:text-blue-400 hover:underline cursor-pointer"
|
|
v-html="getCellValue(item, col)"
|
|
>
|
|
</span>
|
|
<span v-else v-html="getCellValue(item, col)"></span>
|
|
</div>
|
|
</UContextMenu>
|
|
|
|
<div
|
|
v-else
|
|
class="w-full cursor-pointer h-full flex items-center px-4 text-right break-words text-sm whitespace-normal"
|
|
:style="{
|
|
paddingTop: pyClassValue,
|
|
paddingBottom: pyClassValue,
|
|
}"
|
|
@click="
|
|
!col.isLink &&
|
|
handleInteraction({
|
|
type: 'click',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
@dblclick="
|
|
handleInteraction({
|
|
type: 'dblclick',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
>
|
|
<span
|
|
v-if="col.isLink"
|
|
@click.stop="
|
|
handleInteraction({
|
|
type: 'link',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
class="text-blue-600 dark:text-blue-400 hover:underline cursor-pointer"
|
|
v-html="getCellValue(item, col)"
|
|
>
|
|
</span>
|
|
<span v-else v-html="getCellValue(item, col)"></span>
|
|
</div>
|
|
</td>
|
|
|
|
<!-- عملیات -->
|
|
<td
|
|
v-if="props.actionButtons?.length"
|
|
class="p-0 pl-2"
|
|
style="width: 6rem"
|
|
>
|
|
<div
|
|
class="w-full h-full flex items-center justify-center px-4"
|
|
:style="{
|
|
paddingTop: pyClassValue,
|
|
paddingBottom: pyClassValue,
|
|
}"
|
|
>
|
|
<div class="flex gap-2">
|
|
<UButton
|
|
v-if="props.actionButtons.length <= 3"
|
|
v-for="btn in props.actionButtons"
|
|
:key="btn.key"
|
|
:icon="btn.icon"
|
|
size="md"
|
|
:color="getButtonColor(btn.key)"
|
|
variant="ghost"
|
|
square
|
|
@click.stop="
|
|
handleActionFromButton(btn.key, item, index, $event)
|
|
"
|
|
/>
|
|
<ClientOnly>
|
|
<UDropdownMenu
|
|
v-if="props.actionButtons.length > 3"
|
|
:items="
|
|
allActionMenuItems(
|
|
props.actionButtons,
|
|
item,
|
|
index
|
|
)
|
|
"
|
|
>
|
|
<UButton
|
|
icon="heroicons:ellipsis-vertical"
|
|
size="xs"
|
|
color="gray"
|
|
variant="ghost"
|
|
square
|
|
/>
|
|
</UDropdownMenu>
|
|
</ClientOnly>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- بدون داده -->
|
|
<tr v-if="searchedItems.length === 0">
|
|
<td
|
|
:colspan="tableColumns.length + 2"
|
|
class="py-8 text-center text-gray-400 dark:text-gray-500 text-sm"
|
|
>
|
|
❌ دادهای یافت نشد
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- حالت موبایل: کارتها -->
|
|
<div class="md:hidden">
|
|
<div
|
|
class="overflow-y-auto px-4 py-2"
|
|
:style="
|
|
props.tableBodyMaxHeight
|
|
? { maxHeight: props.tableBodyMaxHeight }
|
|
: {}
|
|
"
|
|
>
|
|
<div class="space-y-4">
|
|
<div
|
|
v-for="(item, index) in searchedItems"
|
|
:key="item.id"
|
|
class="border border-gray-200 dark:border-dark-primary-700 rounded-lg p-4 bg-white dark:bg-dark-primary-800 shadow-sm"
|
|
:class="index % 2 === 0 ? 'even-row' : 'odd-row'"
|
|
:draggable="props.draggableRows"
|
|
@dragstart="props.draggableRows && onRowDragStart(item)"
|
|
>
|
|
<div class="space-y-3">
|
|
<!-- شماره ردیف -->
|
|
<div class="flex justify-between items-start gap-2">
|
|
<span
|
|
class="text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
>
|
|
ردیف
|
|
</span>
|
|
<span
|
|
class="text-right text-sm font-medium text-dark-primary dark:text-gray-100"
|
|
>
|
|
{{ item.rowNumber }}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- سایر ستونها -->
|
|
<div
|
|
v-for="col in tableColumns"
|
|
:key="col.key"
|
|
class="flex justify-between items-start gap-2"
|
|
>
|
|
<span
|
|
class="text-xs font-medium text-gray-500 dark:text-gray-400 min-w-0"
|
|
>
|
|
{{ col.title }}
|
|
</span>
|
|
<div
|
|
class="text-right flex-1 text-sm text-dark-primary dark:text-gray-100"
|
|
>
|
|
<UContextMenu
|
|
v-if="col.contextmenu"
|
|
:items="getMenuItemsWithHandler(col, item, index)"
|
|
:ui="{ content: 'w-48' }"
|
|
>
|
|
<span
|
|
v-if="col.isLink"
|
|
@click="
|
|
handleInteraction({
|
|
type: 'link',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
class="text-blue-600 dark:text-blue-400 hover:underline cursor-pointer"
|
|
v-html="getCellValue(item, col)"
|
|
></span>
|
|
<span
|
|
v-else
|
|
@click="
|
|
!col.isLink &&
|
|
handleInteraction({
|
|
type: 'click',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
@dblclick="
|
|
handleInteraction({
|
|
type: 'dblclick',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
class="cursor-pointer"
|
|
v-html="getCellValue(item, col)"
|
|
></span>
|
|
</UContextMenu>
|
|
|
|
<template v-else>
|
|
<span
|
|
v-if="col.isLink"
|
|
@click="
|
|
handleInteraction({
|
|
type: 'link',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
class="text-blue-600 dark:text-blue-400 hover:underline cursor-pointer"
|
|
v-html="getCellValue(item, col)"
|
|
></span>
|
|
<span
|
|
v-else
|
|
@click="
|
|
!col.isLink &&
|
|
handleInteraction({
|
|
type: 'click',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
@dblclick="
|
|
handleInteraction({
|
|
type: 'dblclick',
|
|
column: col,
|
|
item,
|
|
value: getCellValue(item, col),
|
|
index,
|
|
event: $event,
|
|
})
|
|
"
|
|
class="cursor-pointer"
|
|
v-html="getCellValue(item, col)"
|
|
></span>
|
|
</template>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- دکمههای عملیات -->
|
|
<div
|
|
class="flex justify-end gap-2 mt-4"
|
|
v-if="props.actionButtons?.length"
|
|
>
|
|
<UButton
|
|
v-if="props.actionButtons.length <= 3"
|
|
v-for="btn in props.actionButtons"
|
|
:key="btn.key"
|
|
:icon="btn.icon"
|
|
size="xs"
|
|
:color="getButtonColor(btn.key)"
|
|
variant="ghost"
|
|
square
|
|
@click.stop="
|
|
handleActionFromButton(btn.key, item, index, $event)
|
|
"
|
|
/>
|
|
<ClientOnly>
|
|
<UDropdownMenu
|
|
v-if="props.actionButtons.length > 3"
|
|
:items="
|
|
allActionMenuItems(props.actionButtons, item, index)
|
|
"
|
|
>
|
|
<UButton
|
|
icon="heroicons:ellipsis-vertical"
|
|
size="xs"
|
|
color="gray"
|
|
variant="ghost"
|
|
square
|
|
/>
|
|
</UDropdownMenu>
|
|
</ClientOnly>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
v-if="searchedItems.length === 0"
|
|
class="text-center py-8 text-gray-400 dark:text-gray-500 text-sm"
|
|
>
|
|
❌ دادهای یافت نشد
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, watch } from "vue";
|
|
|
|
const props = defineProps({
|
|
tableColumns: { type: Array, required: true },
|
|
actionButtons: { type: Array, default: () => [] },
|
|
rawData: { type: Array, required: true },
|
|
cellMenuItems: { type: Array, default: () => [] },
|
|
showSearch: { type: Boolean, default: true },
|
|
tableBodyMaxHeight: { type: String, default: "80dvh" },
|
|
pagination: { type: Object, required: true },
|
|
draggableRows: { type: Boolean, default: false },
|
|
});
|
|
|
|
const emit = defineEmits(["my-table-action", "drag-start"]);
|
|
|
|
const searchQuery = ref("");
|
|
const clickTimer = ref(null);
|
|
const pyClassValue = "0.75rem"; // میتوانید از props هم بگیرید
|
|
|
|
// شماره ردیف پایدار
|
|
const rowNumberMap = ref(new Map());
|
|
const nextRowNumber = ref(1);
|
|
|
|
const getItemKey = (item, idx) => {
|
|
if (!item) return `__idx_${idx}`;
|
|
if (item.id) return String(item.id);
|
|
if (item._id) return String(item._id);
|
|
if (item._source && (item._source.id || item._source._id))
|
|
return String(item._source.id || item._source._id);
|
|
try {
|
|
return JSON.stringify(item);
|
|
} catch {
|
|
return `__idx_${idx}`;
|
|
}
|
|
};
|
|
|
|
watch(
|
|
() => props.rawData,
|
|
(newVal) => {
|
|
if (!Array.isArray(newVal)) return;
|
|
newVal.forEach((rawItem, idx) => {
|
|
const key = getItemKey(rawItem, idx);
|
|
if (!rowNumberMap.value.has(key)) {
|
|
rowNumberMap.value.set(key, nextRowNumber.value++);
|
|
}
|
|
});
|
|
},
|
|
{ immediate: true, deep: true }
|
|
);
|
|
|
|
const processedData = computed(() => {
|
|
if (!Array.isArray(props.rawData)) return [];
|
|
|
|
const offset = props.pagination?.offset ?? 0;
|
|
|
|
return props.rawData.map((item, idx) => {
|
|
const key = getItemKey(item, idx);
|
|
const computedId = item._id || item.id || key;
|
|
|
|
const rowNumber = offset + idx + 1;
|
|
|
|
return {
|
|
...item,
|
|
id: computedId,
|
|
rowNumber,
|
|
};
|
|
});
|
|
});
|
|
|
|
const searchedItems = computed(() => {
|
|
if (!searchQuery.value) return processedData.value;
|
|
|
|
const q = searchQuery.value.toLowerCase();
|
|
return processedData.value.filter((item) =>
|
|
Object.values(item).some((val) =>
|
|
String(val ?? "")
|
|
.toLowerCase()
|
|
.includes(q)
|
|
)
|
|
);
|
|
});
|
|
|
|
const getButtonColor = (key) => {
|
|
return { edit: "primary", delete: "red", clone: "green" }[key] || "gray";
|
|
};
|
|
|
|
// ====================== getCellValue اصلی ======================
|
|
|
|
const getObjectText = (schema, data) => {
|
|
let text = "";
|
|
if (schema.is_object == 1 && schema.object_text) {
|
|
Object.keys(schema.object_text).forEach((k) => {
|
|
if (data[k] !== undefined) {
|
|
if (schema.object_text[k]) text += " - " + schema.object_text[k] + ":";
|
|
text += data[k];
|
|
}
|
|
});
|
|
} else {
|
|
text = String(data);
|
|
}
|
|
return text;
|
|
};
|
|
|
|
const formatDateToPersian = (item) => {
|
|
if (!item) return "";
|
|
|
|
let date;
|
|
const num = Number(item);
|
|
|
|
if (!isNaN(num) && item.toString().length === 10) {
|
|
date = new Date(item * 1000);
|
|
} else if (typeof item === "string" && !item.includes("T00:00:00")) {
|
|
date = new Date(item + "T00:00:00");
|
|
} else {
|
|
date = new Date(item);
|
|
}
|
|
|
|
if (isNaN(date.getTime())) return item;
|
|
|
|
return date.toLocaleDateString("fa-IR");
|
|
};
|
|
|
|
const getCellValue = (rowItem, column) => {
|
|
let key = column.key;
|
|
let trancate_word = column?.trancate_word;
|
|
let value = "";
|
|
|
|
if (rowItem.highlight && key in rowItem.highlight) {
|
|
if (Array.isArray(rowItem.highlight[key])) {
|
|
value = rowItem.highlight[key][0];
|
|
} else {
|
|
value = rowItem.highlight[key];
|
|
}
|
|
return value;
|
|
}
|
|
|
|
let rowItem_data = rowItem._source ?? rowItem;
|
|
if (!rowItem_data) return "";
|
|
|
|
key = key.replace("__", ".");
|
|
if (key.includes(".")) {
|
|
const keys = key.split(".");
|
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
if (rowItem_data[keys[i]] !== undefined) {
|
|
rowItem_data = rowItem_data[keys[i]];
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
key = keys[keys.length - 1];
|
|
}
|
|
|
|
if (column?.object_text && rowItem_data[column.key]) {
|
|
const data = rowItem_data[column.key];
|
|
if (column.is_array == 1 && Array.isArray(data)) {
|
|
data.forEach((el) => {
|
|
const text = getObjectText(column, el);
|
|
if (text) value += text + "-";
|
|
});
|
|
} else {
|
|
value = getObjectText(column, data);
|
|
}
|
|
}
|
|
|
|
if (value === "" && rowItem_data[key] !== undefined) {
|
|
value = rowItem_data[key];
|
|
}
|
|
|
|
if (value && trancate_word && trancate_word > 0) {
|
|
const words = String(value).split(" ");
|
|
if (words.length > trancate_word) {
|
|
value = words.slice(0, trancate_word).join(" ") + "...";
|
|
}
|
|
}
|
|
|
|
if (value !== "" && column?.process) {
|
|
if (column.process === "len") {
|
|
return String(value).length;
|
|
} else if (
|
|
column.process === "convert_date" ||
|
|
column.process === "convert_gdate"
|
|
) {
|
|
return formatDateToPersian(value);
|
|
}
|
|
}
|
|
|
|
if (
|
|
value !== "" &&
|
|
(key.toLowerCase().includes("date") || key.toLowerCase().includes("time"))
|
|
) {
|
|
return formatDateToPersian(value);
|
|
}
|
|
|
|
if (column?.colors && value in column.colors) {
|
|
value = `<span style="color:${column.colors[value]}">${value}</span>`;
|
|
}
|
|
|
|
return value ?? "";
|
|
};
|
|
|
|
// ====================== Action & Interaction Handlers ======================
|
|
const emitAction = (actionKey, item, index) => {
|
|
const payload = {
|
|
column: null,
|
|
item,
|
|
index,
|
|
menuItem: props.actionButtons.find((b) => b.key === actionKey),
|
|
};
|
|
emit("my-table-action", { action: actionKey, payload: payload });
|
|
};
|
|
|
|
const handleActionFromButton = (actionKey, item, index, event) => {
|
|
event.stopPropagation();
|
|
emitAction(actionKey, item, index);
|
|
};
|
|
|
|
const allActionMenuItems = (buttons, item, index) => {
|
|
if (buttons.length <= 3) return [];
|
|
return buttons.map((btn) => ({
|
|
label: btn.title || btn.key,
|
|
icon: btn.icon,
|
|
onSelect: () => emitAction(btn.key, item, index),
|
|
}));
|
|
};
|
|
|
|
const getMenuItemsWithHandler = (column, item, index) => {
|
|
return props.cellMenuItems.map((section) =>
|
|
section.map((menuItem) => ({
|
|
...menuItem,
|
|
onSelect: () => {
|
|
emit("my-table-action", {
|
|
type: "contextmenu",
|
|
column,
|
|
item,
|
|
value: getCellValue(item, column),
|
|
index,
|
|
menuItem,
|
|
});
|
|
},
|
|
}))
|
|
);
|
|
};
|
|
|
|
const handleInteraction = ({ type, column, item, value, index, event }) => {
|
|
if (type === "click" && event?.detail > 1) return;
|
|
if (type === "link") {
|
|
emit("my-table-action", { type, column, item, value, index, event });
|
|
return;
|
|
}
|
|
if (type === "dblclick") {
|
|
if (clickTimer.value) clearTimeout(clickTimer.value);
|
|
emit("my-table-action", { type, column, item, value, index, event });
|
|
return;
|
|
}
|
|
if (type === "click") {
|
|
if (clickTimer.value) clearTimeout(clickTimer.value);
|
|
clickTimer.value = setTimeout(() => {
|
|
emit("my-table-action", { type, column, item, value, index, event });
|
|
clickTimer.value = null;
|
|
}, 200);
|
|
}
|
|
};
|
|
const onRowDragStart = (item) => {
|
|
if (!props.draggableRows) return;
|
|
emit("drag-start", item);
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
table {
|
|
table-layout: fixed;
|
|
}
|
|
td {
|
|
word-wrap: break-word;
|
|
word-break: break-word;
|
|
}
|
|
.even-row {
|
|
background-color: #f9fafb;
|
|
}
|
|
.odd-row {
|
|
background-color: #ffffff;
|
|
}
|
|
.dark .even-row {
|
|
background-color: #1f2937;
|
|
}
|
|
.dark .odd-row {
|
|
background-color: #111827;
|
|
}
|
|
</style>
|
|
<style>
|
|
.text__orange {
|
|
color: var(--color-text__orange);
|
|
}
|
|
</style>
|