DEV Community

Tobias Mesquita for Quasar Framework Brasil

Posted on

QPANC - Parte 10 - Quasar - Configurações e Customizações

QPANC são as iniciais de Quasar PostgreSQL ASP NET Core.

18 Customização de Temas e Modos (Dark e Light)

A customização do tema e do modo dark é feita de forma semelhante, porém a classe do tema deve ser definida pelo desenvolvedor, enquanto a classe do modo dark é injetada pelo framework, porém o recomendado é que ambas sejam inseridas no body.

Para ativar o modo dark, você deve alterar o quasar.config.js > framework > config > dark
Quasar.App/quasar.config.js

module.exports = function (ctx) { return { framework: { config: { dark: 'auto' } } } } 

abaixo segue um exemplo de customização para o modo dark.:
Quasar.App/src/css/app.sass

// app global css in Sass form body.body--dark color: $grey-1 --q-color-primary: #26a69a --q-color-secondary: #027BE3 --q-color-accent: #9C27B0 --q-color-positive: #21BA45 --q-color-negative: #C10015 --q-color-info: #31CCEC --q-color-warning: #F2C037 .text-main color: $grey-10 .text-content color: $grey-9 .text-content-2 color: $grey-8 .bg-main background: $grey-10 .bg-content background: $grey-9 .bg-content-2 background: $grey-8 body.body--light color: $grey-10 --q-color-primary: #027BE3 --q-color-secondary: #26A69A --q-color-accent: #9C27B0 --q-color-positive: #21BA45 --q-color-negative: #C10015 --q-color-info: #31CCEC --q-color-warning: #F2C037 .text-main color: white .text-content color: $grey-2 .text-content-2 color: $grey-4 .bg-main background: white .bg-content background: $grey-2 .bg-content-2 background: $grey-4 

No caso acima, criamos as cores personalizadas main, content e content-2 para os modos dark e light, assim como definimos as cores base (primary, secondary, accent, positive, negative, info, warning)

Note que as cores definidas para o modo dark, não foram bem selecionas, por tanto pode haver um problema de contraste no modo dark

caso haja a necessidade de implementar múltiplos temas ou esquemas de cores, você poderá definir classes base com a seguinte estrutura: body.${nome_tema}.body--dark e body.${nome_tema}.body--light, e um nível abaixo, definir as customizações.

19 Internacionalização - I18n

A internacionalização no Quasar é bem simples, basicamente são arquivos JSON, então cabe a você desenvolvedor definir como estes textos serão organizados.

Mas dado a estrutura deste projeto, não será possível a flexibilização quanto a estrutura dos textos usados nas validações, ou seja, os erros e os nomes dos rótulos dos campos, aqui chamados de fields.

Então, iremos criar dois arquivos dentro da pasta Quasar.App/src/i18n.
Quasar.App/src/i18n/en-us/index.js

export default { validations: { compare: '{field} and {other} do not match', email: 'The {field} field is not a valid e-mail address', required: 'The {field} field is required' }, fields: { confirmPassword: 'Confirm your Password', confirmUserName: 'Confirm your Email', firstName: 'First Name', lastName: 'Last Name', password: 'Password', userName: 'Email' } } 

Quasar.App/src/i18n/pt-br/index.js

export default { validations: { compare: '{field} e {other} não são iguais', email: 'O campo {field} não possui um email válido', required: 'O campo {field} é requerido' }, fields: { confirmPassword: 'Confirme à Senha', confirmUserName: 'Confirme o Email', firstName: 'Nome', lastName: 'Sobrenome', password: 'Senha', userName: 'Email' } } 

Apenas para ficar claro, os nomes entre {} são placeholders, por exemplo, {field} em The {field} field is required será substituído pelo nome do campo que está sendo validado.

Agora precisamos registrar estes textos localizados.

Quasar.App/src/i18n/index.js

import enUS from './en-us' import ptBR from './pt-br' export default { 'en-us': enUS, 'pt-br': ptBR } 

20 Validações

Iremos utilizar o sistema de validações que o Quasar oferece, porém iremos encapsular isto dentro de um serviço, para que posamos aplicar os textos localizados.

