Skip to content

Commit 1ef4500

Browse files
authored
Merge pull request #291 from devforth/AdminForth/742
Admin forth/742
2 parents dff60f0 + bb7d058 commit 1ef4500

File tree

9 files changed

+180
-81
lines changed

9 files changed

+180
-81
lines changed

adminforth/documentation/docs/tutorial/03-Customization/15-afcl.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,31 @@ const enable = ref(false)
362362
</div>
363363
</div>
364364

365+
366+
## Toggle
367+
368+
<div class="split-screen" >
369+
<div >
370+
371+
```ts
372+
import Toggle from '@/afcl/Toggle.vue';
373+
```
374+
375+
376+
```html
377+
<Toggle
378+
:disabled="false"
379+
@update:modelValue="toggleSwitchHandler">
380+
<p>Click me</p>
381+
</Toggle>
382+
```
383+
</div>
384+
<div>
385+
![AFCL Checkbox](image-94.png)
386+
</div>
387+
</div>
388+
389+
365390
## Dialog (Pop-up)
366391

367392
<div class="split-screen" >
19.7 KB
Loading

adminforth/modules/styles.ts

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,28 @@ export const styles = () => ({
6969
lightDropdownOptionsHoverBackground: "#f3f4f6", //dropdown menu hover background color
7070
lightDropdownOptionsText: "#000000", //dropdown menu hover background color
7171

72+
lightCheckboxBgUnchecked: "alias:lightPrimaryContrast lighten", //checkbox unchecked state bg
73+
lightCheckboxBgChecked: "alias:lightPrimary", //cheched state bg
74+
lightCheckboxIconColor: "alias:lightPrimaryContrast lighten", //checked icon color
75+
lightCheckboxBorderColor: "alias:lightPrimary darken", //border color
76+
lightFocusRing: "alias:lightPrimary lighten", //focus ring color
77+
lightTextLabel: "black", //text color of checkbox label
78+
79+
lightToggleBgUnactive: "#F9FAFB",
80+
lightToggleBgActive: "alias:lightPrimary darken",
81+
lightToggleCircleUnactive: "alias:lightPrimary",
82+
lightToggleCircleActive: "#F9FAFB",
83+
lightToggleRing: "alias:lightPrimary lighten",
84+
lightToggleText: "black",
85+
lightToggleBorderUnactive: "#E5E7EB",
86+
lightToggleBorderActive: "alias:lightPrimary darken",
87+
7288
// colors for dark theme
7389
darkHtml: "#111827",
7490

7591
darkPrimary: "rgb(130 172 255)", // primary color
7692
darkPrimaryContrast: "alias:darkPrimary inverse", // primary color contrast
77-
darkPrimaryOpacity: "#212A40", // primary color opacity
93+
darkPrimaryOpacity: "alias:darkPrimary opacity:0.2", // primary color opacity
7894

7995
darkNavbar: "#111827",
8096
darkNavbarBorder: "#e5e7eb",
@@ -111,15 +127,30 @@ export const styles = () => ({
111127
darkFormBorder: "#222222",
112128
darkFormHeading: "alias:darkListTableHeading",
113129

114-
darkDropdownButtonsBackground: "#374151",
115-
darkDropownButtonsBorder: "#4b5563",
130+
darkDropdownButtonsBackground: "alias:darkForm darken",
131+
darkDropownButtonsBorder: "alias:darkForm lighten",
116132
darkDropdownButtonsText: "#ffffff",
117133
darkDropdownButtonsPlaceholderText: "#9ca3af",
118134

119-
darkDropdownOptionsBackground: "#374151",
120-
darkDropdownOptionsHoverBackground: "#4b5563",
135+
darkDropdownOptionsBackground: "#alias:darkForm lighten",
136+
darkDropdownOptionsHoverBackground: "alias:darkForm",
121137
darkDropdownOptionsText: "#9ca3af",
122138

139+
darkCheckboxBgUnchecked: "alias:darkPrimaryContrast lighten", //checkbox unchecked state bg
140+
darkCheckboxBgChecked: "alias:darkPrimary", //cheched state bg
141+
darkCheckboxIconColor: "alias:darkPrimaryContrast lighten", //checked icon color
142+
darkCheckboxBorderColor: "alias:darkPrimary darken", //border color
143+
darkFocusRing: "alias:darkPrimary lighten",
144+
darkTextLabel: "white",
145+
146+
darkToggleBgUnactive: "#F9FAFB",
147+
darkToggleBgActive: "alias:darkPrimary darken",
148+
darkToggleCircleUnactive: "alias:darkPrimary",
149+
darkToggleCircleActive: "#F9FAFB",
150+
darkToggleRing: "alias:darkPrimary lighten",
151+
darkToggleText: "alias:darkPrimaryContrast lighten",
152+
darkToggleBorderUnactive: "alias:darkPrimary lighten",
153+
darkToggleBorderActive: "alias:darkPrimary darken",
123154
},
124155
boxShadow: {
125156
customLight: "0 4px 8px rgba(0, 0, 0, 0.1)", // Lighter shadow
@@ -138,5 +169,3 @@ export const styles = () => ({
138169
}
139170
});
140171

141-
142-

adminforth/spa/src/afcl/Checkbox.vue

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
<template>
2-
<div class="afcl-checkbox flex items-center h-5" :class="{'opacity-50' : props.disabled}">
3-
<input :id="id"
4-
ref="rememberInput"
5-
type="checkbox"
6-
:checked="props.modelValue"
7-
:disabled="props.disabled"
8-
@change="$emit('update:modelValue', $event.target.checked)"
9-
class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-lightPrimary cursor-pointer
10-
focus:ring-opacity-50 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 checked:bg-lightPrimary checked:dark:bg-darkPrimary" />
2+
<div class="afcl-checkbox flex items-center relative h-5" :class="{'opacity-50' : props.disabled}">
3+
<div class="flex items-center justify-center">
4+
<input :id="id"
5+
ref="rememberInput"
6+
type="checkbox"
7+
:checked="props.modelValue"
8+
:disabled="props.disabled"
9+
@change="$emit('update:modelValue', $event.target.checked)"
10+
class="peer appearance-none min-w-4 min-h-4 bg-lightCheckboxBgUnchecked border border-lightCheckboxBorderColor rounded-sm checked:bg-lightCheckboxBgChecked
11+
focus:ring-lightFocusRing dark:focus:ring-darkFocusRing dark:focus:ring-darkFocusRing
12+
focus:ring-2 dark:bg-darkCheckboxBgUnchecked dark:border-darkCheckboxBorderColor dark:checked:bg-darkCheckboxBgChecked cursor-pointer"
13+
>
14+
<div class="pointer-events-none absolute text-lightCheckboxIconColor dark:text-darkCheckboxIconColor leading-none peer-checked:block hidden">
15+
<IconCheckOutline width="18" height="18" />
16+
</div>
17+
</div>
18+
<label :for="id" class="ms-2 text-sm font-medium text-lightTextLabel dark:text-darkTextLabel">
19+
<slot></slot>
20+
</label>
21+
1122
</div>
12-
<label :for="id" class="ms-2 text-sm font-medium text-gray-900 dark:text-gray-300">
13-
<slot></slot>
14-
</label>
1523
</template>
1624

1725
<script setup lang="ts">
18-
26+
import { IconCheckOutline } from '@iconify-prerendered/vue-flowbite';
1927
const props = defineProps({
2028
modelValue: Boolean,
2129
disabled: Boolean,

adminforth/spa/src/afcl/Toggle.vue

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<template>
2+
<label class="inline-flex items-center cursor-pointer bor" :class="{'opacity-50' : props.disabled}">
3+
<input :id="id"
4+
type="checkbox"
5+
value="" class="sr-only peer"
6+
:disabled="props.disabled"
7+
:checked="props.modelValue"
8+
@change="$emit('update:modelValue', $event.target.checked)"
9+
>
10+
<div class="border border-lightToggleBorderUnactive relative min-w-11 min-h-6 bg-lightToggleBgUnactive peer-focus:outline-none peer-focus:ring-4
11+
peer-focus:ring-lightToggleRing dark:peer-focus:ring-darkToggleRing rounded-full peer dark:bg-darkToggleBgUnactive
12+
peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:top-[2px] peer-checked:border-none
13+
peer-checked:after:border-lightToggleBorderActive after:content-[''] after:absolute after:top-[1px]
14+
after:start-[2px] after:bg-lightToggleCircleUnactive peer-checked:after:bg-lightToggleCircleActive dark:after:bg-darkToggleCircleUnactive after:border-lightToggleBgUnactive dark:after:border-darkToggleBgUnactive after:border after:rounded-full
15+
after:h-5 after:w-5 after:transition-all dark:border-darkToggleBorderUnactive peer-checked:bg-lightToggleBgActive
16+
dark:peer-checked:bg-darkToggleBgActive dark:peer-checked:after:border-darkToggleBorderActive dark:peer-checked:after:bg-darkToggleCircleActive">
17+
</div>
18+
<label :for="id" class="cursor-pointer ms-3 text-sm font-medium text-lightToggleText dark:text-darkToggleText">
19+
<slot></slot>
20+
</label>
21+
</label>
22+
</template>
23+
24+
<script setup lang="ts">
25+
const props = defineProps({
26+
modelValue: Boolean,
27+
disabled: Boolean,
28+
});
29+
30+
defineEmits(['update:modelValue']);
31+
const id = `afcb-${Math.random().toString(36).substring(7)}`
32+
</script>

adminforth/spa/src/afcl/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ export { default as Dialog } from './Dialog.vue';
2020
export { default as MixedChart } from './MixedChart.vue';
2121
export { default as CountryFlag } from './CountryFlag.vue';
2222
export { default as JsonViewer } from './JsonViewer.vue';
23-
23+
export { default as Toggle } from './Toggle.vue';
2424

adminforth/spa/src/components/ResourceListTable.vue

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,13 @@
1616
<!-- table header -->
1717
<tr class="t-header sticky z-10 top-0 text-xs bg-lightListTableHeading dark:bg-darkListTableHeading dark:text-gray-400">
1818
<td scope="col" class="p-4">
19-
<div class="flex items-center justify-center relative">
20-
<input id="checkbox-all-search" type="checkbox" :checked="allFromThisPageChecked" @change="selectAll()"
21-
:disabled="!rows || !rows.length"
22-
class="peer appearance-none w-4 h-4 text-blue-600 bg-light-primary border border-gray-500 rounded-sm checked:bg-blue-500
23-
focus:ring-blue-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800
24-
focus:ring-2 dark:bg-dark-primary dark:border-gray-600 dark:checked:bg-blue-500 cursor-pointer">
25-
<label for="checkbox-all-search" class="sr-only">{{ $t('checkbox') }}</label>
26-
<div class="pointer-events-none absolute text-white text-[13px] leading-none peer-checked:block hidden">
27-
<IconCheckOutline width="18" height="18" />
28-
</div>
29-
</div>
19+
<Checkbox
20+
:modelValue="allFromThisPageChecked"
21+
:disabled="!rows || !rows.length"
22+
@update:modelValue="selectAll"
23+
>
24+
<span class="sr-only">{{ $t('checkbox') }}</span>
25+
</Checkbox>
3026
</td>
3127

3228
<td v-for="c in columnsListed" ref="headerRefs" scope="col" class="px-2 md:px-3 lg:px-6 py-3">
@@ -95,24 +91,13 @@
9591
:class="{'border-b': rowI !== rows.length - 1, 'cursor-pointer': row._clickUrl !== null}"
9692
>
9793
<td class="w-4 p-4 cursor-default" @click="(e)=>e.stopPropagation()">
98-
<div class="flex items-center justify-center relative">
99-
<input
100-
@click="(e)=>e.stopPropagation()"
101-
id="checkbox-table-search-1"
102-
type="checkbox"
103-
:checked="checkboxesInternal.includes(row._primaryKeyValue)"
104-
@change="(e)=>{addToCheckedValues(row._primaryKeyValue)}"
105-
class="peer appearance-none w-4 h-4 text-blue-600 bg-light-primary border border-gray-500 rounded-sm checked:bg-blue-500
106-
focus:ring-blue-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800
107-
focus:ring-2 dark:bg-dark-primary dark:border-gray-600 dark:checked:bg-blue-500 cursor-pointer"
108-
/>
109-
<label for="checkbox-table-search-1" class="sr-only">
110-
{{ $t('checkbox') }}
111-
</label>
112-
<div class="pointer-events-none absolute text-white text-[13px] leading-none peer-checked:block hidden">
113-
<IconCheckOutline width="18" height="18" />
114-
</div>
115-
</div>
94+
<Checkbox
95+
:model-value="checkboxesInternal.includes(row._primaryKeyValue)"
96+
@change="(e)=>{addToCheckedValues(row._primaryKeyValue)}"
97+
@click="(e)=>e.stopPropagation()"
98+
>
99+
<span class="sr-only">{{ $t('checkbox') }}</span>
100+
</Checkbox>
116101
</td>
117102

118103
<td v-for="c in columnsListed" class="px-2 md:px-3 lg:px-6 py-4">
@@ -320,12 +305,12 @@ import {
320305
IconEyeSolid,
321306
IconPenSolid,
322307
IconTrashBinSolid,
323-
IconCheckOutline
324308
} from '@iconify-prerendered/vue-flowbite';
325309
import router from '@/router';
326310
import { Tooltip } from '@/afcl';
327311
import type { AdminForthResourceCommon } from '@/types/Common';
328312
import adminforth from '@/adminforth';
313+
import Checkbox from '@/afcl/Checkbox.vue';
329314
330315
const coreStore = useCoreStore();
331316
const { t } = useI18n();

adminforth/spa/src/components/ResourceListTableVirtual.vue

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
:style="`height: ${containerHeight}px; will-change: transform;`"
66
@scroll="handleScroll"
77
ref="containerRef"
8-
>
8+
>
99
<!-- skelet loader -->
1010
<div role="status" v-if="!resource || !resource.columns"
1111
class="max-w p-4 space-y-4 divide-y divide-gray-200 rounded shadow animate-pulse dark:divide-gray-700 md:p-6 dark:border-gray-700">
@@ -20,17 +20,13 @@
2020
<!-- table header -->
2121
<tr class="t-header sticky z-10 top-0 text-xs bg-lightListTableHeading dark:bg-darkListTableHeading dark:text-gray-400">
2222
<td scope="col" class="p-4">
23-
<div class="flex items-center justify-center relative">
24-
<input id="checkbox-all-search" type="checkbox" :checked="allFromThisPageChecked" @change="selectAll()"
25-
:disabled="!rows || !rows.length"
26-
class="peer appearance-none w-4 h-4 text-blue-600 bg-light-primary border border-gray-500 rounded-sm checked:bg-blue-500
27-
focus:ring-blue-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800
28-
focus:ring-2 dark:bg-dark-primary dark:border-gray-600 dark:checked:bg-blue-500 cursor-pointer">
29-
<label for="checkbox-all-search" class="sr-only">{{ $t('checkbox') }}</label>
30-
<div class="pointer-events-none absolute text-white text-[13px] leading-none peer-checked:block hidden">
31-
<IconCheckOutline width="18" height="18" />
32-
</div>
33-
</div>
23+
<Checkbox
24+
:modelValue="allFromThisPageChecked"
25+
:disabled="!rows || !rows.length"
26+
@update:modelValue="selectAll"
27+
>
28+
<span class="sr-only">{{ $t('checkbox') }}</span>
29+
</Checkbox>
3430
</td>
3531

3632
<td v-for="c in columnsListed" ref="headerRefs" scope="col" class="px-2 md:px-3 lg:px-6 py-3">
@@ -106,24 +102,13 @@
106102
@mounted="(el) => updateRowHeight(`row_${row._primaryKeyValue}`, el.offsetHeight)"
107103
>
108104
<td class="w-4 p-4 cursor-default" @click="(e)=>e.stopPropagation()">
109-
<div class="flex items-center justify-center relative">
110-
<input
111-
@click="(e)=>e.stopPropagation()"
112-
id="checkbox-table-search-1"
113-
type="checkbox"
114-
:checked="checkboxesInternal.includes(row._primaryKeyValue)"
115-
@change="(e)=>{addToCheckedValues(row._primaryKeyValue)}"
116-
class="peer appearance-none w-4 h-4 text-blue-600 bg-gray-50 border border-gray-500 rounded-sm checked:bg-blue-500
117-
focus:ring-blue-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800
118-
focus:ring-2 dark:bg-gray-700 dark:border-gray-600 dark:checked:bg-blue-500 cursor-pointer"
119-
/>
120-
<label for="checkbox-table-search-1" class="sr-only">
121-
{{ $t('checkbox') }}
122-
</label>
123-
<div class="pointer-events-none absolute text-white text-[13px] leading-none peer-checked:block hidden">
124-
<IconCheckOutline width="18" height="18" />
125-
</div>
126-
</div>
105+
<Checkbox
106+
:model-value="checkboxesInternal.includes(row._primaryKeyValue)"
107+
@change="(e)=>{addToCheckedValues(row._primaryKeyValue)}"
108+
@click="(e)=>e.stopPropagation()"
109+
>
110+
<span class="sr-only">{{ $t('checkbox') }}</span>
111+
</Checkbox>
127112
</td>
128113
<td v-for="c in columnsListed" class="px-2 md:px-3 lg:px-6 py-4">
129114
<!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
@@ -342,6 +327,7 @@ import router from '@/router';
342327
import { Tooltip } from '@/afcl';
343328
import type { AdminForthResourceCommon } from '@/types/Common';
344329
import adminforth from '@/adminforth';
330+
import Checkbox from '@/afcl/Checkbox.vue';
345331
346332
const coreStore = useCoreStore();
347333
const { t } = useI18n();
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<template>
2+
<Toggle
3+
:disabled="readonly"
4+
@update:modelValue="$emit('update:value', $event)"
5+
:modelValue="valueFromRecord"
6+
>
7+
<p>{{text}}</p>
8+
</Toggle>
9+
</template>
10+
11+
<script setup lang="ts">
12+
import Toggle from '@/afcl/Toggle.vue';
13+
import type {
14+
AdminForthResourceColumnCommon,
15+
AdminForthResourceCommon,
16+
AdminUser,
17+
} from "@/types/Common";
18+
19+
const props = defineProps<{
20+
value: boolean,
21+
text: string,
22+
column: AdminForthResourceColumnCommon,
23+
record: any,
24+
meta: any,
25+
resource: AdminForthResourceCommon,
26+
adminUser: AdminUser,
27+
readonly: boolean
28+
}>();
29+
console.log(JSON.stringify(props));
30+
console.log("Current mode:", props.meta?.mode)
31+
defineEmits(['update:value']);
32+
const valueFromRecord = props.record[props.column.name]
33+
const editReadOnly = props.column.editReadonly;
34+
</script>

0 commit comments

Comments
 (0)