diff --git a/404.html b/404.html index 5ec3c19d2..f4f686fc1 100644 --- a/404.html +++ b/404.html @@ -13,7 +13,7 @@ - +
diff --git a/assets/js/0f6f7c87.5573ae14.js b/assets/js/0f6f7c87.aa6d996c.js similarity index 71% rename from assets/js/0f6f7c87.5573ae14.js rename to assets/js/0f6f7c87.aa6d996c.js index c092d8d7b..c8804a83a 100644 --- a/assets/js/0f6f7c87.5573ae14.js +++ b/assets/js/0f6f7c87.aa6d996c.js @@ -1 +1 @@ -"use strict";(self.webpackChunkadminforth=self.webpackChunkadminforth||[]).push([[1768],{9706:(n,e,t)=>{t.r(e),t.d(e,{assets:()=>c,contentTitle:()=>r,default:()=>u,frontMatter:()=>s,metadata:()=>i,toc:()=>d});var o=t(4848),a=t(8453);const s={},r="Page Injections",i={id:"tutorial/Customization/pageInjections",title:"Page Injections",description:"In addition to ability to create custom pages and overwrite how fields are rendered, you can also inject custom components in standard AdminForth page.",source:"@site/docs/tutorial/03-Customization/08-pageInjections.md",sourceDirName:"tutorial/03-Customization",slug:"/tutorial/Customization/pageInjections",permalink:"/docs/tutorial/Customization/pageInjections",draft:!1,unlisted:!1,tags:[],version:"current",sidebarPosition:8,frontMatter:{},sidebar:"tutorialSidebar",previous:{title:"Alerts and confirmations",permalink:"/docs/tutorial/Customization/alert"},next:{title:"Custom bulk actions",permalink:"/docs/tutorial/Customization/bulkActions"}},c={},d=[];function l(n){const e={blockquote:"blockquote",code:"code",h1:"h1",img:"img",p:"p",pre:"pre",...(0,a.R)(),...n.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(e.h1,{id:"page-injections",children:"Page Injections"}),"\n",(0,o.jsx)(e.p,{children:"In addition to ability to create custom pages and overwrite how fields are rendered, you can also inject custom components in standard AdminForth page."}),"\n",(0,o.jsxs)(e.p,{children:["For example let's add a custom pie chart to the ",(0,o.jsx)(e.code,{children:"list"})," page of the ",(0,o.jsx)(e.code,{children:"aparts"})," resource. Pie chart will show the distribution of the rooms count and more over will allow to filter the list by the rooms count."]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-ts",metastring:'title="/index.ts"',children:"{\n resourceId: 'aparts',\n ...\n//diff-add\n options: {\n//diff-add\n pageInjections: {\n//diff-add\n list: {\n//diff-add\n afterBreadcrumbs: '@@/ApartsPie.vue',\n//diff-add\n }\n//diff-add\n } \n//diff-add\n }\n}\n"})}),"\n",(0,o.jsxs)(e.p,{children:["Now create file ",(0,o.jsx)(e.code,{children:"ApartsPie.vue"})," in the ",(0,o.jsx)(e.code,{children:"custom"})," folder of your project:"]}),"\n",(0,o.jsx)(e.pre,{children:(0,o.jsx)(e.code,{className:"language-html",metastring:'title="./custom/ApartsPie.vue"',children:'\nPlease note that @@/
is a special prefix which tells AdminForth to look for the file in the custom
directory.
You can use @@/
prefix for all paths in the configuration and also import images like this in your custom components e.g.:
<template>
<img src="@@/myFile.svg" alt="logo">
</template>
To completely remove brand name from sidebar and header, set it to empty string:
+brandName: 'My App',
brandName: '',
AdminForth uses TailwindCSS for styling. By default both black and light thems the same as for Tailwind, but you able to customize the look of the application by changing the TailwindCSS configuration.
Use styles.ts file to see which variables are available for change.
diff --git a/docs/tutorial/Customization/bulkActions/index.html b/docs/tutorial/Customization/bulkActions/index.html index 2503341c9..212f99b8d 100644 --- a/docs/tutorial/Customization/bulkActions/index.html +++ b/docs/tutorial/Customization/bulkActions/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/customFieldRendering/index.html b/docs/tutorial/Customization/customFieldRendering/index.html index 671ad396f..28b09c3c7 100644 --- a/docs/tutorial/Customization/customFieldRendering/index.html +++ b/docs/tutorial/Customization/customFieldRendering/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/customPages/index.html b/docs/tutorial/Customization/customPages/index.html index 636c874ac..948373f5d 100644 --- a/docs/tutorial/Customization/customPages/index.html +++ b/docs/tutorial/Customization/customPages/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/hooks/index.html b/docs/tutorial/Customization/hooks/index.html index 89bfec19b..ab523c7d3 100644 --- a/docs/tutorial/Customization/hooks/index.html +++ b/docs/tutorial/Customization/hooks/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/limitingAccess/index.html b/docs/tutorial/Customization/limitingAccess/index.html index a79541614..4c803e2de 100644 --- a/docs/tutorial/Customization/limitingAccess/index.html +++ b/docs/tutorial/Customization/limitingAccess/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Customization/pageInjections/index.html b/docs/tutorial/Customization/pageInjections/index.html index 3ba664703..5d86e213a 100644 --- a/docs/tutorial/Customization/pageInjections/index.html +++ b/docs/tutorial/Customization/pageInjections/index.html @@ -13,7 +13,7 @@ - + @@ -24,7 +24,7 @@Now create file ApartsPie.vue
in the custom
folder of your project:
<template>
<div class="max-w-sm w-full bg-white rounded-lg shadow dark:bg-gray-800 p-4 md:p-4 mb-5">
<div id="pie-chart"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, Ref } from 'vue';
import ApexCharts from 'apexcharts';
import { callApi } from '@/utils';
const data: Ref<any[]> = ref([]);
const POSSIBLE_COLORS = ["#1C64F2", "#16BDCA", "#9061F9", "#F0A936", "#F55252", "#3B82F6", "#10B981", "#F472B6", "#6B7280"];
const chatOptions = {
series: [],
colors: POSSIBLE_COLORS,
chart: {
height: 200,
width: "100%",
type: "pie",
events: {
dataPointSelection: function (event, chartContext, config) {
if (config.selectedDataPoints[0].length) {
const selectedRoomsCount = data.value[config.dataPointIndex].rooms;
window.adminforth.updateListFilter({field: 'number_of_rooms', operator: 'eq', value: selectedRoomsCount});
} else {
// clear filter
window.adminforth.updateListFilter({field: 'number_of_rooms', value: undefined});
}
}
},
},
stroke: {
colors: ["white"],
lineCap: "",
},
plotOptions: {
pie: {
labels: {
show: true,
},
size: "100%",
dataLabels: {
offset: -25
}
},
},
labels: ["Direct", "Organic search", "Referrals"],
dataLabels: {
enabled: true,
style: {
fontFamily: "Inter, sans-serif",
},
},
legend: {
position: "right",
fontFamily: "Inter, sans-serif",
},
yaxis: {
labels: {
formatter: function (value) {
return value + "%"
},
},
},
xaxis: {
labels: {
formatter: function (value) {
return value + "%"
},
},
axisTicks: {
show: false,
},
axisBorder: {
show: false,
},
},
}
onMounted(async () => {
try {
data.value = await callApi({path: '/api/aparts-by-room-percentages', method: 'GET'});
} catch (error) {
window.adminforth.alert({
message: `Error fetching data: ${error.message}`,
variant: 'danger',
timeout: 'unlimited'
});
return;
}
chatOptions.series = data.value.map((item) => item.percentage);
chatOptions.labels = data.value.map((item) => `${item.rooms} rooms`);
const chart = new ApexCharts(document.getElementById("pie-chart"), chatOptions);
chart.render();
})
</script>
Also we have to add an Api to get percentages:
- app.get('/api/aparts-by-room-percentages/',
admin.express.authorize(
async (req, res) => {
const roomPercentages = await db.prepare(
`SELECT
number_of_rooms,
COUNT(*) as count
FROM apartments
GROUP BY number_of_rooms
ORDER BY number_of_rooms;
`
).all();
const totalAparts = roomPercentages.reduce((acc, { count }) => acc + count, 0);
res.json(
roomPercentages.map(
({ number_of_rooms, count }) => ({
rooms: number_of_rooms,
percentage: Math.round(count / totalAparts * 100),
})
)
);
}
)
);
// serve after you added all api
admin.discoverDatabases();
admin.express.serve(app)
app.get(`${ADMIN_BASE_URL}/api/aparts-by-room-percentages/`,
admin.express.authorize(
async (req, res) => {
const roomPercentages = await db.prepare(
`SELECT
number_of_rooms,
COUNT(*) as count
FROM apartments
GROUP BY number_of_rooms
ORDER BY number_of_rooms;
`
).all();
const totalAparts = roomPercentages.reduce((acc, { count }) => acc + count, 0);
res.json(
roomPercentages.map(
({ number_of_rooms, count }) => ({
rooms: number_of_rooms,
percentage: Math.round(count / totalAparts * 100),
})
)
);
}
)
);
// serve after you added all api
admin.discoverDatabases();
admin.express.serve(app)
diff --git a/docs/tutorial/Customization/virtualColumns/index.html b/docs/tutorial/Customization/virtualColumns/index.html index 446296739..84175a21f 100644 --- a/docs/tutorial/Customization/virtualColumns/index.html +++ b/docs/tutorial/Customization/virtualColumns/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Plugins/AuditLog/index.html b/docs/tutorial/Plugins/AuditLog/index.html index 6a70a67b3..22cbab0ad 100644 --- a/docs/tutorial/Plugins/AuditLog/index.html +++ b/docs/tutorial/Plugins/AuditLog/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Plugins/ForeignInlineList/index.html b/docs/tutorial/Plugins/ForeignInlineList/index.html index 9563912f6..0668c16cf 100644 --- a/docs/tutorial/Plugins/ForeignInlineList/index.html +++ b/docs/tutorial/Plugins/ForeignInlineList/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Plugins/QuillEditor/index.html b/docs/tutorial/Plugins/QuillEditor/index.html index 7fd570d53..8efff96a4 100644 --- a/docs/tutorial/Plugins/QuillEditor/index.html +++ b/docs/tutorial/Plugins/QuillEditor/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Plugins/TwoFactorsAuth/index.html b/docs/tutorial/Plugins/TwoFactorsAuth/index.html index 794b240eb..516d56c8d 100644 --- a/docs/tutorial/Plugins/TwoFactorsAuth/index.html +++ b/docs/tutorial/Plugins/TwoFactorsAuth/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/Plugins/s3Upload/index.html b/docs/tutorial/Plugins/s3Upload/index.html index e94691485..afc7c5f5e 100644 --- a/docs/tutorial/Plugins/s3Upload/index.html +++ b/docs/tutorial/Plugins/s3Upload/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/deploy/index.html b/docs/tutorial/deploy/index.html index 5825824e6..4bcd2cfdc 100644 --- a/docs/tutorial/deploy/index.html +++ b/docs/tutorial/deploy/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/gettingStarted/index.html b/docs/tutorial/gettingStarted/index.html index fcf9f49b9..79248e4a7 100644 --- a/docs/tutorial/gettingStarted/index.html +++ b/docs/tutorial/gettingStarted/index.html @@ -13,7 +13,7 @@ - + diff --git a/docs/tutorial/glossary/index.html b/docs/tutorial/glossary/index.html index 07fb3ed0e..a5eee764d 100644 --- a/docs/tutorial/glossary/index.html +++ b/docs/tutorial/glossary/index.html @@ -13,7 +13,7 @@ - + diff --git a/index.html b/index.html index 62ea6b8c4..41e8e9875 100644 --- a/index.html +++ b/index.html @@ -13,7 +13,7 @@ - + diff --git a/markdown-page/index.html b/markdown-page/index.html index 10325da5a..a094d8d01 100644 --- a/markdown-page/index.html +++ b/markdown-page/index.html @@ -13,7 +13,7 @@ - + diff --git a/search/index.html b/search/index.html index 2bf695d72..cce24bed5 100644 --- a/search/index.html +++ b/search/index.html @@ -13,7 +13,7 @@ - +🫨 Please note that we are using
window.adminforth.updateListFilter({field: 'number_of_rooms', operator: 'eq', value: selectedRoomsCount});
to set filter when we are located on apartments list page