então, crie o seguinte serviço:

Quasar.App/src/services/validations.js

const validations = {} validations.required = ({ self, field }) => { return function required (val) { return !!val || self.$t('validations.required', { field: self.$t(`fields.${field}`) }) } } const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ validations.email = ({ self, field }) => { return function required (val) { return emailRegex.test(val) || self.$t('validations.email', { field: self.$t(`fields.${field}`) }) } } validations.server = ({ self, field }) => { return function server (val) { return self.validationArgs[field].server } } export default function validation (self, context) { const _validations = {} for (const field in context) { const _rules = [] const rules = context[field] const names = Object.keys(validations) for (const rule of names) { if (rules.includes(rule)) { _rules.push(validations[rule]({ self, field })) } } _validations[field] = _rules } _validations.resetServer = function reset () { for (const field in context) { if (field in self.validationArgs && 'server' in self.validationArgs[field]) { self.validationArgs[field].server = true } } } return _validations } 

no serviço acima, as linas que merecem atenção são:

function required (val) { return !!val || self.$t('validations.required', { field: self.$t(`fields.${field}`) }) } 
function email (val) { return emailRegex.test(val) || self.$t('validations.email', { field: self.$t(`fields.${field}`) }) } 

Em ambos os casos, temos uma função que retorna um boolean ou uma string, caso retorne true, é por que passou no teste, se retornar uma string, é por que o teste falhou, e a string é a mensagem de erro. o self.$t serve para recuperamos esta mensagem já localizada.

return function server (val) { return self.validationArgs[field].server } 

Já esta validação dependente de um dado proveniente do componente, neste caso, o retorno da API.

Desta forma, se quisemos validar o userName e o password, podemos montar as rules da seguinte forma.:

import validations from 'services/validations' export default { data () { const self = this const validation = validations(self, { userName: ['required', 'email', 'server'], password: ['required', 'server'] }) return { userName: '', password: '', validation, validationArgs: { userName: { server: true }, password: { server: true } } } } } 
<q-nput label="$t('fields.userName')" v-model="userName" :rules="validation.userName" @blur="validationArgs.userName.server = true" /> <q-nput label="$t('fields.password')" type="password" v-model="password" :rules="validation.password" @blur="validationArgs.password.server = true" /> 

Através do objeto validationArgs, conseguimos passar alguma informação complementar o serviço que constrói as validações, por exemplo, validationArgs.userName.server será utilizado pela validação server.

Lembrando que userName e password devem está presentes no arquivo de localização (i18n), assim como as regras required, email e server.

Assim como as regras utilizadas (no caso acima, required, email e server) devem está devidamente implementadas no serviço validations.

Nos próximos capítulos, nós veremos estas validações em ação.

E para fechamos estes assunto, precisamos criar um alias para a pasta services, o primeiro passo é adicionar o seguinte bloco de código no quasar.config.js > build > extendWebpack

QPANC.App/quasar.config.js

const path = require('path') module.exports = function (ctx) { return { build: { extendWebpack (cfg, { isServer, isClient }) { cfg.resolve.alias = { ...cfg.resolve.alias, services: path.resolve(__dirname, './src/services'), } } } } } 

e para permitir que o intellisense funcione no VSCode, precisamos adicionar o seguinte item jsconfig.json > compilerOptions > paths

QPANC.App/jsconfig.json

{ "compilerOptions": { "paths": { "services/*": [ "src/services/*" ] } } } 

20 Validações

Iremos utilizar o sistema de validações que o Quasar oferece, porém iremos encapsular isto dentro de um serviço, para que posamos aplicar os textos localizados.

então, crie o seguinte serviço:

Quasar.App/src/services/validations.js

