Add new theming docs and changeTheme api

pull/3699/head
Cagatay Civici 2023-03-03 10:02:10 +03:00
parent 7c1790921f
commit 60e368c2a0
16 changed files with 271 additions and 92 deletions

16
app.vue
View File

@ -46,21 +46,10 @@ export default {
};
this.themeChangeListener = (event) => {
const elementId = 'theme-link';
const linkElement = document.getElementById(elementId);
const cloneLinkElement = linkElement.cloneNode(true);
const newThemeUrl = linkElement.getAttribute('href').replace(this.$appState.theme, event.theme);
cloneLinkElement.setAttribute('id', elementId + '-clone');
cloneLinkElement.setAttribute('href', newThemeUrl);
cloneLinkElement.addEventListener('load', () => {
linkElement.remove();
cloneLinkElement.setAttribute('id', elementId);
});
linkElement.parentNode?.insertBefore(cloneLinkElement, linkElement.nextSibling);
this.$primevue.changeTheme(this.$appState.theme, event.theme, 'theme-link', () => {
this.$appState.theme = event.theme;
this.$appState.darkTheme = event.dark;
});
};
EventBus.on('theme-change', this.themeChangeListener);
@ -76,5 +65,4 @@ export default {
<style lang="scss">
@import '@/assets/styles/layout/landing/landing.scss';
@import '@/assets/styles/layout/layout.scss';
@import '@/assets/styles/demo/demo.scss';
</style>

View File

@ -1,4 +0,0 @@
.mypanel .p-panel-header {
background-color: #07c4e8;
color: #ffffff;
}

View File

@ -1 +0,0 @@
@import './_common';

View File

@ -145,11 +145,30 @@ export function usePrimeVue() {
return PrimeVue;
}
function switchTheme(currentTheme, newTheme, linkElementId, callback) {
const linkElement = document.getElementById(linkElementId);
const cloneLinkElement = linkElement.cloneNode(true);
const newThemeUrl = linkElement.getAttribute('href').replace(currentTheme, newTheme);
cloneLinkElement.setAttribute('id', linkElementId + '-clone');
cloneLinkElement.setAttribute('href', newThemeUrl);
cloneLinkElement.addEventListener('load', () => {
linkElement.remove();
cloneLinkElement.setAttribute('id', linkElementId);
if (callback) {
callback();
}
});
linkElement.parentNode?.insertBefore(cloneLinkElement, linkElement.nextSibling);
}
export default {
install: (app, options) => {
let configOptions = options ? { ...defaultOptions, ...options } : { ...defaultOptions };
const PrimeVue = {
config: reactive(configOptions)
config: reactive(configOptions),
changeTheme: switchTheme
};
app.config.globalProperties.$primevue = PrimeVue;

View File

@ -1,10 +1,12 @@
<template>
<DocSectionText v-bind="$attrs">
<p class="line-height-3 bg-indigo-600 text-white p-3 text-lg" style="border-radius: 10px">
<strong>Note</strong>: In upcoming versions, theming architecture will be redesigned to utilize CSS variables instead of SCSS variables in a backward compatible way for a dynamic approach. In addition, a new <strong>Unstyled</strong> mode
will be provided as an optional approach to replace default styling so that CSS libraries like Tailwind or Bootstrap can be used to style the components. This work is planned to be completed by the end of Q2 2023.
</p>
<p>
PrimeVue is a design agnostic library so unlike other UI libraries it does not enforce a certain styling such as material or bootstrap. In order to achieve this, styling has been separated into two parts, core and theme. Core resides
inside PrimeVue to implement the structure of the components such as positioning whereas theme brings the colors, paddings and margins. vVarious free themes and premium themes are available along with premium templates that provide an
application layout as well. All the free themes are built with the <a href="https://www.primefaces.org/designer/primevue">Theme Designer</a> and the npm package brings the compiled CSS output of the theme whereas SCSS is kept as a premium
feature in the designer.
PrimeVue is a design agnostic library so unlike other UI libraries it does not enforce a certain styling such as material or bootstrap. In order to achieve this, styling has been separated into two parts, core and theme. The core resides
inside PrimeVue to implement the structure of the components such as positioning whereas theme brings the colors and spacing.
</p>
<img alt="Architecture" src="https://primefaces.org/cdn/primevue/images/architecture.jpg" class="w-full" />
</DocSectionText>

View File

@ -1,8 +1,13 @@
<template>
<DocSectionText v-bind="$attrs">
<p>PrimeVue ships with various free themes to choose from. The list below states all the available themes in the npm distribution with import paths.</p>
<p>
PrimeVue ships with various free themes to choose from. The list below states all the available themes in the npm distribution with import paths. For a live preview, use the configurator
<span class="border-round inline-flex border-1 w-2rem h-2rem p-0 align-items-center justify-content-center bg-primary"><span class="pi pi-cog"></span></span> at the topbar to switch themes.
</p>
</DocSectionText>
<div class="h-20rem overflow-auto">
<DocSectionCode :code="code" hideToggleCode importCode hideCodeSandbox hideStackBlitz codeClassName="h-20rem overflow-auto" />
</div>
</template>
<script>

View File

@ -0,0 +1,49 @@
<template>
<DocSectionText v-bind="$attrs">
<p>
<a href="https://github.com/css-modules/css-modules">CSS modules</a> are supported by enabling the <i>module</i> property on a style element within your component and using the <i>$style</i> keyword to apply classes to a PrimeVue
component.
</p>
</DocSectionText>
<div class="card flex justify-content-center">
<InputText :class="$style.myinput" placeholder="Search" />
</div>
<DocSectionCode :code="code1" hideToggleCode importCode hideCodeSandbox hideStackBlitz />
<DocSectionCode :code="code2" hideToggleCode importCode hideCodeSandbox hideStackBlitz />
</template>
<script>
export default {
data() {
return {
code1: {
basic: `
<style module>
.myinput {
border-radius: 2rem;
padding: 1rem 2rem;
border-width: 2px;
}
</style>
`
},
code2: {
basic: `
<template>
<InputText :class="$style.myinput" placeholder="Search" />
</template>
`
}
};
}
};
</script>
<style module>
.myinput {
border-radius: 2rem;
padding: 1rem 2rem;
border-width: 2px;
}
</style>

View File

@ -1,5 +0,0 @@
<template>
<DocSectionText v-bind="$attrs">
<p>Each PrimeVue theme exports numerous CSS variables, refer to <NuxtLink to="/colors">Colors</NuxtLink> page for more details.</p>
</DocSectionText>
</template>

View File

@ -0,0 +1,65 @@
<template>
<DocSectionText v-bind="$attrs">
<p>
Themes are created with SASS using the <i>primevue-sass-theme</i> project available at <a href="http://github.com/primefaces/primevue-sass-theme">github</a>. This repository contains all the scss files for the components and the variables
of the built-in themes so that you may customize an existing theme or create your own. The scss variables used in a theme are available at the <a href="https://www.primefaces.org/designer/api/primevue/3.9.0">SASS API</a> documentation.
</p>
<p>
There are 3 alternatives to create your own theme. First option is using the Visual Editor, second one is compiling a theme with command line sass and final alternative is embedding scss files within your project to let your build
environment do the compilation. In all cases, the generated theme file should be imported to your project.
</p>
<h3>Visual Editor</h3>
<p>
<a href="https://designer.primevue.org">Visual Editor</a> is an easy way to quickly customize an existing theme without dealing with the details of the SASS API. The editor allows changing common settings like primary color for built-in
themes. Once you have completed the design, click the download button to access the generated <i>theme.css</i> file and import it to your project as an asset. In near future, an advanced UI Designer will be available with the ability to
edit all variables and components where you'll also be able to save your themes when accessed with an account.
</p>
<h3>Theme SCSS</h3>
<p>
The theme scss is availabe as open source at <a href="http://github.com/primefaces/primevue-sass-theme">primevue-sass-theme</a> repository. The <i>base</i> folder contains the theming structure of the components, themes under
<i>themes</i> folder define the SCSS variables and import the <i>base</i> to define a theme. The <i>themes</i> folder contains all the built-in themes so you can customize their code as well.
</p>
<p>
To create your own theme, clone the <a href="http://github.com/primefaces/primevue-sass-theme">primevue-sass-theme</a> repository and access the <i>themes/mytheme</i> folder. The sass variables to customize are available under the
<i>variables</i> folder. The <i>_fonts</i> file can be used to define a custom font for your project whereas the optional <i>_extensions</i> file is provided to add overrides to the components designs. The <i>theme.scss</i> file imports
the theme files along with the <i>base</i> folder at the root to combine everything together. Next step would be compilation of the scss that can either be command line or within your project.
</p>
<h3>Compile SCSS Manually</h3>
<p>Once your theme is ready run the following command to compile it. Note that <a href="https://www.npmjs.com/package/sass">sass</a> command should be available in your terminal.</p>
<DocSectionCode :code="code1" hideToggleCode importCode hideCodeSandbox hideStackBlitz />
<p>
Then copy and import the theme.css file in your application. For example, in a Vite based template like <a href="https://github.com/vuejs/create-vue">create-vue</a>, you may place theme.css under assets folder and then import it an
<i>main.js</i>.
</p>
<DocSectionCode :code="code2" hideToggleCode importCode hideCodeSandbox hideStackBlitz />
<h3>Build Time Compilation</h3>
<p>
This approach eliminates the manual compilation by delegating it to your build environment that has the ability to compile SCSS. Clone <a href="http://github.com/primefaces/primevue-sass-theme">primevue-sass-theme</a> and copy the
<i>base</i> folder along with <i>themes/mytheme</i> folder to your application where assets reside. At a suitable location like <i>main.js</i> or <i>App.vue</i>, import the <i>theme.scss</i> from <i>assets/themes/mytheme</i>. That would
be it, during build time, your project will compile the sass and import the theme. Any changes to your theme will be reflected instantly.
</p>
</DocSectionText>
</template>
<script>
export default {
data() {
return {
code1: {
basic: `
sass --update themes/mytheme/theme.scss:themes/mytheme/theme.css
`
},
code2: {
basic: `
import './assets/theme.css';
`
}
};
}
};
</script>

View File

@ -1,21 +0,0 @@
<template>
<DocSectionText v-bind="$attrs">
<p>
CSS of the themes share the same license as PrimeVue which is MIT, this means the generated CSS can be customized per your needs however this should be avoided if your customizations are not simple. For instance even to change a primary
color, since there is no variable a find and replace should be performed various times. On the other hand, this can be achieved by changing a single variable e.g. <i>$primaryColor</i>. Visit the{' '}
<a href="https://www.primefaces.org/designer/api/primevue/3.9.0">SASS API</a> for the documentation of available customization options.
</p>
<p>
<a href="https://www.primefaces.org/designer/primevue">Designer</a> is the ultimate tool to create your own PrimeVue experience powered by a SASS based theme engine with 500+ variables and a Visual Designer. PrimeVue only ships the
generated CSS of the themes whereas Designer provides full access to the whole SASS structure and the variables of these pre-built themes for easier customization.
</p>
<p>Whether you have your own style guide or just need a custom theme, Designer is the right tool to design and bring them to existence.</p>
<p>Visit <a href="https://www.primefaces.org/designer/primevue">Designer Website</a> for more information and live demos.</p>
<a href="http://www.primefaces.org/designer/primevue">
<img alt="PrimeVue Designer" src="https://primefaces.org/cdn/primevue/images/primevue-designer.jpg" class="w-full" />
</a>
</DocSectionText>
</template>

View File

@ -8,9 +8,9 @@
<p>Here is an example to demonstrate how to align 3 buttons horizontally on bigger screens and display them as stacked on smaller ones.</p>
</DocSectionText>
<div class="card flex flex-column md:flex-row justify-content-between my-5">
<Button type="button" label="Button 1" class="mb-3 md:mb-0"></Button>
<Button type="button" label="Button 2" class="p-button-secondary mb-3 md:mb-0"></Button>
<div class="card flex flex-column md:flex-row md:justify-content-between row-gap-3">
<Button type="button" label="Button 1"></Button>
<Button type="button" label="Button 2" class="p-button-secondary"></Button>
<Button type="button" label="Button 3" class="p-button-help"></Button>
</div>
<DocSectionCode :code="code" hideToggleCode importCode hideCodeSandbox hideStackBlitz />
@ -22,9 +22,9 @@ export default {
return {
code: {
basic: `
<div class="flex flex-column md:flex-row justify-content-between my-5">
<Button type="button" label="Button 1" class="mb-3 md:mb-0"></Button>
<Button type="button" label="Button 2" class="p-button-secondary mb-3 md:mb-0"></Button>
<div class="flex flex-column md:flex-row md:justify-content-between row-gap-3">
<Button type="button" label="Button 1"></Button>
<Button type="button" label="Button 2" class="p-button-secondary"></Button>
<Button type="button" label="Button 3" class="p-button-help"></Button>
</div>
`

View File

@ -1,12 +1,9 @@
<template>
<DocSectionText v-bind="$attrs">
<p>
A named class is bound to the <i>class</i> property of a component and the CSS is included with an import. Note that, the css still is still bundled globally so prefer this approach if your application doesn't have a built-in solution to
do CSS scoping.
</p>
<p>Scoped CSS allows overriding the styles of a particular PrimeVue component using <i>scoped</i> SFC style and <i>:deep</i>.</p>
</DocSectionText>
<div class="card">
<Panel header="Named ClassName" class="mypanel">
<Panel header="Scoped Panel">
<p class="m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
@ -24,10 +21,15 @@ export default {
code1: {
basic: `
<style scoped>
.mypanel .p-panel-header {
background-color: #07c4e8;
:deep(.p-panel .p-panel-header) {
background-color: var(--teal-500);
border-color: var(--teal-500);
color: #ffffff;
}
:deep(.p-panel .p-panel-content) {
border-color: var(--teal-500);
}
</style>
`
},
@ -35,7 +37,7 @@ export default {
code2: {
basic: `
<template>
<Panel header="Named ClassName" class="mypanel">
<Panel header="Scoped Panel">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
@ -50,8 +52,13 @@ export default {
</script>
<style scoped>
.mypanel .p-panel-header {
background-color: #07c4e8;
:deep(.p-panel .p-panel-header) {
background-color: var(--teal-500);
border-color: var(--teal-500);
color: #ffffff;
}
:deep(.p-panel .p-panel-content) {
border-color: var(--teal-500);
}
</style>

View File

@ -0,0 +1,73 @@
<template>
<DocSectionText v-bind="$attrs">
<p class="line-height-3 bg-indigo-600 text-white p-3 text-lg" style="border-radius: 10px">
Solution below works however there is room for improvement. The upcoming styling api will greatly improve dynamic theme switching ability, eliminates the prerequisites with the introduction of CSS variables and dynamic imports.
</p>
<p>
Themes can be dynamically changed using the <i>PrimeVue.changeTheme</i> function. For this feature to work, there are two prerequisites. To begin with, the themes should be publicly available under the <i>public</i> folder in your project
by copying them from PrimeVue <i>resources/themes</i> folder. Second part is making the theme.css accessible via a link element so that the id of the link can be provided as the 3rd parameter to the <i>changeTheme</i> function.
</p>
</DocSectionText>
<DocSectionCode :code="code1" hideToggleCode importCode hideCodeSandbox hideStackBlitz />
<DocSectionCode :code="code2" hideToggleCode importCode hideCodeSandbox hideStackBlitz />
<DocSectionCode :code="code3" hideToggleCode importCode hideCodeSandbox hideStackBlitz />
<div class="doc-section-description">
<p>In a Vite based project like <a href="https://github.com/vuejs/create-vue">create-vue</a>, the link can be placed at index.html.</p>
</div>
<DocSectionCode :code="code4" hideToggleCode importCode hideCodeSandbox hideStackBlitz />
<div class="doc-section-description">
<p><a href="https://nuxtjs.org/">Nuxt</a> applications can configure the link element using <i>nuxt.config.js</i>.</p>
</div>
<DocSectionCode :code="code5" hideToggleCode importCode hideCodeSandbox hideStackBlitz />
</template>
<script>
export default {
data() {
return {
code1: {
basic: `
primevue.changeTheme(currentTheme: string, newTheme: string, linkElementId: string, callback: Function)
`
},
code2: {
basic: `
// Options API
this.$primevue.changeTheme('md-dark-indigo', 'md-dark-indigo', 'theme-link', () => {});
`
},
code3: {
basic: `
// Composition API
import { usePrimeVue } from 'primevue/config';
const PrimeVue = usePrimeVue();
PrimeVue.changeTheme('md-dark-indigo', 'md-dark-indigo', 'theme-link', () => {});
`
},
code4: {
basic: `
<link id="theme-link" rel="stylesheet" href="/themes/lara-light-blue/theme.css">
`
},
code5: {
basic: `
const baseUrl = '/';
export default defineNuxtConfig({
app: {
baseURL: baseUrl,
head: {
link: [
{
id: 'theme-link',
rel: 'stylesheet',
href: baseUrl + 'themes/lara-light-blue/theme.css'
}
],
`
}
};
}
};
</script>

View File

@ -43,10 +43,6 @@
<td>p-invalid</td>
<td>Applies the invalid style to a text or a form field.</td>
</tr>
<tr>
<td>p-text-secondary</td>
<td>Applies the text color of the theme with the secondary priority.</td>
</tr>
</tbody>
</table>
</div>

View File

@ -4,7 +4,7 @@
<template v-if="doc.children">
<div :id="doc.id">
<DocSectionText :id="doc.id" :label="doc.label">
{{ doc.description || null }}
<p v-if="doc.description">{{ doc.description }}</p>
</DocSectionText>
</div>
<template v-for="comp of doc.children" :key="comp.label">

View File

@ -20,13 +20,14 @@
<script>
import ArchitectureDoc from '@/doc/theming/ArchitectureDoc';
import CSSVariablesDoc from '@/doc/theming/CSSVariablesDoc';
import DesignerDoc from '@/doc/theming/DesignerDoc';
import BuiltInThemesDoc from '@/doc/theming/BuiltInThemesDoc';
import CSSModulesDoc from '@/doc/theming/CSSModulesDoc';
import CustomThemeDoc from '@/doc/theming/CustomThemeDoc';
import PrimeFlexDoc from '@/doc/theming/PrimeFlexDoc';
import ScaleDoc from '@/doc/theming/ScaleDoc';
import ScopedStylingDoc from '@/doc/theming/ScopedStylingDoc';
import ThemesDoc from '@/doc/theming/ThemesDoc';
import ScopedCSSDoc from '@/doc/theming/ScopedCSSDoc';
import UtilsDoc from '@/doc/theming/UtilsDoc';
import SwitchThemesDoc from '../../doc/theming/SwitchThemesDoc';
export default {
data() {
@ -38,19 +39,29 @@ export default {
component: ArchitectureDoc
},
{
id: 'themes',
label: 'Themes',
component: ThemesDoc
id: 'builtinthemes',
label: 'Buit-in Themes',
component: BuiltInThemesDoc
},
{
id: 'designer',
label: 'Designer',
component: DesignerDoc
id: 'switchthemes',
label: 'Switch Themes',
component: SwitchThemesDoc
},
{
id: 'scopedstyling',
label: 'Scoped Styling',
component: ScopedStylingDoc
id: 'customtheme',
label: 'Custom Theme',
component: CustomThemeDoc
},
{
id: 'scopedcss',
label: 'Scoped CSS',
component: ScopedCSSDoc
},
{
id: 'cssmodules',
label: 'CSS Modules',
component: CSSModulesDoc
},
{
id: 'scale',
@ -66,11 +77,6 @@ export default {
id: 'utils',
label: 'Utils',
component: UtilsDoc
},
{
id: 'cssvariables',
label: 'CSS Variables',
component: CSSVariablesDoc
}
]
};