Skip to content

Commit 30def17

Browse files
committed
feat: add overInputs injection point to login page
1 parent 5a330c6 commit 30def17

File tree

10 files changed

+95
-27
lines changed

10 files changed

+95
-27
lines changed

adminforth/commands/createCustomComponent/configUpdater.js

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ export async function updateResourceConfig(resourceId, columnName, fieldType, co
254254
}
255255

256256

257-
export async function injectLoginComponent(indexFilePath, componentPath) {
257+
export async function injectLoginComponent(indexFilePath, componentPath, injectionType) {
258258
console.log(chalk.dim(`Reading file: ${indexFilePath}`));
259259
const content = await fs.readFile(indexFilePath, 'utf-8');
260260
const ast = recast.parse(content, {
@@ -263,6 +263,7 @@ export async function injectLoginComponent(indexFilePath, componentPath) {
263263

264264
let updated = false;
265265
let injectionLine = null;
266+
let targetProperty = null;
266267

267268
recast.visit(ast, {
268269
visitNewExpression(path) {
@@ -293,20 +294,23 @@ export async function injectLoginComponent(indexFilePath, componentPath) {
293294
const loginPageInjections = getOrCreateProp(customization, 'loginPageInjections');
294295
if (!n.ObjectExpression.check(loginPageInjections)) return false;
295296

296-
let underInputsProp = loginPageInjections.properties.find(
297-
p => n.ObjectProperty.check(p) && n.Identifier.check(p.key) && p.key.name === 'underInputs'
297+
// Determine target property based on injection type
298+
targetProperty = injectionType === 'beforeLogin' ? 'overInputs' : 'underInputs';
299+
300+
let targetProp = loginPageInjections.properties.find(
301+
p => n.ObjectProperty.check(p) && n.Identifier.check(p.key) && p.key.name === targetProperty
298302
);
299303

300-
if (underInputsProp) {
301-
const currentVal = underInputsProp.value;
302-
injectionLine = underInputsProp.loc?.start.line ?? null;
304+
if (targetProp) {
305+
const currentVal = targetProp.value;
306+
injectionLine = targetProp.loc?.start.line ?? null;
303307
if (n.StringLiteral.check(currentVal)) {
304308
if (currentVal.value !== componentPath) {
305-
underInputsProp.value = b.arrayExpression([
309+
targetProp.value = b.arrayExpression([
306310
b.stringLiteral(currentVal.value),
307311
b.stringLiteral(componentPath),
308312
]);
309-
console.log(chalk.dim(`Converted 'underInputs' to array with existing + new path.`));
313+
console.log(chalk.dim(`Converted '${targetProperty}' to array with existing + new path.`));
310314
} else {
311315
console.log(chalk.dim(`Component path already present as string. Skipping.`));
312316
}
@@ -316,26 +320,26 @@ export async function injectLoginComponent(indexFilePath, componentPath) {
316320
);
317321
if (!exists) {
318322
currentVal.elements.push(b.stringLiteral(componentPath));
319-
console.log(chalk.dim(`Appended new component path to existing 'underInputs' array.`));
323+
console.log(chalk.dim(`Appended new component path to existing '${targetProperty}' array.`));
320324
} else {
321325
console.log(chalk.dim(`Component path already present in array. Skipping.`));
322326
}
323327
} else {
324-
console.warn(chalk.yellow(`⚠️ 'underInputs' is not a string or array. Skipping.`));
328+
console.warn(chalk.yellow(`⚠️ '${targetProperty}' is not a string or array. Skipping.`));
325329
return false;
326330
}
327331
} else {
328332
const newProperty = b.objectProperty(
329-
b.identifier('underInputs'),
330-
b.stringLiteral(componentPath)
331-
);
332-
333-
if (newProperty.loc) {
334-
console.log(chalk.dim(`Adding 'underInputs' at line: ${newProperty.loc.start.line}`));
335-
}
336-
337-
loginPageInjections.properties.push(newProperty);
338-
console.log(chalk.dim(`Added 'underInputs': ${componentPath}`));
333+
b.identifier(targetProperty),
334+
b.stringLiteral(componentPath)
335+
);
336+
337+
if (newProperty.loc) {
338+
console.log(chalk.dim(`Adding '${targetProperty}' at line: ${newProperty.loc.start.line}`));
339+
}
340+
341+
loginPageInjections.properties.push(newProperty);
342+
console.log(chalk.dim(`Added '${targetProperty}': ${componentPath}`));
339343
}
340344

341345
updated = true;
@@ -353,7 +357,7 @@ export async function injectLoginComponent(indexFilePath, componentPath) {
353357
await fs.writeFile(indexFilePath, outputCode, 'utf-8');
354358
console.log(
355359
chalk.green(
356-
`✅ Successfully updated CRUD injection in resource file: ${indexFilePath}` +
360+
`✅ Successfully updated login ${targetProperty} injection in: ${indexFilePath}` +
357361
(injectionLine !== null ? `:${injectionLine}` : '')
358362
)
359363
);

adminforth/commands/createCustomComponent/fileGenerator.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ export async function generateLoginOrGlobalComponentFile(componentFileName, inje
129129
const __filename = fileURLToPath(import.meta.url);
130130
const __dirname = path.dirname(__filename);
131131
let templatePath;
132-
if (injectionType === 'afterLogin') {
132+
if (injectionType === 'afterLogin' || injectionType === 'beforeLogin') {
133133
templatePath = path.join(__dirname, 'templates', 'login', `${injectionType}.vue.hbs`);
134134
} else {
135135
templatePath = path.join(__dirname, 'templates', 'global', `${injectionType}.vue.hbs`);

adminforth/commands/createCustomComponent/main.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ async function handleLoginPageInjectionCreation(config) {
257257
const injectionType = await select({
258258
message: 'Select injection type:',
259259
choices: [
260+
{ name: 'Before Login and password inputs', value: 'beforeLogin' },
260261
{ name: 'After Login and password inputs', value: 'afterLogin' },
261262
{ name: '🔙 BACK', value: '__BACK__' },
262263
],
@@ -287,7 +288,7 @@ async function handleLoginPageInjectionCreation(config) {
287288
console.log(chalk.dim(`Component generation successful: ${absoluteComponentPath}`));
288289
const configFilePath = path.resolve(process.cwd(), 'index.ts');
289290
console.log(chalk.dim(`Injecting component: ${configFilePath}, ${componentFileName}`));
290-
await injectLoginComponent(configFilePath, `@@/${componentFileName}`);
291+
await injectLoginComponent(configFilePath, `@@/${componentFileName}`, injectionType);
291292

292293
console.log(
293294
chalk.bold.greenBright('You can now open the component in your IDE:'),
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<template>
2+
<div class="text-center text-gray-500 text-sm mt-4">
3+
Login Page Text
4+
</div>
5+
</template>
6+
7+
<script setup>
8+
import { onMounted } from 'vue';
9+
10+
const props = defineProps<{
11+
reason: String
12+
}>();
13+
14+
onMounted(() => {
15+
// Logic on mount if needed
16+
});
17+
</script>
18+

adminforth/documentation/docs/tutorial/03-Customization/08-pageInjections.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,9 @@ Here is how it looks:
141141
142142
You can also inject custom components to the login page.
143143
144-
`loginPageInjections.underInputs` allows to add one or more panels under the login form inputs:
144+
`loginPageInjections.underInputs` and `loginPageInjections.overInputs` allows to add one or more panels under or over the login form inputs:
145145
146-
![login Page Injections underInputs](<Group 2 (1).png>)
146+
![login Page Injections underInputs](<loginPageInjection.png>)
147147
148148
For example:
149149
@@ -172,6 +172,38 @@ Now create file `CustomLoginFooter.vue` in the `custom` folder of your project:
172172
</template>
173173
```
174174
175+
Also you can add `overInputs`
176+
177+
```ts title="/index.ts"
178+
179+
new AdminForth({
180+
...
181+
customization: {
182+
loginPageInjections: {
183+
underInputs: '@@/CustomLoginFooter.vue',
184+
//diff-add
185+
overInputs: '@@/CustomLoginHeader.vue',
186+
}
187+
...
188+
}
189+
190+
...
191+
})
192+
```
193+
194+
Now create file `CustomLoginHeader.vue` in the `custom` folder of your project:
195+
196+
```html title="./custom/CustomLoginHeader.vue"
197+
<template>
198+
<div class="flex items-center justify-center gap-2">
199+
<div class="text-2xl text-black dark:text-white font-bold">
200+
AdminForth
201+
</div>
202+
</div>
203+
</template>
204+
```
205+
206+
175207
176208
## List view page injections shrinking: thin enough to shrink?
177209
Loading

adminforth/modules/configValidator.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,11 @@ export default class ConfigValidator implements IConfigValidator {
115115

116116
const loginPageInjections: AdminForthConfigCustomization['loginPageInjections'] = {
117117
underInputs: [],
118+
overInputs: [],
118119
};
119120

120121
if (this.inputConfig.customization?.loginPageInjections) {
121-
const ALLOWED_LOGIN_INJECTIONS = ['underInputs']
122+
const ALLOWED_LOGIN_INJECTIONS = ['underInputs', 'overInputs']
122123
Object.keys(this.inputConfig.customization.loginPageInjections).forEach((injection) => {
123124
if (ALLOWED_LOGIN_INJECTIONS.includes(injection)) {
124125
loginPageInjections[injection] = this.validateAndListifyInjectionNew(this.inputConfig.customization.loginPageInjections, injection, errors);

adminforth/spa/src/views/LoginView.vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,16 @@
3030
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700 dark:shadow-black" >
3131
<!-- Modal header -->
3232
<div class="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
33-
<h3 class="text-xl font-semibold text-gray-900 dark:text-white">
33+
34+
<div v-if="coreStore?.config?.loginPageInjections?.overInputs.length > 0">
35+
<component
36+
v-for="(c, index) in coreStore?.config?.loginPageInjections?.overInputs || []"
37+
:key="index"
38+
:is="getCustomComponent(c)"
39+
:meta="c.meta"
40+
/>
41+
</div>
42+
<h3 v-else class="text-xl font-semibold text-gray-900 dark:text-white">
3443
{{ $t('Sign in to') }} {{ coreStore.config?.brandName }}
3544
</h3>
3645
</div>

adminforth/types/Back.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,7 @@ interface AdminForthInputConfigCustomization {
747747
*/
748748
loginPageInjections?: {
749749
underInputs?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
750+
overInputs?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
750751
}
751752

752753
/**
@@ -1054,6 +1055,7 @@ export interface AdminForthConfigCustomization extends Omit<AdminForthInputConfi
10541055

10551056
loginPageInjections: {
10561057
underInputs: Array<AdminForthComponentDeclarationFull>,
1058+
overInputs: Array<AdminForthComponentDeclarationFull>,
10571059
},
10581060

10591061
globalInjections: {

adminforth/types/Common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,7 @@ export interface AdminForthConfigForFrontend {
10601060
loginPromptHTML?: string,
10611061
loginPageInjections: {
10621062
underInputs: Array<AdminForthComponentDeclaration>,
1063+
overInputs: Array<AdminForthComponentDeclaration>,
10631064
},
10641065
rememberMeDays: number,
10651066
showBrandNameInSidebar: boolean,

0 commit comments

Comments
 (0)