QPANC são as iniciais de Quasar PostgreSQL ASP NET Core.
- Source
- Introdução
- Parte I - ASP.NET - Inicializando os Projetos
- Parte 2 - PostgreSQL
- Parte 3 - ASP.NET - Registrando Serviços e Lendo Variáveis de Ambiente
- Parte 4 - ASP.NET - Entity Framework e ASP.NET Core Identity
- Parte 5 - ASP.NET - Documentação Interativa com Swagger
- Parte 6 - ASP.NET - Regionalização
- Parte 7 - ASP.NET - Autenticação e Autorização
- Parte 8 - ASP.NET - CORS
- Parte 9 - Quasar - Criação e Configuração do Projeto
- Parte 10 - Quasar - Configurações e Customizações
- Parte 11 - Quasar - Componentes - Diferença entre SPA e SSR
- Parte 12 - Quasar - Serviços
- Parte 13 - Quasar - Regionalização e Stores
- Parte 14 - Quasar - Consumindo a API
- Parte 15 - Quasar - Login
- Parte 16 - Quasar - Áreas Protegidas
- Parte 17 - Quasar - Registro
- Parte 18 - Docker - Maquina Virtual Linux
- Parte 19 - Docker - Registro e Build
- Parte 20 - Docker - Traefik e Publicação
- Demo Online
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)