const validations = {} validations.required = ({ self, field }) => { return function required (val) { return !!val || self.$t('validations.required', { field: self.$t(`fields.${field}`) }) } } const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ validations.email = ({ self, field }) => { return function required (val) { return emailRegex.test(val) || self.$t('validations.email', { field: self.$t(`fields.${field}`) }) } } validations.server = ({ self, field }) => { return function server (val) { return self.validationArgs[field].server } } export default function validation (self, context) { const _validations = {} for (const field in context) { const _rules = [] const rules = context[field] const names = Object.keys(validations) for (const rule of names) { if (rules.includes(rule)) { _rules.push(validations[rule]({ self, field })) } } _validations[field] = _rules } _validations.resetServer = function reset () { for (const field in context) { if (field in self.validationArgs && 'server' in self.validationArgs[field]) { self.validationArgs[field].server = true } } } return _validations } 

no serviço acima, as linhas que merecem atenção são:

function required (val) { return !!val || self.$t('validations.required', { field: self.$t(`fields.${field}`) }) } 
function email (val) { return emailRegex.test(val) || self.$t('validations.email', { field: self.$t(`fields.${field}`) }) } 

Em ambos os casos, temos uma função que retorna um boolean ou uma string, caso retorne true, é por que passou no teste, se retornar uma string, é por que o teste falhou, e a string é a mensagem de erro. o self.$t serve para recuperamos esta mensagem já localizada.

return function server (val) { return self.validationArgs[field].server } 

Já esta validação dependente de um dado proveniente do componente, neste caso, o retorno da API.

Desta forma, se quisemos validar o userName e o password, podemos montar as rules da seguinte forma.:

import validations from 'services/validations' export default { data () { const self = this const validation = validations(self, { userName: ['required', 'email', 'server'], password: ['required', 'server'] }) return { userName: '', password: '', validation, validationArgs: { userName: { server: true }, password: { server: true } } } } } 
<q-nput label="$t('fields.userName')" v-model="userName" :rules="validation.userName" @blur="validationArgs.userName.server = true" /> <q-nput label="$t('fields.password')" type="password" v-model="password" :rules="validation.password" @blur="validationArgs.password.server = true" /> 

Através do objeto validationArgs, conseguimos passar alguma informação complementar ao serviço que constrói as validações, por exemplo, validationArgs.userName.server será utilizado pela validação server.

Lembrando que userName e password devem está presentes no arquivo de localização (i18n), assim como as regras required, email e server.

Assim como as regras utilizadas (no caso acima, required, email e server) devem está devidamente implementadas no serviço validations.

Nos próximos capítulos, nós veremos mais sobre estas validações.

E para fechamos estes assunto, precisamos criar um alias para a pasta services, o primeiro passo é adicionar o seguinte bloco de código no quasar.config.js > build > extendWebpack

QPANC.App/quasar.config.js

const path = require('path') module.exports = function (ctx) { return { build: { extendWebpack (cfg, { isServer, isClient }) { cfg.resolve.alias = { ...cfg.resolve.alias, services: path.resolve(__dirname, './src/services'), } } } } } 

e para permitir que o intellisense funcione no VSCode, precisamos adicionar o seguinte item jsconfig.json > compilerOptions > paths

QPANC.App/jsconfig.json

{ "compilerOptions": { "paths": { "services/*": [ "src/services/*" ] } } } 

21 Instalando extensões

Como a aplicação está rodando em uma VM, e ao instalar uma extensão será adicionado um pacote pelo npm ou yarn. você terá que adotar uma das seguintes rotinas.:

21.1 - quasar ext add extensao_id

Você poderá adicionar a extensão usando o quasar ext add extensao_id, porém será preciso excluir a pasta node_modules e os arquivos de lock (yarn.lock e/ou package-lock.json). exemplo:

quasar ext invoke qautomate 

21.2 - quasar ext invoke extensao_id

Para usar o invoke, é preciso instalar o pacote utilizado pela extensão antes, por exemplo, para a extensão qautomate:

QPANC.App/package.json

{ "devDependencies": { "quasar-app-extension-qautomate": "^1.0.0-alpha.5" } } 

então execute a aplicação para que o pacote seja instalado a partir da VM gerenciada pelo Docker.

Após parar o container, podemos usar o invoke:

quasar ext invoke qautomate 

21.3 - Considerações

Eu sempre opto por fazer o add, então apago o node_modules e o yarn.lock, por mais que seja mais demorado, é mais pratico, menos propenso a erros e me dá uma desculpa para ir tomar um café.

Top comments (0)