- second commit
This commit is contained in:
parent
4fc3bb0a01
commit
59a99ff3c8
|
@ -8,7 +8,7 @@ README.md
|
|||
# Docker stuff
|
||||
.dockerignore
|
||||
Dockerfile*
|
||||
|
||||
docker-compose.yml
|
||||
|
||||
|
||||
|
||||
|
|
11
.prettierrc
Normal file
11
.prettierrc
Normal file
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 4,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"useTabs": false,
|
||||
"quoteProps": "consistent",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"printWidth": 140
|
||||
}
|
|
@ -45,7 +45,7 @@ FROM base AS production
|
|||
|
||||
# Copy package.* to the working directory with active user
|
||||
COPY --chown=node:node ./package*.json ./
|
||||
# We run NPM CI to install the exact versions of dependencies
|
||||
# We run NPM CI to install the exact versions of production dependencies
|
||||
RUN npm ci --omit=dev
|
||||
# Copy files to the working directory from the build folder the user
|
||||
COPY --chown=node:node --from=build /home/node/app/build .
|
||||
|
|
|
@ -117,7 +117,7 @@ export default class UsersController {
|
|||
const roles = await Role.query().pluck('name', 'id');
|
||||
// const userHasRoles = user.roles;
|
||||
const userHasRoles = await user.related('roles').query().orderBy('name').pluck('id');
|
||||
|
||||
// let test = Object.keys(userHasRoles).map((key) => userHasRoles[key]);
|
||||
return inertia.render('Admin/User/Edit', {
|
||||
roles: roles,
|
||||
user: user,
|
||||
|
|
|
@ -4,20 +4,34 @@ import Person from 'App/Models/Person';
|
|||
|
||||
// node ace make:controller Author
|
||||
export default class AuthorsController {
|
||||
public async index({}: HttpContextContract) {
|
||||
// select * from gba.persons
|
||||
// where exists (select * from gba.documents inner join gba.link_documents_persons on "documents"."id" = "link_documents_persons"."document_id"
|
||||
// where ("link_documents_persons"."role" = 'author') and ("persons"."id" = "link_documents_persons"."person_id"));
|
||||
const authors = await Person.query()
|
||||
.whereHas('datasets', (dQuery) => {
|
||||
dQuery.wherePivot('role', 'author');
|
||||
})
|
||||
.withCount('datasets', (query) => {
|
||||
query.as('datasets_count');
|
||||
});
|
||||
|
||||
public async index({}: HttpContextContract) {
|
||||
// select * from gba.persons
|
||||
// where exists (select * from gba.documents inner join gba.link_documents_persons on "documents"."id" = "link_documents_persons"."document_id"
|
||||
// where ("link_documents_persons"."role" = 'author') and ("persons"."id" = "link_documents_persons"."person_id"));
|
||||
const authors = await Person.query()
|
||||
.whereHas('datasets', (dQuery) => {
|
||||
dQuery.wherePivot('role', 'author')
|
||||
})
|
||||
.withCount('datasets', (query) => {
|
||||
query.as('datasets_count')
|
||||
});
|
||||
|
||||
return authors;
|
||||
}
|
||||
return authors;
|
||||
}
|
||||
|
||||
public async persons({ request }: HttpContextContract) {
|
||||
const authors = Person.query().where('status', true);
|
||||
|
||||
if (request.input('filter')) {
|
||||
// users = users.whereRaw('name like %?%', [request.input('search')])
|
||||
const searchTerm = request.input('filter');
|
||||
authors
|
||||
.where('first_name', 'ilike', `%${searchTerm}%`)
|
||||
.orWhere('last_name', 'like', `%${searchTerm}%`)
|
||||
.orWhere('email', 'like', `%${searchTerm}%`);
|
||||
}
|
||||
|
||||
let persons = await authors;
|
||||
return persons;
|
||||
}
|
||||
}
|
||||
|
|
162
app/Controllers/Http/Submitter/DatasetController.ts
Normal file
162
app/Controllers/Http/Submitter/DatasetController.ts
Normal file
|
@ -0,0 +1,162 @@
|
|||
import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
||||
// import User from 'App/Models/User';
|
||||
// import Role from 'App/Models/Role';
|
||||
// import Database from '@ioc:Adonis/Lucid/Database';
|
||||
import License from 'App/Models/License';
|
||||
// import type { ModelQueryBuilderContract } from '@ioc:Adonis/Lucid/Orm';
|
||||
// import CreateUserValidator from 'App/Validators/CreateUserValidator';
|
||||
// import UpdateUserValidator from 'App/Validators/UpdateUserValidator';
|
||||
// import { RenderResponse } from '@ioc:EidelLev/Inertia';
|
||||
import { schema, CustomMessages, rules } from '@ioc:Adonis/Core/Validator';
|
||||
|
||||
enum TitleTypes {
|
||||
Main = 'Main',
|
||||
Sub = 'Sub',
|
||||
Alternative = 'Alternative',
|
||||
Translated = 'Translated',
|
||||
Other = 'Other',
|
||||
}
|
||||
|
||||
enum DescriptionTypes {
|
||||
Abstract = 'Abstract',
|
||||
Methods = 'Methods',
|
||||
Series_information = 'Series_information',
|
||||
Technical_info = 'Technical_info',
|
||||
Translated = 'Translated',
|
||||
Other = 'Other',
|
||||
}
|
||||
|
||||
export default class DatasetController {
|
||||
public async create({ inertia }: HttpContextContract) {
|
||||
const licenses = await License.query().select('id', 'name_long').pluck('name_long', 'id');
|
||||
|
||||
const doctypes = {
|
||||
analysisdata: { label: 'Analysis', value: 'analysisdata' },
|
||||
measurementdata: { label: 'Measurements', value: 'measurementdata' },
|
||||
monitoring: 'Monitoring',
|
||||
remotesensing: 'Remote Sensing',
|
||||
gis: 'GIS',
|
||||
models: 'Models',
|
||||
mixedtype: 'Mixed Type',
|
||||
};
|
||||
|
||||
// const titletypes = {
|
||||
// Sub: 'Sub',
|
||||
// Alternative: 'Alternative',
|
||||
// Translated: 'Translated',
|
||||
// Other: 'Other',
|
||||
// };
|
||||
|
||||
// const languages = await Database.from('languages').select('*').where('active', true);
|
||||
return inertia.render('Submitter/Dataset/Create', {
|
||||
licenses: licenses,
|
||||
doctypes: doctypes,
|
||||
titletypes: Object.values(TitleTypes).filter((x) => x.valueOf() !== 'Main'),
|
||||
descriptiontypes: Object.values(DescriptionTypes).filter((x) => x.valueOf() !== 'Abstract'),
|
||||
// descriptiontypes: DescriptionTypes
|
||||
});
|
||||
}
|
||||
|
||||
public async firstStep({ request, response }: HttpContextContract) {
|
||||
const newDatasetSchema = schema.create({
|
||||
language: schema.string({ trim: true }, [
|
||||
rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
||||
]),
|
||||
licenses: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one license for the new dataset
|
||||
rights: schema.string([rules.equalTo('true')]),
|
||||
});
|
||||
|
||||
try {
|
||||
// Step 2 - Validate request body against the schema
|
||||
|
||||
await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
||||
// console.log({ payload });
|
||||
} catch (error) {
|
||||
// Step 3 - Handle errors
|
||||
// return response.badRequest(error.messages);
|
||||
throw error;
|
||||
}
|
||||
return response.redirect().back();
|
||||
}
|
||||
|
||||
public async secondStep({ request, response }: HttpContextContract) {
|
||||
const newDatasetSchema = schema.create({
|
||||
language: schema.string({ trim: true }, [
|
||||
rules.regex(/^[a-zA-Z0-9-_]+$/), //Must be alphanumeric with hyphens or underscores
|
||||
]),
|
||||
licenses: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one license for the new dataset
|
||||
type: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
||||
creating_corporation: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
||||
titles: schema.array([rules.minLength(1)]).members(
|
||||
schema.object().members({
|
||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
||||
type: schema.enum(Object.values(TitleTypes)),
|
||||
language: schema.string({ trim: true }, [rules.minLength(2), rules.maxLength(255)]),
|
||||
}),
|
||||
),
|
||||
descriptions: schema.array([rules.minLength(1)]).members(
|
||||
schema.object().members({
|
||||
value: schema.string({ trim: true }, [rules.minLength(3), rules.maxLength(255)]),
|
||||
type: schema.enum(Object.values(DescriptionTypes)),
|
||||
language: schema.string({ trim: true }, [rules.minLength(2), rules.maxLength(255)]),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
try {
|
||||
// Step 2 - Validate request body against the schema
|
||||
await request.validate({ schema: newDatasetSchema, messages: this.messages });
|
||||
// console.log({ payload });
|
||||
} catch (error) {
|
||||
// Step 3 - Handle errors
|
||||
// return response.badRequest(error.messages);
|
||||
throw error;
|
||||
}
|
||||
return response.redirect().back();
|
||||
}
|
||||
|
||||
// public async store({ request, response, session }: HttpContextContract) {
|
||||
// // node ace make:validator CreateUser
|
||||
// try {
|
||||
// // Step 2 - Validate request body against the schema
|
||||
// await request.validate(CreateUserValidator);
|
||||
// // console.log({ payload });
|
||||
// } catch (error) {
|
||||
// // Step 3 - Handle errors
|
||||
// // return response.badRequest(error.messages);
|
||||
// throw error;
|
||||
// }
|
||||
// const input = request.only(['login', 'email', 'password']);
|
||||
// const user = await User.create(input);
|
||||
// if (request.input('roles')) {
|
||||
// const roles: Array<number> = request.input('roles');
|
||||
// await user.related('roles').attach(roles);
|
||||
// }
|
||||
|
||||
// session.flash('message', 'User has been created successfully');
|
||||
// return response.redirect().toRoute('user.index');
|
||||
// }
|
||||
|
||||
public messages: CustomMessages = {
|
||||
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
||||
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
||||
'required': '{{ field }} is required',
|
||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
||||
// 'confirmed': '{{ field }} is not correct',
|
||||
'licences.minLength': 'at least {{ options.minLength }} permission must be defined',
|
||||
'licences.*.number': 'Define roles as valid numbers',
|
||||
'rights.equalTo': 'you must agree to continue',
|
||||
|
||||
'titles.0.value.minLength': 'Main Title must be at least {{ options.minLength }} characters long',
|
||||
'titles.0.value.required': 'Main Title is required',
|
||||
'titles.*.value.required': 'Additional title is required, if defined',
|
||||
'titles.*.type.required': 'Additional title type is required',
|
||||
'titles.*.language.required': 'Additional title language is required',
|
||||
|
||||
'descriptions.0.value.minLength': 'Main Abstract must be at least {{ options.minLength }} characters long',
|
||||
'descriptions.0.value.required': 'Main Abstract is required',
|
||||
'descriptions.*.value.required': 'Additional description is required, if defined',
|
||||
'descriptions.*.type.required': 'Additional description type is required',
|
||||
'descriptions.*.language.required': 'Additional description language is required',
|
||||
};
|
||||
}
|
37
app/Models/License.ts
Normal file
37
app/Models/License.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import { column, BaseModel, SnakeCaseNamingStrategy } from '@ioc:Adonis/Lucid/Orm';
|
||||
|
||||
export default class License extends BaseModel {
|
||||
public static namingStrategy = new SnakeCaseNamingStrategy();
|
||||
public static primaryKey = 'id';
|
||||
public static table = 'document_licences';
|
||||
public static selfAssignPrimaryKey = false;
|
||||
|
||||
@column({
|
||||
isPrimary: true,
|
||||
})
|
||||
public id: number;
|
||||
|
||||
@column({})
|
||||
public active: boolean;
|
||||
|
||||
@column({})
|
||||
public langauge: string;
|
||||
|
||||
@column({})
|
||||
public link_licence: string;
|
||||
|
||||
@column({})
|
||||
public link_logo: string;
|
||||
|
||||
@column({})
|
||||
public display_name: string;
|
||||
|
||||
@column({})
|
||||
public name_long: string;
|
||||
|
||||
@column({})
|
||||
public name: string;
|
||||
|
||||
@column({})
|
||||
public sortOrder: number;
|
||||
}
|
|
@ -54,7 +54,7 @@ export default class Person extends BaseModel {
|
|||
serializeAs: 'name'
|
||||
})
|
||||
public get fullName() {
|
||||
return this.firstName + ' ' + this.lastName;
|
||||
return `${this.firstName} ${this.lastName} (${this.email})`;
|
||||
}
|
||||
|
||||
@computed()
|
||||
|
|
|
@ -3,101 +3,101 @@ import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
|
|||
// import { Request } from '@adonisjs/core/build/standalone';
|
||||
|
||||
export default class UpdateUserValidator {
|
||||
protected ctx: HttpContextContract;
|
||||
public schema;
|
||||
protected ctx: HttpContextContract;
|
||||
public schema;
|
||||
|
||||
constructor(ctx: HttpContextContract) {
|
||||
this.ctx = ctx;
|
||||
this.schema = this.createSchema();
|
||||
}
|
||||
constructor(ctx: HttpContextContract) {
|
||||
this.ctx = ctx;
|
||||
this.schema = this.createSchema();
|
||||
}
|
||||
|
||||
// public get schema() {
|
||||
// return this._schema;
|
||||
// }
|
||||
// public get schema() {
|
||||
// return this._schema;
|
||||
// }
|
||||
|
||||
private createSchema() {
|
||||
return schema.create({
|
||||
login: schema.string({ trim: true }, [
|
||||
rules.minLength(3),
|
||||
rules.maxLength(50),
|
||||
rules.unique({
|
||||
table: 'accounts',
|
||||
column: 'login',
|
||||
// whereNot: { id: this.refs.id }
|
||||
whereNot: { id: this.ctx?.params.id },
|
||||
}),
|
||||
// rules.regex(/^[a-zA-Z0-9-_]+$/),
|
||||
//Must be alphanumeric with hyphens or underscores
|
||||
]),
|
||||
email: schema.string({}, [
|
||||
rules.email(),
|
||||
rules.unique({ table: 'accounts', column: 'email', whereNot: { id: this.ctx?.params.id } }),
|
||||
]),
|
||||
password: schema.string.optional([rules.confirmed(), rules.minLength(6)]),
|
||||
roles: schema.array.optional([rules.minLength(1)]).members(schema.number()), // define at least one role for the new user
|
||||
});
|
||||
}
|
||||
private createSchema() {
|
||||
return schema.create({
|
||||
login: schema.string({ trim: true }, [
|
||||
rules.minLength(3),
|
||||
rules.maxLength(50),
|
||||
rules.unique({
|
||||
table: 'accounts',
|
||||
column: 'login',
|
||||
// whereNot: { id: this.refs.id }
|
||||
whereNot: { id: this.ctx?.params.id },
|
||||
}),
|
||||
// rules.regex(/^[a-zA-Z0-9-_]+$/),
|
||||
//Must be alphanumeric with hyphens or underscores
|
||||
]),
|
||||
email: schema.string({}, [
|
||||
rules.email(),
|
||||
rules.unique({ table: 'accounts', column: 'email', whereNot: { id: this.ctx?.params.id } }),
|
||||
]),
|
||||
password: schema.string.optional([rules.confirmed(), rules.minLength(6)]),
|
||||
roles: schema.array.optional([rules.minLength(1)]).members(schema.number()), // define at least one role for the new user
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
||||
*
|
||||
* For example:
|
||||
* 1. The username must be of data type string. But then also, it should
|
||||
* not contain special characters or numbers.
|
||||
* ```
|
||||
* schema.string({}, [ rules.alpha() ])
|
||||
* ```
|
||||
*
|
||||
* 2. The email must be of data type string, formatted as a valid
|
||||
* email. But also, not used by any other user.
|
||||
* ```
|
||||
* schema.string({}, [
|
||||
* rules.email(),
|
||||
* rules.unique({ table: 'users', column: 'email' }),
|
||||
* ])
|
||||
* ```
|
||||
*/
|
||||
/*
|
||||
* Define schema to validate the "shape", "type", "formatting" and "integrity" of data.
|
||||
*
|
||||
* For example:
|
||||
* 1. The username must be of data type string. But then also, it should
|
||||
* not contain special characters or numbers.
|
||||
* ```
|
||||
* schema.string({}, [ rules.alpha() ])
|
||||
* ```
|
||||
*
|
||||
* 2. The email must be of data type string, formatted as a valid
|
||||
* email. But also, not used by any other user.
|
||||
* ```
|
||||
* schema.string({}, [
|
||||
* rules.email(),
|
||||
* rules.unique({ table: 'users', column: 'email' }),
|
||||
* ])
|
||||
* ```
|
||||
*/
|
||||
|
||||
// public refs = schema.refs({
|
||||
// id: this.ctx.params.id
|
||||
// })
|
||||
// public refs = schema.refs({
|
||||
// id: this.ctx.params.id
|
||||
// })
|
||||
|
||||
// public schema = schema.create({
|
||||
// login: schema.string({ trim: true }, [
|
||||
// rules.minLength(3),
|
||||
// rules.maxLength(50),
|
||||
// rules.unique({
|
||||
// table: 'accounts',
|
||||
// column: 'login',
|
||||
// // whereNot: { id: this.refs.id }
|
||||
// whereNot: { id: this.ctx?.params.id },
|
||||
// }),
|
||||
// // rules.regex(/^[a-zA-Z0-9-_]+$/),
|
||||
// //Must be alphanumeric with hyphens or underscores
|
||||
// ]),
|
||||
// email: schema.string({}, [rules.email(), rules.unique({ table: 'accounts', column: 'email' })]),
|
||||
// password: schema.string.optional([rules.confirmed(), rules.minLength(6)]),
|
||||
// roles: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one role for the new user
|
||||
// });
|
||||
// public schema = schema.create({
|
||||
// login: schema.string({ trim: true }, [
|
||||
// rules.minLength(3),
|
||||
// rules.maxLength(50),
|
||||
// rules.unique({
|
||||
// table: 'accounts',
|
||||
// column: 'login',
|
||||
// // whereNot: { id: this.refs.id }
|
||||
// whereNot: { id: this.ctx?.params.id },
|
||||
// }),
|
||||
// // rules.regex(/^[a-zA-Z0-9-_]+$/),
|
||||
// //Must be alphanumeric with hyphens or underscores
|
||||
// ]),
|
||||
// email: schema.string({}, [rules.email(), rules.unique({ table: 'accounts', column: 'email' })]),
|
||||
// password: schema.string.optional([rules.confirmed(), rules.minLength(6)]),
|
||||
// roles: schema.array([rules.minLength(1)]).members(schema.number()), // define at least one role for the new user
|
||||
// });
|
||||
|
||||
/**
|
||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
||||
* children of an array. For example:
|
||||
*
|
||||
* {
|
||||
* 'profile.username.required': 'Username is required',
|
||||
* 'scores.*.number': 'Define scores as valid numbers'
|
||||
* }
|
||||
*
|
||||
*/
|
||||
public messages: CustomMessages = {
|
||||
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
||||
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
||||
'required': '{{ field }} is required',
|
||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
||||
'confirmed': '{{ field }} is not correct',
|
||||
'roles.minLength': 'at least {{ options.minLength }} role must be defined',
|
||||
'roles.*.number': 'Define roles as valid numbers',
|
||||
};
|
||||
/**
|
||||
* Custom messages for validation failures. You can make use of dot notation `(.)`
|
||||
* for targeting nested fields and array expressions `(*)` for targeting all
|
||||
* children of an array. For example:
|
||||
*
|
||||
* {
|
||||
* 'profile.username.required': 'Username is required',
|
||||
* 'scores.*.number': 'Define scores as valid numbers'
|
||||
* }
|
||||
*
|
||||
*/
|
||||
public messages: CustomMessages = {
|
||||
'minLength': '{{ field }} must be at least {{ options.minLength }} characters long',
|
||||
'maxLength': '{{ field }} must be less then {{ options.maxLength }} characters long',
|
||||
'required': '{{ field }} is required',
|
||||
'unique': '{{ field }} must be unique, and this value is already taken',
|
||||
'confirmed': '{{ field }} is not correct',
|
||||
'roles.minLength': 'at least {{ options.minLength }} role must be defined',
|
||||
'roles.*.number': 'Define roles as valid numbers',
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { BaseCommand } from '@adonisjs/core/build/standalone';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
// import Config from '@ioc:Adonis/Core/Config';
|
||||
import Logger from '@ioc:Adonis/Core/Logger'
|
||||
|
||||
export default class ValidateChecksum extends BaseCommand {
|
||||
/**
|
||||
|
@ -37,6 +39,9 @@ export default class ValidateChecksum extends BaseCommand {
|
|||
// query all files from database:
|
||||
const files = await File.query().preload('hashvalues');
|
||||
|
||||
// const logLevel = Config.get('app.logger.level', 'info');
|
||||
// console.log(this.logger.)
|
||||
|
||||
for (var file of files) {
|
||||
let hashValue = await file.related('hashvalues').query().pluck('value', 'type');
|
||||
|
||||
|
@ -45,16 +50,17 @@ export default class ValidateChecksum extends BaseCommand {
|
|||
try {
|
||||
calculatedMd5FileHash = await this.checksumFile(filePath, 'md5');
|
||||
} catch (exception) {
|
||||
this.logger.error(exception.message);
|
||||
// this.logger.error(exception.message);
|
||||
Logger.error(exception.message);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hashValue['md5'] == calculatedMd5FileHash) {
|
||||
this.logger.info(
|
||||
Logger.info(
|
||||
`File id ${file.id}: stored md5 checksum: ${calculatedMd5FileHash}, control md5 checksum: ${hashValue['md5']}`,
|
||||
);
|
||||
} else {
|
||||
this.logger.logError(
|
||||
Logger.error(
|
||||
`File id ${file.id}: stored md5 checksum: ${calculatedMd5FileHash}, control md5 checksum: ${hashValue['md5']}`,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -154,6 +154,10 @@ export const logger: LoggerConfig = {
|
|||
|
|
||||
*/
|
||||
level: Env.get('LOG_LEVEL', 'info'),
|
||||
redact: {
|
||||
paths: ['password', '*.password'],
|
||||
},
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
import BaseSchema from '@ioc:Adonis/Lucid/Schema'
|
||||
import Config from '@ioc:Adonis/Core/Config'
|
||||
import BaseSchema from '@ioc:Adonis/Lucid/Schema';
|
||||
import Config from '@ioc:Adonis/Core/Config';
|
||||
|
||||
export default class Roles extends BaseSchema {
|
||||
protected tableName = Config.get('rolePermission.role_table', 'roles')
|
||||
protected tableName = Config.get('rolePermission.role_table', 'roles');
|
||||
|
||||
public async up () {
|
||||
this.schema.createTable(this.tableName, (table) => {
|
||||
table.increments('id')
|
||||
table.string('name', 191).unique()
|
||||
table.string('slug', 191).nullable().unique()
|
||||
table.string('description', 191).nullable()
|
||||
public async up() {
|
||||
this.schema.createTable(this.tableName, (table) => {
|
||||
table.increments('id');
|
||||
table.string('name', 191).unique();
|
||||
table.string('slug', 191).nullable().unique();
|
||||
table.string('description', 191).nullable();
|
||||
|
||||
/**
|
||||
* Uses timestamptz for PostgreSQL and DATETIME2 for MSSQL
|
||||
*/
|
||||
table.timestamp('created_at', { useTz: true }).nullable()
|
||||
table.timestamp('updated_at', { useTz: true }).nullable()
|
||||
})
|
||||
}
|
||||
/**
|
||||
* Uses timestamptz for PostgreSQL and DATETIME2 for MSSQL
|
||||
*/
|
||||
table.timestamp('created_at', { useTz: true }).nullable();
|
||||
table.timestamp('updated_at', { useTz: true }).nullable();
|
||||
});
|
||||
}
|
||||
|
||||
public async down () {
|
||||
this.schema.dropTable(this.tableName)
|
||||
}
|
||||
public async down() {
|
||||
this.schema.dropTable(this.tableName);
|
||||
}
|
||||
}
|
||||
|
|
32
env.ts
32
env.ts
|
@ -12,21 +12,21 @@
|
|||
|
|
||||
*/
|
||||
|
||||
import Env from '@ioc:Adonis/Core/Env'
|
||||
import Env from '@ioc:Adonis/Core/Env';
|
||||
|
||||
export default Env.rules({
|
||||
HOST: Env.schema.string({ format: 'host' }),
|
||||
PORT: Env.schema.number(),
|
||||
APP_KEY: Env.schema.string(),
|
||||
APP_NAME: Env.schema.string(),
|
||||
CACHE_VIEWS: Env.schema.boolean(),
|
||||
SESSION_DRIVER: Env.schema.string(),
|
||||
DRIVE_DISK: Env.schema.enum(['local'] as const),
|
||||
NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const),
|
||||
DB_CONNECTION: Env.schema.string(),
|
||||
PG_HOST: Env.schema.string({ format: 'host' }),
|
||||
PG_PORT: Env.schema.number(),
|
||||
PG_USER: Env.schema.string(),
|
||||
PG_PASSWORD: Env.schema.string.optional(),
|
||||
PG_DB_NAME: Env.schema.string(),
|
||||
})
|
||||
HOST: Env.schema.string({ format: 'host' }),
|
||||
PORT: Env.schema.number(),
|
||||
APP_KEY: Env.schema.string(),
|
||||
APP_NAME: Env.schema.string(),
|
||||
CACHE_VIEWS: Env.schema.boolean(),
|
||||
SESSION_DRIVER: Env.schema.string(),
|
||||
DRIVE_DISK: Env.schema.enum(['local'] as const),
|
||||
NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const),
|
||||
DB_CONNECTION: Env.schema.string(),
|
||||
PG_HOST: Env.schema.string({ format: 'host' }),
|
||||
PG_PORT: Env.schema.number(),
|
||||
PG_USER: Env.schema.string(),
|
||||
PG_PASSWORD: Env.schema.string.optional(),
|
||||
PG_DB_NAME: Env.schema.string(),
|
||||
});
|
||||
|
|
625
package-lock.json
generated
625
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
17
package.json
17
package.json
|
@ -28,17 +28,6 @@
|
|||
"eslintIgnore": [
|
||||
"build"
|
||||
],
|
||||
"prettier": {
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 4,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"useTabs": false,
|
||||
"quoteProps": "consistent",
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "always",
|
||||
"printWidth": 120
|
||||
},
|
||||
"alias": {
|
||||
"vue": "./node_modules/vue/dist/vue.esm-bundler.js"
|
||||
},
|
||||
|
@ -71,7 +60,7 @@
|
|||
"naive-ui": "^2.34.3",
|
||||
"numeral": "^2.0.6",
|
||||
"pinia": "^2.0.30",
|
||||
"pino-pretty": "^9.1.1",
|
||||
"pino-pretty": "^10.0.0",
|
||||
"postcss-loader": "^7.0.2",
|
||||
"prettier": "^2.8.3",
|
||||
"tailwindcss": "^3.2.4",
|
||||
|
@ -91,7 +80,9 @@
|
|||
"@adonisjs/shield": "^7.1.0",
|
||||
"@adonisjs/view": "^6.1.5",
|
||||
"@eidellev/adonis-stardust": "^3.0.0",
|
||||
"@eidellev/inertia-adonisjs": "^7.4.0",
|
||||
"@eidellev/inertia-adonisjs": "^8.0.0",
|
||||
"@fontsource/archivo-black": "^4.5.9",
|
||||
"@fontsource/inter": "^4.5.15",
|
||||
"@inertiajs/inertia": "^0.11.1",
|
||||
"@inertiajs/vue3": "^1.0.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
{
|
||||
"assets/app.css": "http://localhost:8080/assets/app.css",
|
||||
"assets/app.js": "http://localhost:8080/assets/app.js"
|
||||
"assets/app.js": "http://localhost:8080/assets/app.js",
|
||||
"assets/fonts/inter-all-400-normal.woff": "http://localhost:8080/assets/fonts/inter-all-400-normal.8c804432.woff",
|
||||
"assets/fonts/archivo-black-all-400-normal.woff": "http://localhost:8080/assets/fonts/archivo-black-all-400-normal.da68e413.woff",
|
||||
"assets/fonts/inter-latin-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-latin-ext-400-normal.3a7a7652.woff2",
|
||||
"assets/fonts/archivo-black-latin-400-normal.woff2": "http://localhost:8080/assets/fonts/archivo-black-latin-400-normal.fc847a1f.woff2",
|
||||
"assets/fonts/inter-latin-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-latin-400-normal.be7cb18d.woff2",
|
||||
"assets/fonts/archivo-black-latin-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/archivo-black-latin-ext-400-normal.21761451.woff2",
|
||||
"assets/fonts/inter-cyrillic-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-cyrillic-ext-400-normal.fcc125c4.woff2",
|
||||
"assets/fonts/inter-greek-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-greek-400-normal.0278a49f.woff2",
|
||||
"assets/fonts/inter-cyrillic-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-cyrillic-400-normal.8684fef6.woff2",
|
||||
"assets/fonts/inter-greek-ext-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-greek-ext-400-normal.3f642a92.woff2",
|
||||
"assets/fonts/inter-vietnamese-400-normal.woff2": "http://localhost:8080/assets/fonts/inter-vietnamese-400-normal.789afb71.woff2"
|
||||
}
|
|
@ -1,30 +1,44 @@
|
|||
/* @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500&display=swap'); */
|
||||
@import url('https://fonts.googleapis.com/css?family=Roboto:400,400i,600,700');
|
||||
/* @import url('https://fonts.googleapis.com/css?family=Roboto:400,400i,600,700'); */
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@import "_checkbox-radio-switch.css";
|
||||
@import "_progress.css";
|
||||
@import "_scrollbars.css";
|
||||
@import "_table.css";
|
||||
@import '_checkbox-radio-switch.css';
|
||||
@import '_progress.css';
|
||||
@import '_scrollbars.css';
|
||||
@import '_table.css';
|
||||
|
||||
@import '@fontsource/inter/index.css';
|
||||
@import '@fontsource/archivo-black/index.css';
|
||||
|
||||
html, body {
|
||||
background-color: #F7F8FA;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
/* height: 100vh; */
|
||||
color: #46444c;
|
||||
position: relative;
|
||||
}
|
||||
/* @layer base {
|
||||
html,
|
||||
body {
|
||||
background-color: #f7f8fa;
|
||||
font-family: Inter, system-ui, sans-serif;
|
||||
height: 100vh;
|
||||
color: #46444c;
|
||||
position: relative;
|
||||
}
|
||||
} */
|
||||
|
||||
/* html,
|
||||
body {
|
||||
background-color: #f7f8fa;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
height: 100vh;
|
||||
color: #46444c;
|
||||
position: relative;
|
||||
} */
|
||||
.px-6 {
|
||||
padding-left: 0;
|
||||
/* padding-right: 1.5rem; */
|
||||
padding-left: 0;
|
||||
/* padding-right: 1.5rem; */
|
||||
}
|
||||
|
||||
.rounded-md {
|
||||
color: gray;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
/* body:before {
|
||||
|
@ -90,6 +104,6 @@ main li:before {
|
|||
} */
|
||||
|
||||
main code {
|
||||
font-size: 16px;
|
||||
background: #e6e2ff;
|
||||
font-size: 16px;
|
||||
background: #e6e2ff;
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// import { reactive, computed } from 'vue';
|
||||
// import { usePage } from '@inertiajs/vue3'
|
||||
// import { usePage } from '@inertiajs/inertia-vue3';
|
||||
import { LayoutService } from '@/Stores/layout.js';
|
||||
import menu from '@/menu.js'
|
||||
import { LayoutService } from '@/Stores/layout';
|
||||
import menu from '@/menu'
|
||||
import AsideMenuLayer from '@/Components/AsideMenuLayer.vue';
|
||||
import OverlayLayer from '@/Components/OverlayLayer.vue';
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { ref, computed } from 'vue';
|
|||
import { Link } from '@inertiajs/vue3';
|
||||
// import { Link } from '@inertiajs/inertia-vue3';
|
||||
|
||||
import { StyleService } from '@/Stores/style.js';
|
||||
import { StyleService } from '@/Stores/style';
|
||||
import { mdiMinus, mdiPlus } from '@mdi/js';
|
||||
import { getButtonColor } from '@/colors.js';
|
||||
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||
|
|
|
@ -4,8 +4,8 @@ import { router } from '@inertiajs/vue3'
|
|||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
import { mdiLogout, mdiClose } from '@mdi/js';
|
||||
import { computed } from 'vue';
|
||||
import { LayoutService } from '@/Stores/layout.js';
|
||||
import { StyleService } from '@/Stores/style.js';
|
||||
import { LayoutService } from '@/Stores/layout';
|
||||
import { StyleService } from '@/Stores/style';
|
||||
import AsideMenuList from '@/Components/AsideMenuList.vue';
|
||||
import AsideMenuItem from '@/Components/AsideMenuItem.vue';
|
||||
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||
|
|
|
@ -2,28 +2,28 @@
|
|||
import AsideMenuItem from '@/Components/AsideMenuItem.vue';
|
||||
|
||||
defineProps({
|
||||
isDropdownList: Boolean,
|
||||
menu: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
})
|
||||
isDropdownList: Boolean,
|
||||
menu: {
|
||||
type: Object,
|
||||
default: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['menu-click'])
|
||||
const emit = defineEmits(['menu-click']);
|
||||
|
||||
const menuClick = (event, item) => {
|
||||
emit('menu-click', event, item)
|
||||
}
|
||||
emit('menu-click', event, item);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul>
|
||||
<AsideMenuItem
|
||||
v-for="(item, index) in menu"
|
||||
:key="index"
|
||||
v-bind:item="item"
|
||||
:is-dropdown-list="isDropdownList"
|
||||
@menu-click="menuClick"
|
||||
/>
|
||||
</ul>
|
||||
<ul>
|
||||
<AsideMenuItem
|
||||
v-for="(item, index) in menu"
|
||||
:key="index"
|
||||
v-bind:item="item"
|
||||
:is-dropdown-list="isDropdownList"
|
||||
@menu-click="menuClick"
|
||||
/>
|
||||
</ul>
|
||||
</template>
|
||||
|
|
|
@ -1,111 +1,81 @@
|
|||
<script setup>
|
||||
import { mdiCog } from '@mdi/js'
|
||||
import { computed, useSlots } from 'vue'
|
||||
import BaseIcon from '@/Components/BaseIcon.vue'
|
||||
import { mdiCog } from '@mdi/js';
|
||||
import { computed, useSlots } from 'vue';
|
||||
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
headerIcon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
rounded: {
|
||||
type: String,
|
||||
default: 'rounded-xl'
|
||||
},
|
||||
hasTable: Boolean,
|
||||
empty: Boolean,
|
||||
form: Boolean,
|
||||
hoverable: Boolean,
|
||||
modal: Boolean
|
||||
})
|
||||
title: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
headerIcon: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
rounded: {
|
||||
type: String,
|
||||
default: 'rounded-xl',
|
||||
},
|
||||
hasFormData: Boolean,
|
||||
empty: Boolean,
|
||||
form: Boolean,
|
||||
hoverable: Boolean,
|
||||
modal: Boolean,
|
||||
});
|
||||
|
||||
const emit = defineEmits(['header-icon-click', 'submit'])
|
||||
const emit = defineEmits(['header-icon-click', 'submit']);
|
||||
|
||||
const is = computed(() => props.form ? 'form' : 'div')
|
||||
const is = computed(() => (props.form ? 'form' : 'div'));
|
||||
|
||||
const slots = useSlots()
|
||||
const slots = useSlots();
|
||||
|
||||
const footer = computed(() => slots.footer && !!slots.footer())
|
||||
const footer = computed(() => slots.footer && !!slots.footer());
|
||||
|
||||
const componentClass = computed(() => {
|
||||
const base = [
|
||||
props.rounded,
|
||||
props.modal ? 'dark:bg-slate-900' : 'dark:bg-slate-900/70'
|
||||
]
|
||||
const base = [props.rounded, props.modal ? 'dark:bg-slate-900' : 'dark:bg-slate-900/70'];
|
||||
|
||||
if (props.hoverable) {
|
||||
base.push('hover:shadow-lg transition-shadow duration-500')
|
||||
}
|
||||
if (props.hoverable) {
|
||||
base.push('hover:shadow-lg transition-shadow duration-500');
|
||||
}
|
||||
|
||||
return base
|
||||
})
|
||||
return base;
|
||||
});
|
||||
|
||||
const computedHeaderIcon = computed(() => props.headerIcon ?? mdiCog)
|
||||
const computedHeaderIcon = computed(() => props.headerIcon ?? mdiCog);
|
||||
|
||||
const headerIconClick = () => {
|
||||
emit('header-icon-click')
|
||||
}
|
||||
emit('header-icon-click');
|
||||
};
|
||||
|
||||
const submit = e => {
|
||||
emit('submit', e)
|
||||
}
|
||||
const submit = (e) => {
|
||||
emit('submit', e);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component
|
||||
:is="is"
|
||||
:class="componentClass"
|
||||
class="bg-white flex flex-col"
|
||||
@submit="submit"
|
||||
>
|
||||
<header
|
||||
v-if="title"
|
||||
class="flex items-stretch border-b border-gray-100 dark:border-slate-800"
|
||||
>
|
||||
<div
|
||||
class="flex items-center py-3 grow font-bold"
|
||||
:class="[ icon ? 'px-4' : 'px-6' ]"
|
||||
>
|
||||
<BaseIcon
|
||||
v-if="icon"
|
||||
:path="icon"
|
||||
class="mr-3"
|
||||
/>
|
||||
{{ title }}
|
||||
</div>
|
||||
<button
|
||||
class="flex items-center py-3 px-4 justify-center ring-blue-700 focus:ring"
|
||||
@click="headerIconClick"
|
||||
>
|
||||
<BaseIcon :path="computedHeaderIcon" />
|
||||
</button>
|
||||
</header>
|
||||
<div
|
||||
v-if="empty"
|
||||
class="text-center py-24 text-gray-500 dark:text-slate-400"
|
||||
>
|
||||
<p>Nothing's here…</p>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="flex-1"
|
||||
:class="{'p-6':!hasTable}"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
<div
|
||||
v-if="footer"
|
||||
class="p-6 border-t border-gray-100 dark:border-slate-800"
|
||||
>
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</component>
|
||||
<component :is="is" :class="componentClass" class="bg-white flex flex-col" @submit="submit">
|
||||
<header v-if="title" class="flex items-stretch border-b border-gray-100 dark:border-slate-800">
|
||||
<div class="flex items-center py-3 grow font-bold" :class="[icon ? 'px-4' : 'px-6']">
|
||||
<BaseIcon v-if="icon" :path="icon" class="mr-3" />
|
||||
{{ title }}
|
||||
</div>
|
||||
<button class="flex items-center py-3 px-4 justify-center ring-blue-700 focus:ring" @click="headerIconClick">
|
||||
<BaseIcon :path="computedHeaderIcon" />
|
||||
</button>
|
||||
</header>
|
||||
<div v-if="empty" class="text-center py-24 text-gray-500 dark:text-slate-400">
|
||||
<p>Nothing's here…</p>
|
||||
</div>
|
||||
<!-- <div v-else class="flex-1" :class="{'p-6':!hasTable}"> -->
|
||||
<div v-else class="flex-1" :class="[!hasFormData && 'p-6']">
|
||||
<slot />
|
||||
</div>
|
||||
<div v-if="footer" class="p-6 border-t border-gray-100 dark:border-slate-800">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</component>
|
||||
</template>
|
||||
|
|
|
@ -1,56 +1,62 @@
|
|||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { mdiClose } from '@mdi/js'
|
||||
import BaseButton from '@/Components/BaseButton.vue'
|
||||
import BaseButtons from '@/Components/BaseButtons.vue'
|
||||
import CardBox from '@/Components/CardBox.vue'
|
||||
import OverlayLayer from '@/Components/OverlayLayer.vue'
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { mdiClose } from '@mdi/js';
|
||||
import BaseButton from '@/Components/BaseButton.vue';
|
||||
import BaseButtons from '@/Components/BaseButtons.vue';
|
||||
import CardBox from '@/Components/CardBox.vue';
|
||||
import OverlayLayer from '@/Components/OverlayLayer.vue';
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: null
|
||||
default: null,
|
||||
},
|
||||
largeTitle: {
|
||||
type: String,
|
||||
default: null
|
||||
default: null,
|
||||
},
|
||||
button: {
|
||||
type: String,
|
||||
default: 'info'
|
||||
default: 'info',
|
||||
},
|
||||
buttonLabel: {
|
||||
type: String,
|
||||
default: 'Done'
|
||||
default: 'Done',
|
||||
},
|
||||
hasCancel: Boolean,
|
||||
modelValue: {
|
||||
type: [String, Number, Boolean],
|
||||
default: null
|
||||
}
|
||||
})
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'cancel', 'confirm'])
|
||||
const emit = defineEmits(['update:modelValue', 'cancel', 'confirm']);
|
||||
|
||||
const value = computed({
|
||||
get: () => props.modelValue,
|
||||
set: value => emit('update:modelValue', value)
|
||||
})
|
||||
set: (value) => emit('update:modelValue', value),
|
||||
});
|
||||
|
||||
const confirmCancel = (mode) => {
|
||||
value.value = false;
|
||||
emit(mode);
|
||||
}
|
||||
};
|
||||
|
||||
const confirm = () => confirmCancel('confirm')
|
||||
const confirm = () => confirmCancel('confirm');
|
||||
|
||||
const cancel = () => confirmCancel('cancel')
|
||||
const cancel = () => confirmCancel('cancel');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<OverlayLayer v-show="value" @overlay-click="cancel">
|
||||
<CardBox v-show="value" :title="title" class="shadow-lg max-h-modal w-11/12 md:w-3/5 lg:w-2/5 xl:w-4/12 z-50"
|
||||
:header-icon="mdiClose" modal @header-icon-click="cancel">
|
||||
<CardBox
|
||||
v-show="value"
|
||||
:title="title"
|
||||
class="shadow-lg max-h-modal w-11/12 md:w-3/5 lg:w-2/5 xl:w-4/12 z-50"
|
||||
:header-icon="mdiClose"
|
||||
modal
|
||||
@header-icon-click="cancel"
|
||||
>
|
||||
<div class="space-y-3">
|
||||
<h1 v-if="largeTitle" class="text-2xl">
|
||||
{{ largeTitle }}
|
||||
|
|
|
@ -3,66 +3,71 @@ import { computed, ref, onMounted, onBeforeUnmount } from 'vue';
|
|||
import { MainService } from '@/Stores/main';
|
||||
import FormControlIcon from '@/Components/FormControlIcon.vue';
|
||||
const props = defineProps({
|
||||
name: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
autocomplete: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
inputmode: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: null,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text',
|
||||
},
|
||||
modelValue: {
|
||||
type: [String, Number, Boolean, Array, Object],
|
||||
default: '',
|
||||
},
|
||||
required: Boolean,
|
||||
borderless: Boolean,
|
||||
transparent: Boolean,
|
||||
ctrlKFocus: Boolean,
|
||||
name: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
id: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
autocomplete: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
inputmode: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
options: {
|
||||
type: [Array, Object],
|
||||
default: null,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text',
|
||||
},
|
||||
isReadOnly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
modelValue: {
|
||||
type: [String, Number, Boolean, Array, Object],
|
||||
default: '',
|
||||
},
|
||||
required: Boolean,
|
||||
borderless: Boolean,
|
||||
transparent: Boolean,
|
||||
ctrlKFocus: Boolean,
|
||||
});
|
||||
const emit = defineEmits(['update:modelValue', 'setRef']);
|
||||
const computedValue = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
emit('update:modelValue', value);
|
||||
},
|
||||
get: () => props.modelValue,
|
||||
set: (value) => {
|
||||
emit('update:modelValue', value);
|
||||
},
|
||||
});
|
||||
const inputElClass = computed(() => {
|
||||
const base = [
|
||||
'px-3 py-2 max-w-full focus:ring focus:outline-none border-gray-700 rounded w-full',
|
||||
'dark:placeholder-gray-400',
|
||||
computedType.value === 'textarea' ? 'h-24' : 'h-12',
|
||||
props.borderless ? 'border-0' : 'border',
|
||||
props.transparent ? 'bg-transparent' : 'bg-white dark:bg-slate-800',
|
||||
];
|
||||
if (props.icon) {
|
||||
base.push('pl-10');
|
||||
}
|
||||
return base;
|
||||
const base = [
|
||||
'px-3 py-2 max-w-full focus:ring focus:outline-none border-gray-700 rounded w-full',
|
||||
'dark:placeholder-gray-400',
|
||||
computedType.value === 'textarea' ? 'h-24' : 'h-12',
|
||||
props.borderless ? 'border-0' : 'border',
|
||||
// props.transparent && !props.isReadOnly ? 'bg-transparent' : 'bg-white dark:bg-slate-800',
|
||||
props.isReadOnly ? 'bg-gray-50 dark:bg-slate-600' : 'bg-white dark:bg-slate-800',
|
||||
];
|
||||
if (props.icon) {
|
||||
base.push('pl-10');
|
||||
}
|
||||
return base;
|
||||
});
|
||||
const computedType = computed(() => (props.options ? 'select' : props.type));
|
||||
const controlIconH = computed(() => (props.type === 'textarea' ? 'h-full' : 'h-12'));
|
||||
|
@ -71,74 +76,70 @@ const selectEl = ref(null);
|
|||
const textareaEl = ref(null);
|
||||
const inputEl = ref(null);
|
||||
onMounted(() => {
|
||||
if (selectEl.value) {
|
||||
emit('setRef', selectEl.value);
|
||||
} else if (textareaEl.value) {
|
||||
emit('setRef', textareaEl.value);
|
||||
} else {
|
||||
emit('setRef', inputEl.value);
|
||||
}
|
||||
if (selectEl.value) {
|
||||
emit('setRef', selectEl.value);
|
||||
} else if (textareaEl.value) {
|
||||
emit('setRef', textareaEl.value);
|
||||
} else {
|
||||
emit('setRef', inputEl.value);
|
||||
}
|
||||
});
|
||||
if (props.ctrlKFocus) {
|
||||
const fieldFocusHook = (e) => {
|
||||
if (e.ctrlKey && e.key === 'k') {
|
||||
e.preventDefault();
|
||||
inputEl.value.focus();
|
||||
} else if (e.key === 'Escape') {
|
||||
inputEl.value.blur();
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
if (!mainService.isFieldFocusRegistered) {
|
||||
window.addEventListener('keydown', fieldFocusHook);
|
||||
mainService.isFieldFocusRegistered = true;
|
||||
} else {
|
||||
// console.error('Duplicate field focus event')
|
||||
}
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', fieldFocusHook);
|
||||
mainService.isFieldFocusRegistered = false;
|
||||
});
|
||||
const fieldFocusHook = (e) => {
|
||||
if (e.ctrlKey && e.key === 'k') {
|
||||
e.preventDefault();
|
||||
inputEl.value.focus();
|
||||
} else if (e.key === 'Escape') {
|
||||
inputEl.value.blur();
|
||||
}
|
||||
};
|
||||
onMounted(() => {
|
||||
if (!mainService.isFieldFocusRegistered) {
|
||||
window.addEventListener('keydown', fieldFocusHook);
|
||||
mainService.isFieldFocusRegistered = true;
|
||||
} else {
|
||||
// console.error('Duplicate field focus event')
|
||||
}
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('keydown', fieldFocusHook);
|
||||
mainService.isFieldFocusRegistered = false;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="relative">
|
||||
<select
|
||||
v-if="computedType === 'select'"
|
||||
:id="id"
|
||||
v-model="computedValue"
|
||||
:name="name"
|
||||
:class="inputElClass"
|
||||
>
|
||||
<option v-for="option in options" :key="option.id ?? option" :value="option">
|
||||
{{ option.label ?? option }}
|
||||
</option>
|
||||
</select>
|
||||
<textarea
|
||||
v-else-if="computedType === 'textarea'"
|
||||
:id="id"
|
||||
v-model="computedValue"
|
||||
:class="inputElClass"
|
||||
:name="name"
|
||||
:placeholder="placeholder"
|
||||
:required="required"
|
||||
/>
|
||||
<input
|
||||
v-else
|
||||
:id="id"
|
||||
ref="inputEl"
|
||||
v-model="computedValue"
|
||||
:name="name"
|
||||
:inputmode="inputmode"
|
||||
:autocomplete="autocomplete"
|
||||
:required="required"
|
||||
:placeholder="placeholder"
|
||||
:type="computedType"
|
||||
:class="inputElClass"
|
||||
/>
|
||||
<FormControlIcon v-if="icon" :icon="icon" :h="controlIconH" />
|
||||
<slot />
|
||||
</div>
|
||||
<div class="relative">
|
||||
<select v-if="computedType === 'select'" :id="id" v-model="computedValue" :name="name" :class="inputElClass">
|
||||
<option v-if="placeholder" class="text-opacity-25" value="" disabled selected>{{ placeholder }}</option>
|
||||
<option v-for="option in options" :key="option.id ?? option" :value="option.value ?? option">
|
||||
{{ option.label ?? option }}
|
||||
</option>
|
||||
</select>
|
||||
<textarea
|
||||
v-else-if="computedType === 'textarea'"
|
||||
:id="id"
|
||||
v-model="computedValue"
|
||||
:class="inputElClass"
|
||||
:name="name"
|
||||
:placeholder="placeholder"
|
||||
:required="required"
|
||||
/>
|
||||
<input
|
||||
v-else
|
||||
:id="id"
|
||||
ref="inputEl"
|
||||
v-model="computedValue"
|
||||
:name="name"
|
||||
:inputmode="inputmode"
|
||||
:autocomplete="autocomplete"
|
||||
:required="required"
|
||||
:placeholder="placeholder"
|
||||
:type="computedType"
|
||||
:class="inputElClass"
|
||||
:readonly="isReadOnly"
|
||||
/>
|
||||
<FormControlIcon v-if="icon" :icon="icon" :h="controlIconH" />
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -2,46 +2,47 @@
|
|||
import { computed, useSlots } from 'vue';
|
||||
|
||||
defineProps({
|
||||
label: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
labelFor: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
labelFor: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
help: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
|
||||
const slots = useSlots();
|
||||
|
||||
const wrapperClass = computed(() => {
|
||||
const base = [];
|
||||
const slotsLength = slots.default().length;
|
||||
const base = [];
|
||||
const slotsLength = slots.default().length;
|
||||
|
||||
if (slotsLength > 1) {
|
||||
base.push('grid grid-cols-1 gap-3');
|
||||
}
|
||||
if (slotsLength > 1) {
|
||||
base.push('grid grid-cols-1 gap-3');
|
||||
}
|
||||
|
||||
if (slotsLength === 2) {
|
||||
base.push('md:grid-cols-2');
|
||||
}
|
||||
if (slotsLength === 2) {
|
||||
base.push('md:grid-cols-2');
|
||||
}
|
||||
|
||||
return base;
|
||||
return base;
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mb-6 last:mb-0">
|
||||
<label v-if="label" :for="labelFor" class="block font-bold mb-2">{{ label }}</label>
|
||||
<div v-bind:class="wrapperClass">
|
||||
<slot />
|
||||
</div>
|
||||
<div v-if="help" class="text-xs text-gray-500 dark:text-slate-400 mt-1">
|
||||
{{ help }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-6 last:mb-0">
|
||||
<!-- <label v-if="label" :for="labelFor" class="block font-bold mb-2">{{ label }}</label> -->
|
||||
<label v-if="label" :for="labelFor" class="font-bold h-6 mt-3 text-xs leading-8 uppercase">{{ label }}</label>
|
||||
<div v-bind:class="wrapperClass">
|
||||
<slot />
|
||||
</div>
|
||||
<div v-if="help" class="text-xs text-gray-500 dark:text-slate-400 mt-1">
|
||||
{{ help }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
44
resources/js/Components/Icons/Confirm.vue
Normal file
44
resources/js/Components/Icons/Confirm.vue
Normal file
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="100%"
|
||||
height="100%"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="my-svg-component"
|
||||
>
|
||||
<ellipse cx="12" cy="5" rx="9" ry="3"></ellipse>
|
||||
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"></path>
|
||||
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"></path>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'Icon_Mandatory',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my-svg-component {
|
||||
/* Scoped CSS here */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 1;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* path,
|
||||
circle {
|
||||
stroke: #ffffff;
|
||||
stroke-width: 6px;
|
||||
fill: none;
|
||||
} */
|
||||
</style>
|
35
resources/js/Components/Icons/Language.vue
Normal file
35
resources/js/Components/Icons/Language.vue
Normal file
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="my-svg-component">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M9 2.25a.75.75 0 01.75.75v1.506a49.38 49.38 0 015.343.371.75.75 0 11-.186 1.489c-.66-.083-1.323-.151-1.99-.206a18.67 18.67 0 01-2.969 6.323c.317.384.65.753.998 1.107a.75.75 0 11-1.07 1.052A18.902 18.902 0 019 13.687a18.823 18.823 0 01-5.656 4.482.75.75 0 11-.688-1.333 17.323 17.323 0 005.396-4.353A18.72 18.72 0 015.89 8.598a.75.75 0 011.388-.568A17.21 17.21 0 009 11.224a17.17 17.17 0 002.391-5.165 48.038 48.038 0 00-8.298.307.75.75 0 01-.186-1.489 49.159 49.159 0 015.343-.371V3A.75.75 0 019 2.25zM15.75 9a.75.75 0 01.68.433l5.25 11.25a.75.75 0 01-1.36.634l-1.198-2.567h-6.744l-1.198 2.567a.75.75 0 01-1.36-.634l5.25-11.25A.75.75 0 0115.75 9zm-2.672 8.25h5.344l-2.672-5.726-2.672 5.726z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Icon_Mandatory',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my-svg-component {
|
||||
/* Scoped CSS here */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 1;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* path,
|
||||
circle {
|
||||
stroke: #ffffff;
|
||||
stroke-width: 6px;
|
||||
fill: none;
|
||||
} */
|
||||
</style>
|
35
resources/js/Components/Icons/Mandatory.vue
Normal file
35
resources/js/Components/Icons/Mandatory.vue
Normal file
|
@ -0,0 +1,35 @@
|
|||
<template>
|
||||
<svg class="my-svg-component" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M11.42 15.17L17.25 21A2.652 2.652 0 0021 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 11-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 004.486-6.336l-3.276 3.277a3.004 3.004 0 01-2.25-2.25l3.276-3.276a4.5 4.5 0 00-6.336 4.486c.091 1.076-.071 2.264-.904 2.95l-.102.085m-1.745 1.437L5.909 7.5H4.5L2.25 3.75l1.5-1.5L7.5 4.5v1.409l4.26 4.26m-1.745 1.437l1.745-1.437m6.615 8.206L15.75 15.75M4.867 19.125h.008v.008h-.008v-.008z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Icon_Mandatory',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my-svg-component {
|
||||
/* Scoped CSS here */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* path,
|
||||
circle {
|
||||
stroke: #ffffff;
|
||||
stroke-width: 6px;
|
||||
fill: none;
|
||||
} */
|
||||
</style>
|
33
resources/js/Components/Icons/Recommendet.vue
Normal file
33
resources/js/Components/Icons/Recommendet.vue
Normal file
|
@ -0,0 +1,33 @@
|
|||
<template>
|
||||
<svg class="my-svg-component" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M6 3a3 3 0 00-3 3v2.25a3 3 0 003 3h2.25a3 3 0 003-3V6a3 3 0 00-3-3H6zM15.75 3a3 3 0 00-3 3v2.25a3 3 0 003 3H18a3 3 0 003-3V6a3 3 0 00-3-3h-2.25zM6 12.75a3 3 0 00-3 3V18a3 3 0 003 3h2.25a3 3 0 003-3v-2.25a3 3 0 00-3-3H6zM17.625 13.5a.75.75 0 00-1.5 0v2.625H13.5a.75.75 0 000 1.5h2.625v2.625a.75.75 0 001.5 0v-2.625h2.625a.75.75 0 000-1.5h-2.625V13.5z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Icon_Mandatory',
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my-svg-component {
|
||||
/* Scoped CSS here */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 2;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
/* path,
|
||||
circle {
|
||||
stroke: #ffffff;
|
||||
stroke-width: 6px;
|
||||
fill: none;
|
||||
} */
|
||||
</style>
|
49
resources/js/Components/Icons/Wizard.vue
Normal file
49
resources/js/Components/Icons/Wizard.vue
Normal file
|
@ -0,0 +1,49 @@
|
|||
<template>
|
||||
<div class="flex items-center relative">
|
||||
<!-- v-bind:class="{ 'text-white bg-teal-600 border-teal-600': isCurrent, 'border-teal-600': isChecked }" -->
|
||||
<div
|
||||
class="text-gray-500 rounded-full transition duration-500 ease-in-out h-12 w-12 py-3 border-2"
|
||||
:class="[
|
||||
isCurrent ? 'text-white bg-teal-600 border-teal-600' : 'border-gray-300',
|
||||
isChecked && 'text-teal-600 border-teal-600',
|
||||
]"
|
||||
>
|
||||
<!-- <svg class="my-svg-component" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M11.42 15.17L17.25 21A2.652 2.652 0 0021 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 11-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 004.486-6.336l-3.276 3.277a3.004 3.004 0 01-2.25-2.25l3.276-3.276a4.5 4.5 0 00-6.336 4.486c.091 1.076-.071 2.264-.904 2.95l-.102.085m-1.745 1.437L5.909 7.5H4.5L2.25 3.75l1.5-1.5L7.5 4.5v1.409l4.26 4.26m-1.745 1.437l1.745-1.437m6.615 8.206L15.75 15.75M4.867 19.125h.008v.008h-.008v-.008z"
|
||||
/>
|
||||
</svg> -->
|
||||
<slot></slot>
|
||||
<div class="absolute top-0 -ml-10 text-center mt-16 w-32 text-xs font-medium uppercase invisible sm:visible">
|
||||
{{ label }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!isLastStep"
|
||||
class="flex-auto border-t-2 transition duration-500 ease-in-out invisible sm:visible"
|
||||
:class="[isChecked ? 'border-teal-600' : 'border-gray-300']"
|
||||
></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Icon_Multistep',
|
||||
|
||||
props: {
|
||||
isCurrent: Boolean,
|
||||
isChecked: Boolean,
|
||||
isLastStep: Boolean,
|
||||
label: String,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
mode: 'light',
|
||||
checkedClass: 'border-teal-600',
|
||||
uncheckedClass: 'border-gray-300',
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -7,8 +7,8 @@ import {ComputedRef} from "vue";
|
|||
import { computed, ref } from 'vue';
|
||||
import { containerMaxW } from '@/config.js';
|
||||
// import { MainService } from '@/Stores/main.js';
|
||||
import { StyleService } from '@/Stores/style.js';
|
||||
import { LayoutService } from '@/Stores/layout.js';
|
||||
import { StyleService } from '@/Stores/style';
|
||||
import { LayoutService } from '@/Stores/layout';
|
||||
import {
|
||||
mdiForwardburger,
|
||||
mdiBackburger,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { StyleService } from '@/Stores/style.js'
|
||||
import { StyleService } from '@/Stores/style'
|
||||
// import { Link } from '@inertiajs/vue3'
|
||||
import { Link } from '@inertiajs/vue3'
|
||||
import { computed } from 'vue'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { StyleService } from '@/Stores/style.js'
|
||||
import { StyleService } from '@/Stores/style'
|
||||
import { computed, ref, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { mdiChevronUp, mdiChevronDown } from '@mdi/js'
|
||||
import NavBarItem from '@/Components/NavBarItem.vue'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { StyleService } from '@/Stores/style.js';
|
||||
import { StyleService } from '@/Stores/style';
|
||||
|
||||
defineProps({
|
||||
zIndex: {
|
||||
|
|
281
resources/js/Components/SearchAutocomplete.vue
Normal file
281
resources/js/Components/SearchAutocomplete.vue
Normal file
|
@ -0,0 +1,281 @@
|
|||
<template>
|
||||
<!-- <input
|
||||
v-model="data.search"
|
||||
@change="onChange"
|
||||
type="text"
|
||||
class="text-base font-medium block w-full rounded-md border transition ease-in-out focus:ring-1 border-gray-300 border-solid py-2 px-3 text-gray-700 placeholder-gray-400 focus:border-blue-200 focus:ring-blue-500 focus:outline-none"
|
||||
v-bind:name="props.name"
|
||||
/>
|
||||
<ul v-if="data.isOpen" class="mt-1 border-2 border-slate-50 overflow-auto shadow-lg rounded list-none">
|
||||
<li
|
||||
:class="['hover:bg-blue-100 hover:text-blue-800', 'w-full list-none text-left py-2 px-3 cursor-pointer']"
|
||||
v-for="(result, i) in data.results"
|
||||
:key="i"
|
||||
>
|
||||
{{ result.name }}
|
||||
</li>
|
||||
</ul> -->
|
||||
|
||||
<!-- <div class="flex-col justify-center relative"> -->
|
||||
<div class="relative">
|
||||
<input
|
||||
v-model="data.search"
|
||||
type="text"
|
||||
:class="inputElClass"
|
||||
:name="props.name"
|
||||
:placeholder="placeholder"
|
||||
autocomplete="off"
|
||||
@keydown.down="onArrowDown"
|
||||
@keydown.up="onArrowUp"
|
||||
/>
|
||||
<svg
|
||||
class="w-4 h-4 absolute left-2.5 top-3.5"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<!-- <ul v-if="data.isOpen" class="bg-white border border-gray-100 w-full mt-2 max-h-28 overflow-y-auto"> -->
|
||||
<!-- :ref="(el) => { ul[i] = el }" -->
|
||||
<ul v-if="data.isOpen" class="bg-white dark:bg-slate-800 w-full mt-2 max-h-28 overflow-y-auto scroll-smooth">
|
||||
<li
|
||||
class="pl-8 pr-2 py-1 border-b-2 border-gray-100 relative cursor-pointer hover:bg-yellow-50 hover:text-gray-900"
|
||||
:class="{
|
||||
'bg-yellow-50 text-gray-900': i == selectedIndex,
|
||||
}"
|
||||
v-for="(result, i) in data.results"
|
||||
:key="i"
|
||||
:ref="
|
||||
(el: HTMLLIElement | null) => {
|
||||
ul[i] = el;
|
||||
}
|
||||
"
|
||||
>
|
||||
<svg class="absolute w-4 h-4 left-2 top-2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
<!-- <b>Gar</b>{{ result.name }} -->
|
||||
|
||||
<!-- <span>
|
||||
{{ makeBold(result.name) }}
|
||||
</span> -->
|
||||
<span
|
||||
v-for="(item, index) in makeBold(result.name)"
|
||||
:key="index"
|
||||
:class="{
|
||||
'font-bold': data.search.toLowerCase().includes(item.toLowerCase()),
|
||||
'is-active': index == selectedIndex,
|
||||
}"
|
||||
>
|
||||
{{ item }}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- </div> -->
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, computed, Ref, watch } from 'vue';
|
||||
import axios from 'axios';
|
||||
let props = defineProps({
|
||||
name: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'autocomplete',
|
||||
},
|
||||
source: {
|
||||
type: [String, Array, Function],
|
||||
required: true,
|
||||
default: '',
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'name',
|
||||
},
|
||||
responseProperty: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'name',
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
icon: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
required: Boolean,
|
||||
borderless: Boolean,
|
||||
transparent: Boolean,
|
||||
ctrlKFocus: Boolean,
|
||||
});
|
||||
|
||||
const inputElClass = computed(() => {
|
||||
const base = [
|
||||
'px-3 py-2 max-w-full focus:ring focus:outline-none border-gray-700 rounded w-full',
|
||||
'dark:placeholder-gray-400',
|
||||
'h-12',
|
||||
props.borderless ? 'border-0' : 'border',
|
||||
props.transparent ? 'bg-transparent' : 'bg-white dark:bg-slate-800',
|
||||
// props.isReadOnly ? 'bg-gray-50 dark:bg-slate-600' : 'bg-white dark:bg-slate-800',
|
||||
];
|
||||
// if (props.icon) {
|
||||
base.push('pl-10');
|
||||
// }
|
||||
return base;
|
||||
});
|
||||
|
||||
let search = ref('');
|
||||
let data = reactive({
|
||||
search: search,
|
||||
isOpen: false,
|
||||
results: [],
|
||||
});
|
||||
let error = ref('');
|
||||
let selectedIndex: Ref<number> = ref(0);
|
||||
// const listItem = ref(null);
|
||||
const ul: Ref<Array<HTMLLIElement | null>> = ref([]);
|
||||
|
||||
watch(selectedIndex, (selectedIndex) => {
|
||||
if (selectedIndex != null && ul.value != null) {
|
||||
const currentElement: HTMLLIElement | null = ul.value[selectedIndex];
|
||||
currentElement &&
|
||||
currentElement.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'nearest',
|
||||
inline: 'start',
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
watch(search, async () => {
|
||||
await onChange();
|
||||
});
|
||||
|
||||
// function clear() {
|
||||
// data.search = "";
|
||||
// data.isOpen = false;
|
||||
// data.results = [];
|
||||
// error.value = "";
|
||||
// // this.$emit("clear");
|
||||
// }
|
||||
|
||||
// function onChange() {
|
||||
// if (!props.source || !data.search) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// data.isOpen = true;
|
||||
// arrayLikeSearch(props.source);
|
||||
// }
|
||||
async function onChange() {
|
||||
if (!props.source || !data.search) return false;
|
||||
|
||||
selectedIndex.value = 0;
|
||||
|
||||
if (data.search.length >= 2) {
|
||||
data.isOpen = true;
|
||||
switch (true) {
|
||||
case typeof props.source === 'string':
|
||||
return await request(props.source, data.search);
|
||||
// case typeof props.source === 'function':
|
||||
// return props.source(data.search).then((response) => {
|
||||
// data.results = getResults(response);
|
||||
// });
|
||||
case Array.isArray(props.source):
|
||||
return arrayLikeSearch(props.source);
|
||||
default:
|
||||
throw new Error('typeof source is ' + typeof props.source);
|
||||
}
|
||||
} else {
|
||||
data.results = [];
|
||||
data.isOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
function getResults(response) {
|
||||
// if (props.responseProperty) {
|
||||
// let foundObj;
|
||||
// JSON.stringify(response, (_, nestedValue) => {
|
||||
// if (nestedValue && nestedValue[props.responseProperty]) foundObj = nestedValue[props.responseProperty];
|
||||
|
||||
// return nestedValue;
|
||||
// });
|
||||
// return foundObj;
|
||||
// }
|
||||
if (Array.isArray(response)) {
|
||||
return response;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// function setResult(result) {
|
||||
// data.search = result[props.label];
|
||||
// data.isOpen = false;
|
||||
// }
|
||||
|
||||
// function request(url) {
|
||||
// return axios.get(url).then((response) => {
|
||||
// data.results = getResults(response);
|
||||
// });
|
||||
// }
|
||||
async function request(url, param) {
|
||||
try {
|
||||
let response = await searchTerm(url, param);
|
||||
error.value = '';
|
||||
data.results = getResults(response);
|
||||
// this.results = res.data;
|
||||
// this.loading = false;
|
||||
} catch (error) {
|
||||
error.value = error.message;
|
||||
// this.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function searchTerm(term: string, param): Promise<any> {
|
||||
let res = await axios.get(term, { params: { filter: param } });
|
||||
// console.log(res.data);
|
||||
return res.data; //.response;//.docs;
|
||||
}
|
||||
// async function request(term: string): Promise<any> {
|
||||
// let res = await axios.get('/api/persons', { params: { filter: term } });
|
||||
// return res.data; //.response;//.docs;
|
||||
// }
|
||||
|
||||
function arrayLikeSearch(items) {
|
||||
data.results = items.filter((item) => {
|
||||
return item.toLowerCase().indexOf(data.search.toLowerCase()) > -1;
|
||||
});
|
||||
}
|
||||
|
||||
function makeBold(suggestion) {
|
||||
const query = data.search.valueOf();
|
||||
const regex = new RegExp(query.split('').join('-?'), 'i');
|
||||
const test = suggestion.replace(regex, (match) => '<split>' + match + '<split>');
|
||||
// return suggestion.match(regex);
|
||||
// const splitWord = suggestion.match(regex);
|
||||
return test.split('<split>');
|
||||
}
|
||||
|
||||
function onArrowDown() {
|
||||
if (data.results.length > 0) {
|
||||
selectedIndex.value = selectedIndex.value === data.results.length - 1 ? 0 : selectedIndex.value + 1;
|
||||
// const currentElement: HTMLLIElement = ul.value[selectedIndex.value];
|
||||
}
|
||||
}
|
||||
|
||||
function onArrowUp() {
|
||||
if (data.results.length > 0) {
|
||||
selectedIndex.value = selectedIndex.value == 0 || selectedIndex.value == -1 ? data.results.length - 1 : selectedIndex.value - 1;
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -1,9 +1,9 @@
|
|||
<script setup>
|
||||
import { containerMaxW } from '@/config.js'
|
||||
import { containerMaxW } from '@/config.js';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="p-6" v-bind:class="containerMaxW">
|
||||
<slot />
|
||||
</section>
|
||||
<section class="p-6" v-bind:class="containerMaxW">
|
||||
<slot />
|
||||
</section>
|
||||
</template>
|
||||
|
|
30
resources/js/Dataset.ts
Normal file
30
resources/js/Dataset.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { Ref } from 'vue';
|
||||
|
||||
export interface Dataset {
|
||||
[key: string]: string | Ref<string>| boolean | Array<Title> | (IErrorMessage | undefined);
|
||||
language: Ref<string>;
|
||||
// licenses: Array<number>;
|
||||
rights: boolean;
|
||||
type: string;
|
||||
creating_corporation: string;
|
||||
titles: Array<Title>;
|
||||
descriptions: Array<Description>;
|
||||
errors?: IErrorMessage;
|
||||
// async (user): Promise<void>;
|
||||
}
|
||||
|
||||
export interface Title {
|
||||
value: string;
|
||||
type: string;
|
||||
language: string | Ref<string>;
|
||||
}
|
||||
|
||||
export interface Description {
|
||||
value: string;
|
||||
type: string;
|
||||
language: string | Ref<string>;
|
||||
}
|
||||
|
||||
interface IErrorMessage {
|
||||
[key: string]: Array<string>;
|
||||
}
|
|
@ -1,33 +1,37 @@
|
|||
<script lang="ts" setup>
|
||||
import { LayoutService } from '@/Stores/layout.js'
|
||||
import { StyleService } from '@/Stores/style'
|
||||
import NavBar from '@/Components/NavBar.vue'
|
||||
import AsideMenu from '@/Components/AsideMenu.vue'
|
||||
import FooterBar from '@/Components/FooterBar.vue'
|
||||
import { LayoutService } from '@/Stores/layout';
|
||||
import { StyleService } from '@/Stores/style';
|
||||
import NavBar from '@/Components/NavBar.vue';
|
||||
import AsideMenu from '@/Components/AsideMenu.vue';
|
||||
import FooterBar from '@/Components/FooterBar.vue';
|
||||
|
||||
const styleService = StyleService()
|
||||
const styleService = StyleService();
|
||||
|
||||
const layoutService = LayoutService()
|
||||
const layoutService = LayoutService();
|
||||
|
||||
// defineProps({
|
||||
// defineProps({
|
||||
// user: {
|
||||
// type: Object,
|
||||
// default: () => ({}),
|
||||
// }
|
||||
// });
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="{ 'dark': styleService.darkMode, 'overflow-hidden lg:overflow-visible': layoutService.isAsideMobileExpanded }">
|
||||
<div
|
||||
:class="{ 'ml-60 lg:ml-0': layoutService.isAsideMobileExpanded }"
|
||||
class="pt-14 xl:pl-60 min-h-screen w-screen transition-position lg:w-auto bg-gray-50 dark:bg-slate-800 dark:text-slate-100"
|
||||
:class="{
|
||||
'dark': styleService.darkMode,
|
||||
'overflow-hidden lg:overflow-visible': layoutService.isAsideMobileExpanded,
|
||||
}"
|
||||
>
|
||||
<NavBar :class="{ 'ml-60 lg:ml-0': layoutService.isAsideMobileExpanded }" />
|
||||
<AsideMenu />
|
||||
<slot></slot>
|
||||
<FooterBar />
|
||||
<div
|
||||
:class="{ 'ml-60 lg:ml-0': layoutService.isAsideMobileExpanded }"
|
||||
class="pt-14 xl:pl-60 min-h-screen w-screen transition-position lg:w-auto bg-gray-50 dark:bg-slate-800 dark:text-slate-100"
|
||||
>
|
||||
<NavBar :class="{ 'ml-60 lg:ml-0': layoutService.isAsideMobileExpanded }" />
|
||||
<AsideMenu />
|
||||
<slot></slot>
|
||||
<FooterBar />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { StyleService } from '@/Stores/style.js';
|
||||
import { StyleService } from '@/Stores/style';
|
||||
const styleService = StyleService();
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { StyleService } from '@/Stores/style.js';
|
||||
import { StyleService } from '@/Stores/style';
|
||||
|
||||
import {
|
||||
mdiContrastCircle,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script setup>
|
||||
<script setup lang="ts">
|
||||
// import { Head, Link, useForm } from '@inertiajs/inertia-vue3';
|
||||
import { Head, Link, useForm, router } from '@inertiajs/vue3';
|
||||
import { useForm } from '@inertiajs/vue3';
|
||||
// import { reactive } from 'vue';
|
||||
import {
|
||||
mdiAccount,
|
||||
mdiAccountCircle,
|
||||
|
@ -9,7 +10,7 @@ import {
|
|||
mdiAsterisk,
|
||||
mdiFormTextboxPassword,
|
||||
mdiArrowLeftBoldOutline,
|
||||
mdiAlertBoxOutline,
|
||||
// mdiAlertBoxOutline,
|
||||
} from '@mdi/js';
|
||||
import SectionMain from '@/Components/SectionMain.vue';
|
||||
import CardBox from '@/Components/CardBox.vue';
|
||||
|
@ -18,7 +19,7 @@ import FormField from '@/Components/FormField.vue';
|
|||
import FormControl from '@/Components/FormControl.vue';
|
||||
import BaseButton from '@/Components/BaseButton.vue';
|
||||
import BaseButtons from '@/Components/BaseButtons.vue';
|
||||
import NotificationBar from '@/Components/NotificationBar.vue';
|
||||
// import NotificationBar from '@/Components/NotificationBar.vue';
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import SectionTitleLineWithButton from '@/Components/SectionTitleLineWithButton.vue';
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
|
@ -41,16 +42,16 @@ const profileForm = useForm({
|
|||
email: props.user.email,
|
||||
});
|
||||
const profileSubmit = async () => {
|
||||
await router.post(stardust.route('admin.account.info.store', [props.user.id]), profileForm);
|
||||
await profileForm.post(stardust.route('admin.account.info.store', [props.user.id]));
|
||||
};
|
||||
|
||||
const passwordForm = useForm({
|
||||
old_password: null,
|
||||
new_password: null,
|
||||
confirm_password: null,
|
||||
old_password: "",
|
||||
new_password: "",
|
||||
confirm_password: "",
|
||||
});
|
||||
const passwordSubmit = async () => {
|
||||
await router.post(stardust.route('admin.account.info.store'), passwordForm, {
|
||||
await passwordForm.post(stardust.route('admin.account.info.store'), {
|
||||
preserveScroll: true,
|
||||
onSuccess: (resp) => {
|
||||
console.log(resp);
|
||||
|
@ -68,9 +69,9 @@ const passwordSubmit = async () => {
|
|||
rounded-full small />
|
||||
</SectionTitleLineWithButton>
|
||||
|
||||
<NotificationBar v-if="$page.props.flash.message" color="success" :icon="mdiAlertBoxOutline">
|
||||
<!-- <NotificationBar v-if="$page.props.flash.message" color="success" :icon="mdiAlertBoxOutline">
|
||||
{{ $page.props.flash.message }}
|
||||
</NotificationBar>
|
||||
</NotificationBar> -->
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { Head, Link, useForm, router } from '@inertiajs/vue3';
|
||||
<script setup lang="ts">
|
||||
import { Head, useForm, router } from '@inertiajs/vue3';
|
||||
import { mdiAccountKey, mdiArrowLeftBoldOutline } from '@mdi/js';
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import SectionMain from '@/Components/SectionMain.vue';
|
||||
|
@ -45,11 +45,11 @@ const submit = async () => {
|
|||
<SectionMain>
|
||||
<SectionTitleLineWithButton :icon="mdiAccountKey" title="Add user" main>
|
||||
<BaseButton :route-name="stardust.route('user.index')" :icon="mdiArrowLeftBoldOutline" label="Back"
|
||||
color="white" rounded-full small />
|
||||
color="modern" rounded-full small />
|
||||
</SectionTitleLineWithButton>
|
||||
<!-- @submit.prevent="form.post(stardust.route('user.store'))" -->
|
||||
<CardBox form @submit.prevent="submit()">
|
||||
<FormField label="Login" :class="{ 'text-red-400': errors.name }">
|
||||
<FormField label="Login" :class="{ 'text-red-400': errors.login }">
|
||||
<FormControl v-model="form.login" type="text" placeholder="Enter Login" :errors="errors.login">
|
||||
<div class="text-red-400 text-sm" v-if="errors.login && Array.isArray(errors.login)">
|
||||
<!-- {{ errors.login }} -->
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { Head, Link, useForm, router } from "@inertiajs/vue3"
|
||||
<script setup lang="ts">
|
||||
import { Head, useForm, router } from "@inertiajs/vue3"
|
||||
import {
|
||||
mdiAccountKey,
|
||||
mdiArrowLeftBoldOutline
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script setup>
|
||||
<script setup lang="ts">
|
||||
// import { Head, Link, useForm, usePage } from '@inertiajs/inertia-vue3';
|
||||
import { Head, Link, useForm, usePage } from '@inertiajs/vue3';
|
||||
import { ComputedRef } from 'vue';
|
||||
import {
|
||||
mdiAccountKey,
|
||||
mdiPlus,
|
||||
|
@ -8,7 +9,7 @@ import {
|
|||
mdiTrashCan,
|
||||
mdiAlertBoxOutline,
|
||||
} from '@mdi/js';
|
||||
import { watch, computed } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import SectionMain from '@/Components/SectionMain.vue';
|
||||
import SectionTitleLineWithButton from '@/Components/SectionTitleLineWithButton.vue';
|
||||
|
@ -44,7 +45,7 @@ const props = defineProps({
|
|||
// return props.filters.search;
|
||||
// });
|
||||
|
||||
const flash = computed(() => {
|
||||
const flash: ComputedRef<any> = computed(() => {
|
||||
// let test = usePage();
|
||||
// console.log(test);
|
||||
return usePage().props.flash;
|
||||
|
@ -73,7 +74,7 @@ const destroy = async (id) => {
|
|||
<SectionMain>
|
||||
<SectionTitleLineWithButton :icon="mdiAccountKey" title="Tethys Users" main>
|
||||
<BaseButton v-if="can.create" :route-name="stardust.route('user.create')" :icon="mdiPlus" label="Add"
|
||||
color="info" rounded-full small />
|
||||
color="modern" rounded-full small />
|
||||
</SectionTitleLineWithButton>
|
||||
<!-- <label>{{ form.search }}</label> -->
|
||||
<NotificationBar v-if="flash.message" color="success" :icon="mdiAlertBoxOutline">
|
||||
|
@ -87,7 +88,7 @@ const destroy = async (id) => {
|
|||
<input type="search" v-model="form.search"
|
||||
class="rounded-md shadow-sm border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||
placeholder="Search" />
|
||||
<BaseButton label="Search" type="submit" color="info"
|
||||
<BaseButton label="Search" type="submit" color="modern"
|
||||
class="ml-4 inline-flex items-center px-4 py-2" />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,92 +1,67 @@
|
|||
<script setup>
|
||||
import { Head, Link, useForm } from "@inertiajs/vue3"
|
||||
import {
|
||||
mdiAccountKey,
|
||||
mdiArrowLeftBoldOutline,
|
||||
} from "@mdi/js"
|
||||
import LayoutAuthenticated from "@/Layouts/LayoutAuthenticated.vue"
|
||||
import SectionMain from "@/Components/SectionMain.vue"
|
||||
import SectionTitleLineWithButton from "@/Components/SectionTitleLineWithButton.vue"
|
||||
import CardBox from "@/Components/CardBox.vue"
|
||||
import BaseButton from "@/Components/BaseButton.vue"
|
||||
<script setup lang="ts">
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { mdiAccountKey, mdiArrowLeftBoldOutline } from '@mdi/js';
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import SectionMain from '@/Components/SectionMain.vue';
|
||||
import SectionTitleLineWithButton from '@/Components/SectionTitleLineWithButton.vue';
|
||||
import CardBox from '@/Components/CardBox.vue';
|
||||
import BaseButton from '@/Components/BaseButton.vue';
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
|
||||
const props = defineProps({
|
||||
user: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
roles: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
userHasRoles: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
}
|
||||
})
|
||||
defineProps({
|
||||
user: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
roles: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
userHasRoles: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<LayoutAuthenticated :user="user">
|
||||
|
||||
<Head title="View user" />
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton :icon="mdiAccountKey" title="View user" main>
|
||||
<BaseButton :route-name="stardust.route('user.index')" :icon="mdiArrowLeftBoldOutline" label="Back" color="white"
|
||||
rounded-full small />
|
||||
</SectionTitleLineWithButton>
|
||||
<CardBox class="mb-6">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="
|
||||
p-4
|
||||
pl-8
|
||||
text-slate-500
|
||||
dark:text-slate-400
|
||||
hidden
|
||||
lg:block
|
||||
">
|
||||
Login
|
||||
</td>
|
||||
<td data-label="Login">
|
||||
{{ user.login }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="
|
||||
p-4
|
||||
pl-8
|
||||
text-slate-500
|
||||
dark:text-slate-400
|
||||
hidden
|
||||
lg:block
|
||||
">
|
||||
Email
|
||||
</td>
|
||||
<td data-label="Email">
|
||||
{{ user.email }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="
|
||||
p-4
|
||||
pl-8
|
||||
text-slate-500
|
||||
dark:text-slate-400
|
||||
hidden
|
||||
lg:block
|
||||
">
|
||||
Created
|
||||
</td>
|
||||
<td data-label="Created">
|
||||
{{ new Date(user.created_at).toLocaleString() }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</CardBox>
|
||||
</SectionMain>
|
||||
</LayoutAuthenticated>
|
||||
<LayoutAuthenticated :user="user">
|
||||
<Head title="View user" />
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton :icon="mdiAccountKey" title="View user" main>
|
||||
<BaseButton
|
||||
:route-name="stardust.route('user.index')"
|
||||
:icon="mdiArrowLeftBoldOutline"
|
||||
label="Back"
|
||||
color="white"
|
||||
rounded-full
|
||||
small
|
||||
/>
|
||||
</SectionTitleLineWithButton>
|
||||
<CardBox class="mb-6">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="p-4 pl-8 text-slate-500 dark:text-slate-400 hidden lg:block">Login</td>
|
||||
<td data-label="Login">
|
||||
{{ user.login }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="p-4 pl-8 text-slate-500 dark:text-slate-400 hidden lg:block">Email</td>
|
||||
<td data-label="Email">
|
||||
{{ user.email }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="p-4 pl-8 text-slate-500 dark:text-slate-400 hidden lg:block">Created</td>
|
||||
<td data-label="Created">
|
||||
{{ new Date(user.created_at).toLocaleString() }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</CardBox>
|
||||
</SectionMain>
|
||||
</LayoutAuthenticated>
|
||||
</template>
|
||||
|
|
|
@ -31,60 +31,70 @@ import FormControl from '@/Components/FormControl.vue';
|
|||
</script> -->
|
||||
|
||||
<template>
|
||||
<LayoutGuest>
|
||||
<LayoutGuest>
|
||||
<Head title="Login" />
|
||||
|
||||
<Head title="Login" />
|
||||
<SectionFullScreen v-slot="{ cardClass }" :bg="'greenBlue'">
|
||||
<CardBox :class="cardClass" form @submit.prevent="submit">
|
||||
<FormValidationErrors v-bind:errors="errors" />
|
||||
|
||||
<SectionFullScreen v-slot="{ cardClass }" :bg="'greenBlue'">
|
||||
<CardBox :class="cardClass" form @submit.prevent="submit">
|
||||
<FormValidationErrors v-bind:errors="errors" />
|
||||
<NotificationBarInCard v-if="status" color="info">
|
||||
{{ status }}
|
||||
</NotificationBarInCard>
|
||||
|
||||
<NotificationBarInCard v-if="status" color="info">
|
||||
{{ status }}
|
||||
</NotificationBarInCard>
|
||||
<FormField label="Email" label-for="email" help="Please enter your email">
|
||||
<FormControl v-model="form.email" :icon="mdiAccount" id="email" autocomplete="email" type="email" required />
|
||||
</FormField>
|
||||
|
||||
<FormField label="Email" label-for="email" help="Please enter your email">
|
||||
<FormControl v-model="form.email" :icon="mdiAccount" id="email" autocomplete="email" type="email"
|
||||
required />
|
||||
</FormField>
|
||||
<FormField label="Password" label-for="password" help="Please enter your password">
|
||||
<FormControl
|
||||
v-model="form.password"
|
||||
:icon="mdiAsterisk"
|
||||
type="password"
|
||||
id="password"
|
||||
autocomplete="current-password"
|
||||
required
|
||||
/>
|
||||
</FormField>
|
||||
|
||||
<FormField label="Password" label-for="password" help="Please enter your password">
|
||||
<FormControl v-model="form.password" :icon="mdiAsterisk" type="password" id="password"
|
||||
autocomplete="current-password" required />
|
||||
</FormField>
|
||||
<FormCheckRadioGroup v-model="form.remember" name="remember" :options="{ remember: 'Remember' }" />
|
||||
|
||||
<FormCheckRadioGroup v-model="form.remember" name="remember" :options="{ remember: 'Remember' }" />
|
||||
|
||||
<!-- <NotificationBar v-if="flash && flash.message" color="warning" :icon="mdiAlertBoxOutline">
|
||||
<!-- <NotificationBar v-if="flash && flash.message" color="warning" :icon="mdiAlertBoxOutline">
|
||||
{{ flash.message }}
|
||||
class="bg-orange-100 border-l-4 border-orange-500 text-orange-700 p-4"
|
||||
</NotificationBar> -->
|
||||
<div v-if="flash && flash.message" class="flex flex-col mt-6 animate-fade-in">
|
||||
<div class="bg-yellow-500 border-l-4 border-orange-400 text-white p-4" role="alert">
|
||||
<p class="font-bold">Be Warned</p>
|
||||
<p>{{ flash.message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="flash && flash.message" class="flex flex-col mt-6 animate-fade-in">
|
||||
<div class="bg-yellow-500 border-l-4 border-orange-400 text-white p-4" role="alert">
|
||||
<p class="font-bold">Be Warned</p>
|
||||
<p>{{ flash.message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<BaseDivider />
|
||||
<BaseDivider />
|
||||
|
||||
<!-- buttons -->
|
||||
<BaseLevel>
|
||||
<BaseButtons>
|
||||
<BaseButton type="submit" color="info" label="Login" :class="{ 'opacity-25': form.processing }"
|
||||
v-bind:disabled="form.processing" />
|
||||
<!-- <BaseButton v-if="canResetPassword" :route-name="route('password.request')" color="info" outline
|
||||
<!-- buttons -->
|
||||
<BaseLevel>
|
||||
<BaseButtons>
|
||||
<BaseButton
|
||||
type="submit"
|
||||
color="info"
|
||||
label="Login"
|
||||
:class="{ 'opacity-25': form.processing }"
|
||||
v-bind:disabled="form.processing"
|
||||
/>
|
||||
<!-- <BaseButton v-if="canResetPassword" :route-name="route('password.request')" color="info" outline
|
||||
label="Remind" /> -->
|
||||
</BaseButtons>
|
||||
<Link :href="stardust.route('app.register.show')"> Register </Link>
|
||||
</BaseLevel>
|
||||
</CardBox>
|
||||
</SectionFullScreen>
|
||||
</LayoutGuest>
|
||||
</BaseButtons>
|
||||
<!-- <Link :href="stardust.route('app.register.show')"> Register </Link> -->
|
||||
</BaseLevel>
|
||||
</CardBox>
|
||||
</SectionFullScreen>
|
||||
</LayoutGuest>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useForm, Head, Link } from '@inertiajs/vue3';
|
||||
<script setup lang="ts">
|
||||
import { useForm, Head } from '@inertiajs/vue3';
|
||||
import { Ref } from 'vue';
|
||||
// import { Head, Link, useForm } from '@inertiajs/inertia-vue3';
|
||||
import { mdiAccount, mdiAsterisk } from '@mdi/js';
|
||||
import LayoutGuest from '@/Layouts/LayoutGuest.vue';
|
||||
|
@ -101,45 +111,45 @@ import NotificationBarInCard from '@/Components/NotificationBarInCard.vue';
|
|||
import BaseLevel from '@/Components/BaseLevel.vue';
|
||||
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
import NotificationBar from '@/Components/NotificationBar.vue';
|
||||
// import NotificationBar from '@/Components/NotificationBar.vue';
|
||||
import { computed } from 'vue';
|
||||
import { usePage } from '@inertiajs/vue3';
|
||||
|
||||
// interface IErrorMessage {
|
||||
// [key: string]: Array<string>;
|
||||
// }
|
||||
const flash = computed(() => {
|
||||
return usePage().props.flash;
|
||||
const flash: Ref<any> = computed(() => {
|
||||
return usePage().props.flash;
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
canResetPassword: Boolean,
|
||||
status: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
errors: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
defineProps({
|
||||
canResetPassword: Boolean,
|
||||
status: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
errors: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
const form = useForm({
|
||||
email: '',
|
||||
password: '',
|
||||
remember: [],
|
||||
email: '',
|
||||
password: '',
|
||||
remember: [],
|
||||
});
|
||||
|
||||
const submit = async() => {
|
||||
await form
|
||||
.transform((data) => ({
|
||||
...data,
|
||||
remember: form.remember && form.remember.length ? 'on' : '',
|
||||
}))
|
||||
.post(stardust.route('login.store'), {
|
||||
// onFinish: () => {
|
||||
// form.reset('password');
|
||||
// }
|
||||
});
|
||||
const submit = async () => {
|
||||
await form
|
||||
.transform((data) => ({
|
||||
...data,
|
||||
remember: form.remember && form.remember.length ? 'on' : '',
|
||||
}))
|
||||
.post(stardust.route('login.store'), {
|
||||
onFinish: () => {
|
||||
form.reset('password');
|
||||
},
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { computed, ref, onMounted } from 'vue';
|
||||
import { MainService } from '@/Stores/main';
|
||||
// import { Inertia } from '@inertiajs/inertia';
|
||||
import {
|
||||
mdiAccountMultiple,
|
||||
mdiCartOutline,
|
||||
mdiDatabaseOutline,
|
||||
mdiChartTimelineVariant,
|
||||
mdiFinance,
|
||||
|
@ -13,7 +13,7 @@ import {
|
|||
mdiGithub,
|
||||
mdiChartPie,
|
||||
} from '@mdi/js';
|
||||
import { containerMaxW } from '@/config.js'; // "xl:max-w-6xl xl:mx-auto"
|
||||
// import { containerMaxW } from '@/config.js'; // "xl:max-w-6xl xl:mx-auto"
|
||||
import * as chartConfig from '@/Components/Charts/chart.config.js';
|
||||
import LineChart from '@/Components/Charts/LineChart.vue';
|
||||
import SectionMain from '@/Components/SectionMain.vue';
|
||||
|
@ -27,7 +27,7 @@ import CardBoxClient from '@/Components/CardBoxClient.vue';
|
|||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import SectionTitleLineWithButton from '@/Components/SectionTitleLineWithButton.vue';
|
||||
import SectionBannerStarOnGitHub from '@/Components/SectionBannerStarOnGitea.vue';
|
||||
const chartData = ref(null);
|
||||
const chartData = ref();
|
||||
const fillChartData = () => {
|
||||
chartData.value = chartConfig.sampleChartData();
|
||||
};
|
||||
|
@ -42,7 +42,7 @@ mainService.fetch('history');
|
|||
mainService.fetchApi('authors');
|
||||
mainService.fetchApi('datasets');
|
||||
|
||||
const clientBarItems = computed(() => mainService.clients.slice(0, 4));
|
||||
// const clientBarItems = computed(() => mainService.clients.slice(0, 4));
|
||||
const transactionBarItems = computed(() => mainService.history);
|
||||
|
||||
const authorBarItems = computed(() => mainService.authors.slice(0, 4));
|
||||
|
@ -109,9 +109,9 @@ const datasets = computed(() => mainService.datasets);
|
|||
|
||||
<SectionTitleLineWithButton :icon="mdiAccountMultiple" title="Submitters (to do)" />
|
||||
|
||||
<!-- <NotificationBar color="info" :icon="mdiMonitorCellphone">
|
||||
<NotificationBar color="info" :icon="mdiMonitorCellphone">
|
||||
<b>Responsive table.</b> Collapses on mobile
|
||||
</NotificationBar> -->
|
||||
</NotificationBar>
|
||||
|
||||
<CardBox :icon="mdiMonitorCellphone" title="Responsive table" has-table>
|
||||
<TableSampleClients />
|
||||
|
|
604
resources/js/Pages/Submitter/Dataset/Create.vue
Normal file
604
resources/js/Pages/Submitter/Dataset/Create.vue
Normal file
|
@ -0,0 +1,604 @@
|
|||
<script setup lang="ts">
|
||||
import { Head, useForm } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
import { Dataset, Title } from '@/Dataset';
|
||||
import { mdiDatabasePlus, mdiMinusCircle, mdiPlusCircle, mdiFinance, mdiInformationOutline, mdiBookOpenPageVariant } from '@mdi/js';
|
||||
import LayoutAuthenticated from '@/Layouts/LayoutAuthenticated.vue';
|
||||
import SectionMain from '@/Components/SectionMain.vue';
|
||||
import SectionTitleLineWithButton from '@/Components/SectionTitleLineWithButton.vue';
|
||||
import CardBox from '@/Components/CardBox.vue';
|
||||
import FormField from '@/Components/FormField.vue';
|
||||
import FormControl from '@/Components/FormControl.vue';
|
||||
import FormCheckRadioGroup from '@/Components/FormCheckRadioGroup.vue';
|
||||
// import BaseDivider from '@/Components/BaseDivider.vue';
|
||||
import BaseButton from '@/Components/BaseButton.vue';
|
||||
// import BaseButtons from '@/Components/BaseButtons.vue';
|
||||
import { stardust } from '@eidellev/adonis-stardust/client';
|
||||
// import { Inertia } from '@inertiajs/inertia';
|
||||
import CardBoxModal from '@/Components/CardBoxModal.vue';
|
||||
import BaseIcon from '@/Components/BaseIcon.vue';
|
||||
|
||||
import IconWizard from '@/Components/Icons/Wizard.vue';
|
||||
import IconMandatory from '@/Components/Icons/Mandatory.vue';
|
||||
import IconLanguage from '@/Components/Icons/Language.vue';
|
||||
import IconRecommendet from '@/Components/Icons/Recommendet.vue';
|
||||
import IconConfirm from '@/Components/Icons/Confirm.vue';
|
||||
import SearchAutocomplete from '@/Components/SearchAutocomplete.vue';
|
||||
|
||||
const props = defineProps({
|
||||
licenses: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
doctypes: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
titletypes: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
descriptiontypes: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
errors: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
});
|
||||
|
||||
// const form = useForm({
|
||||
// language: '',
|
||||
// licenses: [],
|
||||
// type: '',
|
||||
// titles: [{ value: '', type: 'Main', language: Dataset.language }],
|
||||
// });
|
||||
// let language: (string | Ref<string>) = ref('');
|
||||
let language = ref('');
|
||||
let dataset = {
|
||||
language: language,
|
||||
licenses: [],
|
||||
rights: false,
|
||||
type: '',
|
||||
creating_corporation: 'Tethys RDR',
|
||||
titles: [{ value: '', type: 'Main', language: language }],
|
||||
descriptions: [{ value: '', type: 'Abstract', language: language }],
|
||||
// errors: undefined,
|
||||
};
|
||||
// const form = useForm({
|
||||
// language: language,
|
||||
// licenses: [],
|
||||
// rights: false,
|
||||
// type: '',
|
||||
// creating_corporation: 'Tethys RDR',
|
||||
// titles: [{ value: '', type: 'Main', language: language }],
|
||||
// descriptions: [{ value: '', type: 'Abstract', language: language }],
|
||||
// });
|
||||
const form = useForm<Dataset>(dataset);
|
||||
// dataset.language.value = 'de';
|
||||
|
||||
// const emit = defineEmits(['update:modelValue', 'setRef']);
|
||||
// computed({
|
||||
// get: () => form.rights,
|
||||
// set: (value) => {
|
||||
// emit('update:modelValue', value);
|
||||
// },
|
||||
// });
|
||||
|
||||
const isModalActive = ref(false);
|
||||
const formStep = ref(1);
|
||||
|
||||
// const submit = async () => {
|
||||
// await router.post(stardust.route('user.store'), form, {
|
||||
// onSuccess: () => {
|
||||
// form.reset(), (formStep.value = 1);
|
||||
// },
|
||||
// });
|
||||
// };
|
||||
|
||||
const nextStep = async () => {
|
||||
let route = stardust.route('dataset.first.step');
|
||||
if (formStep.value == 2) {
|
||||
route = stardust.route('dataset.second.step');
|
||||
}
|
||||
// formStep.value++;
|
||||
await form
|
||||
.transform((data) => ({
|
||||
...data,
|
||||
rights: form.rights && form.rights == true ? 'true' : 'false',
|
||||
}))
|
||||
.post(route, {
|
||||
form,
|
||||
onSuccess: () => {
|
||||
formStep.value++;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const prevStep = () => {
|
||||
formStep.value--;
|
||||
};
|
||||
|
||||
const addTitle = () => {
|
||||
let newTitle: Title = { value: '', language: '', type: '' };
|
||||
//this.dataset.files.push(uploadedFiles[i]);
|
||||
form.titles.push(newTitle);
|
||||
};
|
||||
const removeTitle = (key) => {
|
||||
form.titles.splice(key, 1);
|
||||
};
|
||||
|
||||
const addDescription = () => {
|
||||
let newDescription = { value: '', language: '', type: '' };
|
||||
//this.dataset.files.push(uploadedFiles[i]);
|
||||
form.descriptions.push(newDescription);
|
||||
};
|
||||
const removeDescription = (key) => {
|
||||
form.descriptions.splice(key, 1);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<CardBoxModal v-model="isModalActive" title="Einverständniserklärung *">
|
||||
Mit dem Setzen des Hakens bestätige ich hiermit
|
||||
<ul class="list-decimal">
|
||||
<li>
|
||||
die Data Policy von Tethys RDR sowie die Terms & Conditions von Tethys gelesen und verstanden zu haben (<a
|
||||
href="/docs/HandbuchTethys.pdf"
|
||||
target="_blank"
|
||||
>siehe hier</a
|
||||
>)
|
||||
</li>
|
||||
<li>das Einverständnis aller Co-Autoren über die bevorstehende Datenpublikation schriftlich eingeholt zu haben</li>
|
||||
<li>sowohl mit der Data Policy als auch mit den Terms & Conditions einverstanden zu sein</li>
|
||||
</ul>
|
||||
</CardBoxModal>
|
||||
|
||||
<LayoutAuthenticated>
|
||||
<Head title="Submit Dataset" />
|
||||
<SectionMain>
|
||||
<SectionTitleLineWithButton :icon="mdiDatabasePlus" title="Submit dataset" main>
|
||||
<!-- <BaseButton :route-name="stardust.route('user.index')" :icon="mdiArrowLeftBoldOutline" label="Back"
|
||||
color="white" rounded-full small /> -->
|
||||
</SectionTitleLineWithButton>
|
||||
|
||||
<CardBox>
|
||||
<div class="mx-4 p-4">
|
||||
<div class="flex items-center">
|
||||
<!-- <label>{{ form.titles[0].language }}</label>
|
||||
<label>{{ form.language }}</label> -->
|
||||
<icon-wizard :is-current="formStep == 1" :is-checked="formStep > 1" :label="'Language'">
|
||||
<icon-language></icon-language>
|
||||
</icon-wizard>
|
||||
|
||||
<icon-wizard :is-current="formStep == 2" :is-checked="formStep > 2" :label="'Mandatory'">
|
||||
<icon-mandatory></icon-mandatory>
|
||||
</icon-wizard>
|
||||
|
||||
<icon-wizard :is-current="formStep == 3" :is-checked="formStep > 3" :label="'Recommendet'">
|
||||
<icon-recommendet></icon-recommendet>
|
||||
</icon-wizard>
|
||||
|
||||
<icon-wizard :is-current="formStep == 4" :is-checked="false" :label="'Confirm'" :is-last-step="true">
|
||||
<icon-confirm></icon-confirm>
|
||||
</icon-wizard>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- mt-8: margin-top: 2rem; /* 32px */ 4 p-4: spacing 1rem 16px-->
|
||||
<div class="mt-8 p-4">
|
||||
<div v-if="formStep == 1">
|
||||
<div class="flex flex-col md:flex-row">
|
||||
<FormField
|
||||
label="Language *"
|
||||
help="required: select dataset main language"
|
||||
:class="{ 'text-red-400': errors.language }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl
|
||||
required
|
||||
v-model="form.language"
|
||||
:type="'select'"
|
||||
placeholder="[Enter Language]"
|
||||
:errors="form.errors.language"
|
||||
:options="['de', 'en']"
|
||||
>
|
||||
<div class="text-red-400 text-sm" v-if="form.errors.language">
|
||||
{{ form.errors.language.join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
</div>
|
||||
|
||||
<FormField
|
||||
label="Licenses"
|
||||
wrap-body
|
||||
:class="{ 'text-red-400': form.errors.licenses }"
|
||||
class="mt-8 w-full mx-2 flex-1"
|
||||
>
|
||||
<FormCheckRadioGroup v-model="form.licenses" name="roles" is-column :options="props.licenses" />
|
||||
</FormField>
|
||||
|
||||
<!-- <label for="rights">
|
||||
<input class="form-checkbox" name="rights" id="rights" type="checkbox" v-model="dataset.rights" />
|
||||
terms and conditions
|
||||
</label> -->
|
||||
<FormField
|
||||
label="Rights"
|
||||
help="You must agree to continue"
|
||||
wrap-body
|
||||
:class="{ 'text-red-400': form.errors.rights }"
|
||||
class="mt-8 w-full mx-2 flex-1 flex-col"
|
||||
>
|
||||
<label for="rights" class="checkbox mr-6 mb-3 last:mr-0">
|
||||
<input type="checkbox" id="rights" required v-model="form.rights" />
|
||||
<span class="check" />
|
||||
<a class="pl-2" target="_blank">terms and conditions </a>
|
||||
<!-- <BaseButton color="modern" :icon="mdiInformationOutline" small @click="isModalActive = true" /> -->
|
||||
<BaseIcon
|
||||
v-if="mdiInformationOutline"
|
||||
:path="mdiInformationOutline"
|
||||
@click.prevent="isModalActive = true"
|
||||
/>
|
||||
</label>
|
||||
</FormField>
|
||||
<div class="text-red-400 text-sm" v-if="errors.rights && Array.isArray(errors.rights)">
|
||||
<!-- {{ errors.password_confirmation }} -->
|
||||
{{ errors.rights.join(', ') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="formStep == 2">
|
||||
<!-- <CardBox title="Performance" :icon="mdiFinance" :header-icon="mdiReload" class="mb-6"> -->
|
||||
<div class="flex flex-col md:flex-row">
|
||||
<FormField
|
||||
label="Dataset Type *"
|
||||
help="required: dataset type"
|
||||
:class="{ 'text-red-400': form.errors.type }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl
|
||||
required
|
||||
v-model="form.type"
|
||||
:type="'select'"
|
||||
placeholder="-- select type --"
|
||||
:errors="errors.type"
|
||||
:options="doctypes"
|
||||
>
|
||||
<div class="text-red-400 text-sm" v-if="form.errors.type && Array.isArray(form.errors.type)">
|
||||
{{ form.errors.type.join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
<!-- <div class="w-full mx-2 flex-1 svelte-1l8159u"></div> -->
|
||||
<!-- Creating Corporation -->
|
||||
<FormField
|
||||
label="Creating Corporation *"
|
||||
:class="{ 'text-red-400': form.errors.creating_corporation }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl
|
||||
required
|
||||
v-model="form.creating_corporation"
|
||||
type="text"
|
||||
placeholder="[enter creating corporation]"
|
||||
:is-read-only="true"
|
||||
>
|
||||
<div
|
||||
class="text-red-400 text-sm"
|
||||
v-if="form.errors.creating_corporation && Array.isArray(form.errors.creating_corporation)"
|
||||
>
|
||||
{{ form.errors.creating_corporation.join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
</div>
|
||||
<!-- <BaseDivider /> -->
|
||||
|
||||
<!-- titles -->
|
||||
<CardBox
|
||||
class="mb-6"
|
||||
:has-form-data="true"
|
||||
title="Titles"
|
||||
:icon="mdiFinance"
|
||||
:header-icon="mdiPlusCircle"
|
||||
v-on:header-icon-click="addTitle()"
|
||||
>
|
||||
<!-- <div class="py-6 border-t border-gray-100 dark:border-slate-800"> -->
|
||||
<div class="flex flex-col md:flex-row">
|
||||
<FormField
|
||||
label="Main Title *"
|
||||
help="required: main title"
|
||||
:class="{ 'text-red-400': form.errors['titles.0.value'] }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl required v-model="form.titles[0].value" type="text" placeholder="[enter main title]">
|
||||
<div
|
||||
class="text-red-400 text-sm"
|
||||
v-if="form.errors['titles.0.value'] && Array.isArray(form.errors['titles.0.value'])"
|
||||
>
|
||||
{{ form.errors['titles.0.value'].join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
<FormField
|
||||
label="Main Title Language*"
|
||||
help="required: main title language"
|
||||
:class="{ 'text-red-400': form.errors['titles.0.language'] }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl required v-model="form.titles[0].language" type="text" :is-read-only="true">
|
||||
<div
|
||||
class="text-red-400 text-sm"
|
||||
v-if="form.errors['titles.0.language'] && Array.isArray(form.errors['titles.0.language'])"
|
||||
>
|
||||
{{ form.errors['titles.0.language'].join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
</div>
|
||||
<label v-if="form.titles.length > 1">additional titles </label>
|
||||
<!-- <BaseButton :icon="mdiPlusCircle" @click.prevent="addTitle()" color="modern" rounded-full small /> -->
|
||||
<div v-if="form.titles.length > 1">
|
||||
<div v-for="(item, index) in form.titles">
|
||||
<div class="flex flex-col md:flex-row" v-if="item.type != 'Main'">
|
||||
<FormField v-if="item.type != 'Main'" label="Remove">
|
||||
<BaseButton
|
||||
:icon="mdiMinusCircle"
|
||||
class="mt-1"
|
||||
@click.prevent="removeTitle(index)"
|
||||
color="modern"
|
||||
small
|
||||
/>
|
||||
</FormField>
|
||||
<FormField
|
||||
label="Title Value *"
|
||||
:class="{ 'text-red-400': form.errors[`titles.${index}.value`] }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl
|
||||
required
|
||||
v-model="form.titles[index].value"
|
||||
type="text"
|
||||
placeholder="[enter main title]"
|
||||
>
|
||||
<div class="text-red-400 text-sm" v-if="form.errors[`titles.${index}.value`]">
|
||||
{{ form.errors[`titles.${index}.value`].join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
<FormField
|
||||
label="Title Type*"
|
||||
:class="{ 'text-red-400': form.errors[`titles.${index}.type`] }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl
|
||||
required
|
||||
v-model="form.titles[index].type"
|
||||
type="select"
|
||||
:options="titletypes"
|
||||
placeholder="[select title type]"
|
||||
>
|
||||
<div class="text-red-400 text-sm" v-if="Array.isArray(form.errors[`titles.${index}.type`])">
|
||||
{{ form.errors[`titles.${index}.type`].join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
<FormField
|
||||
label="Title Language*"
|
||||
:class="{ 'text-red-400': form.errors[`titles.${index}.language`] }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl
|
||||
required
|
||||
v-model="form.titles[index].language"
|
||||
type="select"
|
||||
:options="['de', 'en']"
|
||||
placeholder="[select title language]"
|
||||
>
|
||||
<div class="text-red-400 text-sm" v-if="form.errors[`titles.${index}.language`]">
|
||||
{{ form.errors[`titles.${index}.language`].join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- </div> -->
|
||||
</CardBox>
|
||||
|
||||
<!-- Descriptions -->
|
||||
<CardBox
|
||||
class="mb-6"
|
||||
:has-form-data="true"
|
||||
title="Descriptions"
|
||||
:header-icon="mdiPlusCircle"
|
||||
v-on:header-icon-click="addDescription()"
|
||||
>
|
||||
<div class="flex flex-col md:flex-row">
|
||||
<FormField
|
||||
label="Main Abstract *"
|
||||
help="required: main abstract"
|
||||
:class="{ 'text-red-400': form.errors['descriptions.0.value'] }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl
|
||||
required
|
||||
v-model="form.descriptions[0].value"
|
||||
type="textarea"
|
||||
placeholder="[enter main abstract]"
|
||||
>
|
||||
<div
|
||||
class="text-red-400 text-sm"
|
||||
v-if="form.errors['descriptions.0.value'] && Array.isArray(form.errors['descriptions.0.value'])"
|
||||
>
|
||||
{{ form.errors['descriptions.0.value'].join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
<FormField
|
||||
label="Main Title Language*"
|
||||
help="required: main abstract language"
|
||||
:class="{ 'text-red-400': form.errors['descriptions.0.language'] }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl required v-model="form.descriptions[0].language" type="text" :is-read-only="true">
|
||||
<div
|
||||
class="text-red-400 text-sm"
|
||||
v-if="
|
||||
form.errors['descriptions.0.value'] && Array.isArray(form.errors['descriptions.0.language'])
|
||||
"
|
||||
>
|
||||
{{ form.errors['descriptions.0.language'].join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
</div>
|
||||
<label v-if="form.descriptions.length > 1">additional descriptions: </label>
|
||||
<!-- <BaseButton :icon="mdiPlusCircle" @click.prevent="addTitle()" color="modern" rounded-full small /> -->
|
||||
<div v-if="form.descriptions.length > 1">
|
||||
<div v-for="(item, index) in form.descriptions">
|
||||
<div class="flex flex-col md:flex-row" v-if="item.type != 'Abstract'">
|
||||
<FormField v-if="item.type != 'Abstract'" label="Remove">
|
||||
<BaseButton
|
||||
:icon="mdiMinusCircle"
|
||||
class="mt-1"
|
||||
@click.prevent="removeDescription(index)"
|
||||
color="modern"
|
||||
small
|
||||
/>
|
||||
</FormField>
|
||||
<FormField
|
||||
label="Description Value *"
|
||||
:class="{ 'text-red-400': form.errors[`descriptions.${index}.value`] }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl
|
||||
required
|
||||
v-model="form.descriptions[index].value"
|
||||
type="text"
|
||||
placeholder="[enter additional description]"
|
||||
>
|
||||
<div
|
||||
class="text-red-400 text-sm"
|
||||
v-if="
|
||||
form.errors[`descriptions.${index}.value`] &&
|
||||
Array.isArray(form.errors[`descriptions.${index}.value`])
|
||||
"
|
||||
>
|
||||
{{ form.errors[`descriptions.${index}.value`].join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
<FormField
|
||||
label="Description Type *"
|
||||
:class="{ 'text-red-400': form.errors[`descriptions.${index}.type`] }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl
|
||||
required
|
||||
v-model="form.descriptions[index].type"
|
||||
type="select"
|
||||
:options="descriptiontypes"
|
||||
placeholder="[select description type]"
|
||||
>
|
||||
<div
|
||||
class="text-red-400 text-sm"
|
||||
v-if="
|
||||
form.errors[`descriptions.${index}.type`] &&
|
||||
Array.isArray(form.errors[`descriptions.${index}.type`])
|
||||
"
|
||||
>
|
||||
{{ form.errors[`descriptions.${index}.type`].join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
<FormField
|
||||
label="Description Language*"
|
||||
:class="{ 'text-red-400': form.errors[`titdescriptionsles.${index}.language`] }"
|
||||
class="w-full mx-2 flex-1"
|
||||
>
|
||||
<FormControl
|
||||
required
|
||||
v-model="form.descriptions[index].language"
|
||||
type="select"
|
||||
:options="['de', 'en']"
|
||||
placeholder="[select title language]"
|
||||
>
|
||||
<div
|
||||
class="text-red-400 text-sm"
|
||||
v-if="form.errors && Array.isArray(form.errors[`descriptions.${index}.language`])"
|
||||
>
|
||||
{{ form.errors[`descriptions.${index}.language`].join(', ') }}
|
||||
</div>
|
||||
</FormControl>
|
||||
</FormField>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardBox>
|
||||
|
||||
<CardBox class="mb-6" :has-form-data="true" title="Authors" :icon="mdiBookOpenPageVariant" >
|
||||
<SearchAutocomplete
|
||||
source="/api/persons"
|
||||
:response-property="'first_name'"
|
||||
placeholder="search in person table...."
|
||||
></SearchAutocomplete>
|
||||
</CardBox>
|
||||
<!-- <SectionTitleLineWithButton :icon="mdiChartPie" title="Trends overview (to do publications per year)" class="flex flex-col md:flex-row" >
|
||||
</SectionTitleLineWithButton> -->
|
||||
</div>
|
||||
|
||||
<div v-if="formStep == 3">
|
||||
<label>To Do: Recommendet</label>
|
||||
<!-- <div class="w-full mx-2 flex-1 svelte-1l8159u">
|
||||
<div class="font-bold h-6 mt-3 text-gray-600 text-xs leading-8 uppercase">Username</div>
|
||||
<div class="bg-white my-2 p-1 flex border border-gray-200 rounded svelte-1l8159u">
|
||||
<input placeholder="Just a hint.." class="p-1 px-2 appearance-none outline-none w-full text-gray-800" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full mx-2 flex-1 svelte-1l8159u">
|
||||
<div class="font-bold h-6 mt-3 text-gray-600 text-xs leading-8 uppercase">Your Email</div>
|
||||
<div class="bg-white my-2 p-1 flex border border-gray-200 rounded svelte-1l8159u">
|
||||
<input placeholder="jhon@doe.com" class="p-1 px-2 appearance-none outline-none w-full text-gray-800" />
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
|
||||
<div v-if="formStep == 4">
|
||||
<label>To Do: File Upload</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex p-2 mt-4">
|
||||
<button
|
||||
v-if="formStep > 1"
|
||||
@click="prevStep"
|
||||
class="text-base hover:scale-110 focus:outline-none flex justify-center px-4 py-2 rounded font-bold cursor-pointer hover:bg-gray-200 bg-gray-100 text-gray-700 border duration-200 ease-in-out border-gray-600 transition"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
|
||||
<div class="flex-auto flex flex-row-reverse">
|
||||
<button
|
||||
v-if="formStep < 4"
|
||||
@click="nextStep"
|
||||
class="text-base ml-2 hover:scale-110 focus:outline-none flex justify-center px-4 py-2 rounded font-bold cursor-pointer hover:bg-teal-600 bg-teal-600 text-teal-100 border duration-200 ease-in-out border-teal-600 transition"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
|
||||
<!-- <button
|
||||
class="text-base hover:scale-110 focus:outline-none flex justify-center px-4 py-2 rounded font-bold cursor-pointer hover:bg-teal-200 bg-teal-100 text-teal-700 border duration-200 ease-in-out border-teal-600 transition"
|
||||
>
|
||||
Skip
|
||||
</button> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</CardBox>
|
||||
</SectionMain>
|
||||
</LayoutAuthenticated>
|
||||
</template>
|
|
@ -1,62 +0,0 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import axios from 'axios';
|
||||
|
||||
export const MainService = defineStore('main', {
|
||||
state: () => ({
|
||||
/* User */
|
||||
userName: '',
|
||||
userEmail: null,
|
||||
userAvatar: null,
|
||||
|
||||
/* Field focus with ctrl+k (to register only once) */
|
||||
isFieldFocusRegistered: false,
|
||||
|
||||
/* Sample data for starting dashboard(commonly used) */
|
||||
clients: [],
|
||||
history: [],
|
||||
authors: [],
|
||||
datasets: []
|
||||
}),
|
||||
actions: {
|
||||
// payload = authenticated user
|
||||
setUser(payload) {
|
||||
if (payload.name) {
|
||||
this.userName = payload.name;
|
||||
}
|
||||
if (payload.email) {
|
||||
this.userEmail = payload.email;
|
||||
}
|
||||
if (payload.avatar) {
|
||||
this.userAvatar = payload.avatar;
|
||||
}
|
||||
},
|
||||
|
||||
fetch(sampleDataKey) {
|
||||
// sampleDataKey= clients or history
|
||||
axios
|
||||
.get(`data-sources/${sampleDataKey}.json`)
|
||||
.then((r) => {
|
||||
if (r.data && r.data.data) {
|
||||
this[sampleDataKey] = r.data.data;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
alert(error.message);
|
||||
});
|
||||
},
|
||||
|
||||
fetchApi(sampleDataKey) {
|
||||
// sampleDataKey= clients or history
|
||||
axios
|
||||
.get(`api/${sampleDataKey}`)
|
||||
.then((r) => {
|
||||
if (r.data) {
|
||||
this[sampleDataKey] = r.data;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
alert(error.message);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
79
resources/js/Stores/main.ts
Normal file
79
resources/js/Stores/main.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import axios from 'axios';
|
||||
|
||||
interface Person {
|
||||
id: number;
|
||||
name: string;
|
||||
email: string;
|
||||
datasetCount: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
interface TransactionItem {
|
||||
amount: number;
|
||||
account: string;
|
||||
name: string;
|
||||
date: string;
|
||||
type: string;
|
||||
business: string;
|
||||
}
|
||||
|
||||
export const MainService = defineStore('main', {
|
||||
state: () => ({
|
||||
/* User */
|
||||
userName: '',
|
||||
userEmail: null,
|
||||
userAvatar: null,
|
||||
|
||||
/* Field focus with ctrl+k (to register only once) */
|
||||
isFieldFocusRegistered: false,
|
||||
|
||||
/* Sample data for starting dashboard(commonly used) */
|
||||
clients: [],
|
||||
history: [] as Array<TransactionItem>,
|
||||
authors: [] as Array<Person>,
|
||||
datasets: [],
|
||||
}),
|
||||
actions: {
|
||||
// payload = authenticated user
|
||||
setUser(payload) {
|
||||
if (payload.name) {
|
||||
this.userName = payload.name;
|
||||
}
|
||||
if (payload.email) {
|
||||
this.userEmail = payload.email;
|
||||
}
|
||||
if (payload.avatar) {
|
||||
this.userAvatar = payload.avatar;
|
||||
}
|
||||
},
|
||||
|
||||
fetch(sampleDataKey) {
|
||||
// sampleDataKey= clients or history
|
||||
axios
|
||||
.get(`data-sources/${sampleDataKey}.json`)
|
||||
.then((r) => {
|
||||
if (r.data && r.data.data) {
|
||||
this[sampleDataKey] = r.data.data;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
alert(error.message);
|
||||
});
|
||||
},
|
||||
|
||||
fetchApi(sampleDataKey) {
|
||||
// sampleDataKey= authors or datasets
|
||||
axios
|
||||
.get(`api/${sampleDataKey}`)
|
||||
.then((r) => {
|
||||
if (r.data) {
|
||||
this[sampleDataKey] = r.data;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
alert(error.message);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
|
@ -3,11 +3,11 @@ import { createApp, h } from 'vue';
|
|||
import { Inertia } from '@inertiajs/inertia';
|
||||
|
||||
import { createInertiaApp, Link, usePage } from '@inertiajs/vue3';
|
||||
import DefaultLayout from '@/Layouts/Default.vue';
|
||||
// import DefaultLayout from '@/Layouts/Default.vue';
|
||||
|
||||
import { createPinia } from 'pinia';
|
||||
import { StyleService } from '@/Stores/style.js';
|
||||
import { LayoutService } from '@/Stores/layout.js';
|
||||
import { StyleService } from '@/Stores/style';
|
||||
import { LayoutService } from '@/Stores/layout';
|
||||
import { MainService } from '@/Stores/main';
|
||||
import { darkModeKey, styleKey } from '@/config';
|
||||
const pinia = createPinia();
|
||||
|
@ -15,41 +15,36 @@ const pinia = createPinia();
|
|||
import { initRoutes } from '@eidellev/adonis-stardust/client';
|
||||
initRoutes();
|
||||
|
||||
// import { defineProps } from 'vue';
|
||||
|
||||
// const props = defineProps({
|
||||
// user: {
|
||||
// type: Object,
|
||||
// default: () => ({}),
|
||||
// },
|
||||
// });
|
||||
// import '@fontsource/archivo-black/index.css';
|
||||
// import '@fontsource/inter/index.css';
|
||||
|
||||
createInertiaApp({
|
||||
progress: {
|
||||
color: '#4B5563',
|
||||
},
|
||||
// resolve: (name) => {
|
||||
// const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
|
||||
// return pages[`./Pages/${name}.vue`]
|
||||
// },
|
||||
// Webpack
|
||||
// resolve: (name) => require(`./Pages/${name}`),
|
||||
// resolve: (name) => require(`./Pages/${name}.vue`),
|
||||
// add default layout
|
||||
resolve: (name) => {
|
||||
const page = require(`./Pages/${name}.vue`).default;
|
||||
// if (!page.layout) {
|
||||
// page.layout = DefaultLayout;
|
||||
// }
|
||||
return page;
|
||||
},
|
||||
setup({ el, App, props, plugin }) {
|
||||
createApp({ render: () => h(App, props) })
|
||||
.use(plugin)
|
||||
.use(pinia)
|
||||
// .component('inertia-link', Link)
|
||||
.mount(el);
|
||||
},
|
||||
progress: {
|
||||
// color: '#4B5563',
|
||||
color: '#22C55E',
|
||||
},
|
||||
// resolve: (name) => {
|
||||
// const pages = import.meta.glob('./Pages/**/*.vue', { eager: true })
|
||||
// return pages[`./Pages/${name}.vue`]
|
||||
// },
|
||||
// Webpack
|
||||
// resolve: (name) => require(`./Pages/${name}`),
|
||||
// resolve: (name) => require(`./Pages/${name}.vue`),
|
||||
// add default layout
|
||||
resolve: (name) => {
|
||||
const page = require(`./Pages/${name}.vue`).default;
|
||||
// if (!page.layout) {
|
||||
// page.layout = DefaultLayout;
|
||||
// }
|
||||
return page;
|
||||
},
|
||||
setup({ el, App, props, plugin }) {
|
||||
createApp({ render: () => h(App, props) })
|
||||
.use(plugin)
|
||||
.use(pinia)
|
||||
// .component('inertia-link', Link)
|
||||
.mount(el);
|
||||
},
|
||||
});
|
||||
|
||||
const styleService = StyleService(pinia);
|
||||
|
@ -62,14 +57,14 @@ styleService.setStyle(localStorage[styleKey] ?? 'basic');
|
|||
|
||||
/* Dark mode */
|
||||
if (
|
||||
(!localStorage[darkModeKey] && window.matchMedia('(prefers-color-scheme: dark)').matches) ||
|
||||
localStorage[darkModeKey] === '1'
|
||||
(!localStorage[darkModeKey] && window.matchMedia('(prefers-color-scheme: dark)').matches) ||
|
||||
localStorage[darkModeKey] === '1'
|
||||
) {
|
||||
styleService.setDarkMode(true);
|
||||
styleService.setDarkMode(true);
|
||||
}
|
||||
|
||||
/* Collapse mobile aside menu on route change */
|
||||
Inertia.on('navigate', (event) => {
|
||||
layoutService.isAsideMobileExpanded = false;
|
||||
layoutService.isAsideLgActive = false;
|
||||
layoutService.isAsideMobileExpanded = false;
|
||||
layoutService.isAsideLgActive = false;
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ export const colorsText = {
|
|||
danger: 'text-red-500',
|
||||
warning: 'text-yellow-500',
|
||||
info: 'text-blue-500',
|
||||
modern: 'text-teal-500',
|
||||
};
|
||||
|
||||
export const colorsOutline = {
|
||||
|
@ -44,6 +45,7 @@ export const getButtonColor = (color, isOutlined, hasHover) => {
|
|||
danger: 'bg-red-600 dark:bg-red-500 text-white',
|
||||
warning: 'bg-yellow-600 dark:bg-yellow-500 text-white',
|
||||
info: 'bg-blue-600 dark:bg-blue-500 text-white',
|
||||
modern: 'bg-teal-600 dark:bg-teal-500 text-white',
|
||||
},
|
||||
bgHover: {
|
||||
white: 'hover:bg-gray-50',
|
||||
|
@ -56,6 +58,7 @@ export const getButtonColor = (color, isOutlined, hasHover) => {
|
|||
warning:
|
||||
'hover:bg-yellow-700 hover:border-yellow-700 hover:dark:bg-yellow-600 hover:dark:border-yellow-600',
|
||||
info: 'hover:bg-blue-700 hover:border-blue-700 hover:dark:bg-blue-600 hover:dark:border-blue-600',
|
||||
modern: 'hover:bg-emerald-700 hover:border-emerald-700 hover:dark:bg-emerald-600 hover:dark:border-emerald-600',
|
||||
},
|
||||
borders: {
|
||||
white: 'border-gray-100',
|
||||
|
@ -65,6 +68,7 @@ export const getButtonColor = (color, isOutlined, hasHover) => {
|
|||
danger: 'border-red-600 dark:border-red-500',
|
||||
warning: 'border-yellow-600 dark:border-yellow-500',
|
||||
info: 'border-blue-600 dark:border-blue-500',
|
||||
modern: 'border-teal-600 dark:border-teal-500',
|
||||
},
|
||||
text: {
|
||||
white: 'text-black dark:text-slate-100',
|
||||
|
@ -74,12 +78,13 @@ export const getButtonColor = (color, isOutlined, hasHover) => {
|
|||
danger: 'text-red-600 dark:text-red-500',
|
||||
warning: 'text-yellow-600 dark:text-yellow-500',
|
||||
info: 'text-blue-600 dark:text-blue-500',
|
||||
modern: 'text-teal-600 dark:text-teal-500',
|
||||
},
|
||||
outlineHover: {
|
||||
white: 'hover:bg-gray-100 hover:text-gray-900 dark:hover:text-slate-900',
|
||||
contrast:
|
||||
'hover:bg-gray-800 hover:text-gray-100 hover:dark:bg-slate-100 hover:dark:text-black',
|
||||
light: 'hover:bg-gray-100 hover:text-gray-900 dark:hover:text-slate-900',
|
||||
light: 'hover:bg-gray-100 hover:text-gray-900 dark:hover:text-slate-900',
|
||||
success:
|
||||
'hover:bg-emerald-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-emerald-600',
|
||||
danger:
|
||||
|
@ -87,6 +92,7 @@ export const getButtonColor = (color, isOutlined, hasHover) => {
|
|||
warning:
|
||||
'hover:bg-yellow-600 hover:text-white hover:text-white hover:dark:text-white hover:dark:border-yellow-600',
|
||||
info: 'hover:bg-blue-600 hover:text-white hover:dark:text-white hover:dark:border-blue-600',
|
||||
modern: 'hover:bg-teal-600 hover:text-teal hover:dark:bg-teal-100 hover:dark:text-black',
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
import {
|
||||
mdiAccountCircle,
|
||||
mdiMonitor,
|
||||
mdiGithub,
|
||||
mdiAccountKey,
|
||||
mdiAccountEye,
|
||||
mdiAccountGroup,
|
||||
mdiPalette,
|
||||
} from '@mdi/js'
|
||||
|
||||
export default [
|
||||
{
|
||||
route: 'dashboard',
|
||||
icon: mdiMonitor,
|
||||
label: 'Dashboard'
|
||||
},
|
||||
// {
|
||||
// route: 'permission.index',
|
||||
// icon: mdiAccountKey,
|
||||
// label: 'Permissions'
|
||||
// },
|
||||
// {
|
||||
// route: 'role.index',
|
||||
// icon: mdiAccountEye,
|
||||
// label: 'Roles'
|
||||
// },
|
||||
{
|
||||
route: 'user.index',
|
||||
icon: mdiAccountGroup,
|
||||
label: 'Users'
|
||||
},
|
||||
{
|
||||
route: 'role.index',
|
||||
icon: mdiAccountEye,
|
||||
label: 'Roles'
|
||||
},
|
||||
{
|
||||
href: 'https://gitea.geologie.ac.at/geolba/tethys',
|
||||
icon: mdiGithub,
|
||||
label: 'Gitea',
|
||||
target: '_blank'
|
||||
}
|
||||
]
|
46
resources/js/menu.ts
Normal file
46
resources/js/menu.ts
Normal file
|
@ -0,0 +1,46 @@
|
|||
import {
|
||||
mdiMonitor,
|
||||
mdiGithub,
|
||||
mdiAccountEye,
|
||||
mdiAccountGroup,
|
||||
mdiDatabasePlus,
|
||||
} from '@mdi/js';
|
||||
|
||||
export default [
|
||||
{
|
||||
route: 'dashboard',
|
||||
icon: mdiMonitor,
|
||||
label: 'Dashboard',
|
||||
},
|
||||
// {
|
||||
// route: 'permission.index',
|
||||
// icon: mdiAccountKey,
|
||||
// label: 'Permissions'
|
||||
// },
|
||||
// {
|
||||
// route: 'role.index',
|
||||
// icon: mdiAccountEye,
|
||||
// label: 'Roles'
|
||||
// },
|
||||
{
|
||||
route: 'user.index',
|
||||
icon: mdiAccountGroup,
|
||||
label: 'Users',
|
||||
},
|
||||
{
|
||||
route: 'role.index',
|
||||
icon: mdiAccountEye,
|
||||
label: 'Roles',
|
||||
},
|
||||
{
|
||||
route: 'dataset.create',
|
||||
icon: mdiDatabasePlus,
|
||||
label: 'Create Dataset',
|
||||
},
|
||||
{
|
||||
href: 'https://gitea.geologie.ac.at/geolba/tethys',
|
||||
icon: mdiGithub,
|
||||
label: 'Gitea',
|
||||
target: '_blank',
|
||||
},
|
||||
];
|
10
server.ts
10
server.ts
|
@ -10,10 +10,10 @@
|
|||
|
|
||||
*/
|
||||
|
||||
import 'reflect-metadata'
|
||||
import sourceMapSupport from 'source-map-support'
|
||||
import { Ignitor } from '@adonisjs/core/build/standalone'
|
||||
import 'reflect-metadata';
|
||||
import sourceMapSupport from 'source-map-support';
|
||||
import { Ignitor } from '@adonisjs/core/build/standalone';
|
||||
|
||||
sourceMapSupport.install({ handleUncaughtExceptions: false })
|
||||
sourceMapSupport.install({ handleUncaughtExceptions: false });
|
||||
|
||||
new Ignitor(__dirname).httpServer().start()
|
||||
new Ignitor(__dirname).httpServer().start();
|
||||
|
|
|
@ -123,3 +123,23 @@ Route.post('/edit-account-info/store/:id', 'UsersController.accountInfoStore')
|
|||
.namespace('App/Controllers/Http/Admin')
|
||||
.middleware(['auth']);
|
||||
// Route::post('change-password', 'UserController@changePasswordStore')->name('admin.account.password.store');
|
||||
|
||||
Route.group(() => {
|
||||
// Route.get('/user', 'UsersController.index').as('user.index');
|
||||
Route.get('/dataset/create', 'DatasetController.create').as('dataset.create').middleware(['auth', 'can:dataset-submit']);
|
||||
Route.post('/dataset/first/first-step', 'DatasetController.firstStep')
|
||||
.as('dataset.first.step')
|
||||
.middleware(['auth', 'can:dataset-submit']);
|
||||
Route.post('/dataset/second/second-step', 'DatasetController.secondStep')
|
||||
.as('dataset.second.step')
|
||||
.middleware(['auth', 'can:dataset-submit']);
|
||||
// Route.get('/user/:id', 'UsersController.show').as('user.show').where('id', Route.matchers.number());
|
||||
// Route.get('/user/:id/edit', 'UsersController.edit').as('user.edit').where('id', Route.matchers.number());
|
||||
// Route.put('/user/:id/update', 'UsersController.update').as('user.update').where('id', Route.matchers.number());
|
||||
// Route.delete('/user/:id', 'UsersController.destroy').as('user.destroy').where('id', Route.matchers.number());
|
||||
// Route.resource('user', 'DatasetController');
|
||||
})
|
||||
.namespace('App/Controllers/Http/Submitter')
|
||||
.prefix('submitter');
|
||||
// .middleware(['auth', 'can:dataset-list,dataset-publish']);
|
||||
// .middleware(['auth', 'is:submitter']);
|
||||
|
|
|
@ -8,6 +8,7 @@ Route.group(() => {
|
|||
Route.group(() => {
|
||||
Route.get('authors', 'AuthorsController.index').as('author.index');
|
||||
Route.get('datasets', 'DatasetController.index').as('dataset.index');
|
||||
Route.get('persons', 'AuthorsController.persons').as('author.persons');
|
||||
// Route.get("author/:id", "TodosController.show");
|
||||
// Route.put("author/update", "TodosController.update");
|
||||
// Route.post("author", "TodosController.store");
|
||||
|
|
|
@ -1,77 +1,86 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
const plugin = require("tailwindcss/plugin");
|
||||
const plugin = require('tailwindcss/plugin');
|
||||
const defaultTheme = require('tailwindcss/defaultTheme');
|
||||
|
||||
module.exports = {
|
||||
content: ['./resources/**/*.{edge,js,ts,jsx,tsx,vue}'],
|
||||
darkMode: 'class', // or 'media' or 'class'
|
||||
theme: {
|
||||
asideScrollbars: {
|
||||
light: 'light',
|
||||
gray: 'gray',
|
||||
},
|
||||
extend: {
|
||||
zIndex: {
|
||||
'-1': '-1',
|
||||
},
|
||||
flexGrow: {
|
||||
5: '5',
|
||||
},
|
||||
maxHeight: {
|
||||
'screen-menu': 'calc(100vh - 3.5rem)',
|
||||
'modal': 'calc(100vh - 160px)',
|
||||
},
|
||||
transitionProperty: {
|
||||
position: 'right, left, top, bottom, margin, padding',
|
||||
textColor: 'color',
|
||||
},
|
||||
keyframes: {
|
||||
'fade-out': {
|
||||
from: { opacity: 1 },
|
||||
to: { opacity: 0 },
|
||||
},
|
||||
'fade-in': {
|
||||
from: { opacity: 0 },
|
||||
to: { opacity: 1 },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
'fade-out': 'fade-out 250ms ease-in-out',
|
||||
'fade-in': 'fade-in 250ms ease-in-out',
|
||||
},
|
||||
}, //extend
|
||||
}, // theme
|
||||
plugins: [
|
||||
require("@tailwindcss/forms"),
|
||||
plugin(function ({ matchUtilities, theme }) {
|
||||
matchUtilities(
|
||||
{
|
||||
"aside-scrollbars": (value) => {
|
||||
const track = value === "light" ? "100" : "900";
|
||||
const thumb = value === "light" ? "300" : "600";
|
||||
const color = value === "light" ? "gray" : value;
|
||||
|
||||
return {
|
||||
scrollbarWidth: "thin",
|
||||
scrollbarColor: `${theme(`colors.${color}.${thumb}`)} ${theme(
|
||||
`colors.${color}.${track}`
|
||||
)}`,
|
||||
"&::-webkit-scrollbar": {
|
||||
width: "8px",
|
||||
height: "8px",
|
||||
},
|
||||
"&::-webkit-scrollbar-track": {
|
||||
backgroundColor: theme(`colors.${color}.${track}`),
|
||||
},
|
||||
"&::-webkit-scrollbar-thumb": {
|
||||
borderRadius: "0.25rem",
|
||||
backgroundColor: theme(`colors.${color}.${thumb}`),
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{ values: theme("asideScrollbars") }
|
||||
);
|
||||
}),
|
||||
require("@tailwindcss/line-clamp"),
|
||||
],
|
||||
content: ['./resources/**/*.{edge,js,ts,jsx,tsx,vue}'],
|
||||
darkMode: 'class', // or 'media' or 'class'
|
||||
theme: {
|
||||
asideScrollbars: {
|
||||
light: 'light',
|
||||
gray: 'gray',
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
'primary': '#22C55E',
|
||||
'primary-dark': '#DCFCE7',
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ['Inter', ...defaultTheme.fontFamily.sans],
|
||||
logo: ['Archivo Black', ...defaultTheme.fontFamily.sans],
|
||||
},
|
||||
zIndex: {
|
||||
'-1': '-1',
|
||||
},
|
||||
flexGrow: {
|
||||
5: '5',
|
||||
},
|
||||
maxHeight: {
|
||||
'screen-menu': 'calc(100vh - 3.5rem)',
|
||||
'modal': 'calc(100vh - 160px)',
|
||||
},
|
||||
transitionProperty: {
|
||||
position: 'right, left, top, bottom, margin, padding',
|
||||
textColor: 'color',
|
||||
},
|
||||
keyframes: {
|
||||
'fade-out': {
|
||||
from: { opacity: 1 },
|
||||
to: { opacity: 0 },
|
||||
},
|
||||
'fade-in': {
|
||||
from: { opacity: 0 },
|
||||
to: { opacity: 1 },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
'fade-out': 'fade-out 250ms ease-in-out',
|
||||
'fade-in': 'fade-in 250ms ease-in-out',
|
||||
},
|
||||
}, //extend
|
||||
}, // theme
|
||||
plugins: [
|
||||
require('@tailwindcss/forms'),
|
||||
plugin(function ({ matchUtilities, theme }) {
|
||||
matchUtilities(
|
||||
{
|
||||
'aside-scrollbars': (value) => {
|
||||
const track = value === 'light' ? '100' : '900';
|
||||
const thumb = value === 'light' ? '300' : '600';
|
||||
const color = value === 'light' ? 'gray' : value;
|
||||
|
||||
return {
|
||||
'scrollbarWidth': 'thin',
|
||||
'scrollbarColor': `${theme(`colors.${color}.${thumb}`)} ${theme(
|
||||
`colors.${color}.${track}`,
|
||||
)}`,
|
||||
'&::-webkit-scrollbar': {
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
},
|
||||
'&::-webkit-scrollbar-track': {
|
||||
backgroundColor: theme(`colors.${color}.${track}`),
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
borderRadius: '0.25rem',
|
||||
backgroundColor: theme(`colors.${color}.${thumb}`),
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
{ values: theme('asideScrollbars') },
|
||||
);
|
||||
}),
|
||||
require('@tailwindcss/line-clamp'),
|
||||
],
|
||||
};
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
{
|
||||
"extends": "adonis-preset-ts/tsconfig.json",
|
||||
"include": [
|
||||
"**/*"
|
||||
// "**/*",
|
||||
"**/*",
|
||||
// "./resources/js/**/*"
|
||||
// "./resources/js/**/*.vue",
|
||||
// "./resources/js/**/*.ts",
|
||||
// "./resources/js/**/*.vue",
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
|
Loading…
Reference in New Issue
Block a user