separate styles for separate module in Angular 5 - css

My project has two main parts. One for public web pages and the other for admin control panel. Each of them has separate CSS and javascript files for their template.
If I define all CSS and js files in index.html, all files load in the first meet of the web page, and also maybe have a conflict between CSS classes.
How can I handle this problem?
app.component:
<router-outlet></router-outlet>
app-routing.module:
import { NgModule } from "#angular/core";
import { Routes, RouterModule } from "#angular/router";
import { FirstComponent } from './first/first.component';
const appRoutes: Routes = [
{ path: 'first', component: FirstComponent },
{
path: 'controlpanel',
loadChildren: 'app/control-panel/control-panel.module#ControlPanelModule'
},
{
path: 'publicpanel',
loadChildren: 'app/public-panel/public-panel.module#PublicPanelModule'
}
];
each module has its submodules. Can I separate their styles?

Use sass and create a class flag for public and admin components
like this
theme/_public.scss
.public{
label {
color:red;
}
}
theme/_admin.scss
.admin {
label {
color:green;
}
}
and this in main style.scc
#import "theme/_public.scss";
#import "theme/_admin.scss";
this is much better for app performance you will have one style file with public and admin pages style
stackblitz example

I found the solution. We can disable or enable css files in component.
document.styleSheets[2].disabled = false;
or
document.styleSheets[2].disabled = true;
that's it.

Related

#aws-amplify/ui-react how to customize UI if my project uses SASS?

I'm extending a Next.js (React) project that was built by someone else, which uses .scss files (SASS) for styling. This is the project in question https://github.com/codebushi/nextjs-starter-dimension
Now I'm adding an authentication flow to the project using #aws-amplify/ui-react. Everything works fine, but I want to customize the UI style. I've found in the documentation that I can do that through :root in globals.css, as so:
:root {
--amplify-primary-color: #ff6347;
--amplify-primary-tint: #ff7359;
--amplify-primary-shade: #e0573e;
}
Documentation here: https://docs.amplify.aws/ui/customization/theming/q/framework/react
I know pretty much nothing about SASS except the basics. How would I do the equivalent of setting those variables in :root?
Edit with more details
This is my next.config.js:
module.exports = {
webpack: (config, { dev }) => {
config.module.rules.push(
{
test: /\.scss$/,
use: ['raw-loader', 'sass-loader']
}
)
return config
}
}
This is my authentication page where the Amplify elements are defined:
import { useState, useEffect } from 'react'
import { AuthState, onAuthUIStateChange } from '#aws-amplify/ui-components';
import { AmplifyAuthenticator, AmplifyAuthContainer, AmplifySignUp, AmplifySignIn, AmplifySignOut } from '#aws-amplify/ui-react';
import Router from 'next/router'
const Auth = (props) => {
const [authState, setAuthState] = useState();
const [user, setUser] = useState();
useEffect(() => {
return onAuthUIStateChange((nextAuthState, authData) => {
setAuthState(nextAuthState);
setUser(authData);
//console.log(`authData: ${JSON.stringify(authData, null, 2)}`);
});
}, []);
if (authState === AuthState.SignedIn && user) {
Router.push('https://mywebsite')
return <p>Redirecting...</p>
}
return (
<AmplifyAuthContainer>
<AmplifyAuthenticator usernameAlias="email">
<AmplifySignUp
slot="sign-up"
usernameAlias="email"
formFields={[
{
type: "email",
label: "Email Address *",
placeholder: "Enter your email address",
inputProps: { required: true },
},
{
type: "password",
label: "Password *",
placeholder: "Enter your password",
inputProps: { required: true },
},
]}
/>
<AmplifySignIn slot="sign-in" usernameAlias="email" />
</AmplifyAuthenticator>
</AmplifyAuthContainer>
);
}
export default Auth;
As per the answer below from Sean W, I've already tried creating an _app.js with:
import '../styles/global.scss'
const App = ({ Component, pageProps }) => {
return <Component {...pageProps} />
}
export default App;
with global.scss:
:root {
--amplify-primary-color: #ff6347;
--amplify-primary-tint: #ff7359;
--amplify-primary-shade: #e0573e;
}
But the CSS variables don't seem to be replaced.
Include the styles in your pages. The easiest way is to create a new SCSS file and include it in a custom _app.js.
By default, Next supports SASS - you only need to install the sass npm package and likely do not need a custom next.config. This could be one of your problems.
file - global.scss -
:root{
--amplify-primary-color: #ff6347;
--amplify-primary-shade: #e0573e;
}
//scoped & redeclared to an element with id #__next
:root #__next {
--amplify-primary-color: #ff6347;
--amplify-primary-shade: #e0573e;
}
Amplify could also be setting setting styles after you have already defined them for the :root - if this is the case you will need to scope your custom styles to take precedence over the default Amplify CSS variables. To do this - redeclare them in a CSS rule that is more specific than :root like the example above - keeping order of precedence in mind
Amplify also lets you directly target components.
amplify-authenticator {
--amplify-primary-color: #ff6347;
background: var(--amplify-primary-color);
padding: 5px;
}
// scoped & redeclared
:root #__next amplify-sign-in{
--amplify-primary-color: #ff6347;
}
The amplify elements that can be targeted are
amplify-authenticator
amplify-sign-in
amplify-confirm-sign-in
amplify-sign-up
amplify-confirm-sign-up
amplify-forgot-password
amplify-require-new-password
amplify-verify-contact
amplify-totp-setup
import your file - pages/_app.js
import 'path/to/global.scss';
const App = ({ Component, pageProps }) => <Component {...pageProps} />;
export default App;
Global variables (the equivalent of :root variables) can be created simply with this line.
$color = #c0ff33 !important;
The content can be anything that is available in css and partially sass.
For large projects, creating a variables.scss file and including in it all these variable declarations can be truly helpful for changing multiple variables at once. To include this file, just do #import "./variables.scss" at the top of your file.
Hope this helps! Good luck in your sassy endeavors!

Importing css from a node module required in a plugin file with nuxt js

To add the fullscreen button to my leaflet map into nuxt i have installed leaflet.fullscreen package and i have edited my plugin leaflet.js like so:
import Vue from "vue";
import { LMap, LTileLayer, LMarker, LPolyline } from "vue2-leaflet";
require("leaflet-routing-machine");
require("lrm-graphhopper");
require("leaflet.fullscreen");
So i can use it in my main template:
<template>
<div>
<section class="search__page">
<div id="map-wrap" class="map__wrapper"></div>
</section>
</div>
</template>
<script>
import Tmap from "#/utils/TripMap.js";
export default {
mounted() {
this.initTmap();
},
data() {
return {
mainMap: null,
},
methods: {
initTmap() {
this.mainMap = new Tmap();
this.mainMap.load();
}
}
}
</script>
My class looks like that :
export default class Tmap {
constructor() {
this.map = null;
}
load) {
this.map = L.map("map-wrap", {
fullscreenControl: true,
fullscreenControlOptions: {
position: "topleft"
}).setView([46.7227062, 2.5046503], 6);
L.tileLayer("http://{s}.tile.osm.org/{z}/{x}/{y}.png", {
maxZoom: 18,
attribution: '© OpenStreetMap, ©TRIP'
}).addTo(this.map);
}
addMarkerOnClick() {
this.map.addEventListener("click", ev => {
L.marker(ev.latlng).addTo(this.map);
});
}
getBounds() {
return this.map.getBounds();
}
}
So in my main component i don't know how to import the css associated to this fullscreen plugin. I tried :
<style>
#import "~/node_modules/leaflet.fullscreen/Control.FullScreen.css";
</style>
That works but it's obviously not the good way to do that. Any idea how to that properly ?
From a quick web research i would say you should be able to access the styles like this:
#import "~leaflet/dist/leaflet.css";
When you register a global style in your nuxt.config.js the app will load it just once. I assume your build is taking more time than normal due to the node_modules path.
// nuxt.config.js
css: ['~/assets/styles/global.css'],
You could also give the nuxt resource loader a try.

rollup 'rollup-plugin-postcss' dont inject css into head

I want to create an HTML web component and i need to import CSS file but I want to inject it into my shadow dom. I have some code like below:
import introHTML from './Intro.html';
import introCss from './Intro.css';
class IntroWebComponent extends HTMLElement{
constructor(){
super();
this.defineClassProp();
}
defineClassProp(){
this._shadowRoot = this.attachShadow({ mode: 'open' });
this._html = introHTML
this._element = document.createElement('template');
this._element.innerHTML = this._html;
this._element.append(`<style>${introCss}</style>`)
this._shadowRoot.appendChild(this._element.content.cloneNode(true));
}
}
window.customElements.define('index-intro', IntroWebComponent);
but 'rollup-plugin-postcss' keep injecting css to my main html head and i dont know how to stop it
just config your rollup to stop inject style in your js module:
the default config is:
postcss({
inject: { insertAt: 'top' }
})
you must change it to:
postcss({
inject:false
})

where do you import css in angular2 cli

when we try to import 3rd party libs in angular 2 cli we are using this,
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
module.exports = function(defaults) {
return new Angular2App(defaults, {
vendorNpmFiles: [
'#angular2-material/**/*.js'
]
});
};
and in system-config.ts we write it like this,
/** Map relative paths to URLs. */
const map: any = {
'#angular2-material': 'vendor/#angular2-material'
};
/** User packages configuration. */
const packages: any = {
'#angular2-material/core': {
format: 'cjs',
defaultExtension: 'js',
main: 'core.js'
},
'#angular2-material/checkbox': {
format: 'cjs',
defaultExtension: 'js',
main: 'checkbox.js'
},
// And so on...
};
and in component
import { Component } from '#angular/core';
import { MdCheckbox } from '#angular2-material/checkbox';
#Component({
selector: 'my-app',
template: `<md-checkbox></md-checkbox>`,
directives: [MdCheckbox]
})
export class AppComponent { }
all library is in .js but what if it's css how do we import it?
like how to use fontawesome , sweetalert or bootstrap ?
If you'd like to pull in a style library (bootstrap/font-awesome) you can place the files in the generated public directory.
Within there I create a style directory and place the files in there for example....
[project-root]/public/style/bootstrap.css
When builds run it will take the contents of public and move it to dist...
[project-root]/dist/style/bootstrap.css
And you can reference these files within index.html like so...
<link rel="stylesheet" href="style/bootstrap.css">

React: Inline CSS modules in JSX with Webpack

I have a minimal React component which consists of two files: button.jsx and button.less. The styles are imported and the class names are appended with a hash to make all styles local to the component.
This is great, but i'd like to have all component code in one file. Is it possible to inline the styles in jsx file without losing css modularity?
Current Code
button.jsx
import React from 'react';
import styles from './button.less'
export default class Button extends React.Component {
render() {
return <button className={styles.primary}>{this.props.text}</button>;
}
}
button.less
#import '~semantic-ui/src/definitions/elements/button.less';
.common {
composes: ui button;
}
.primary {
composes: common primary;
}
webpack.config.js (relevant bits)
module: {
loaders: [
{
test: /\.jsx$/,
loader: 'babel'
},
{
test: /\.less$/,
loader: "style!css?modules&importLoaders=1!less"
}
]
},
What i'd like to write instead
button.jsx
<style lang="less" modules>
#import '~semantic-ui/src/definitions/elements/button.less';
.common {
composes: ui button;
}
.primary {
composes: common primary;
}
</style>
import React from 'react';
export default class Button extends React.Component {
render() {
return <button className={styles.primary}>{this.props.text}</button>;
}
}
Inspired by vue.js and vue-loader.
I believe this is a duplicate of this unanswered question:
Using css-loader inline with Webpack + React
I wrote a Webpack loader for this very purpose:
https://github.com/chrisdavies/stylextract-loader
It allows you to write a single style tag per JSX file and it supports webpack CSS modules, too, if you want.
At build time, it extracts the rules from your style tag and moves them out to an external CSS file.
I should note that because it simply extracts your rules out to an external CSS file, it plays nice with SASS, autoprefixer, etc
You can use callback-loader for this. This is actualy a workaround, but it do the trick. Just implement a callback which will extract your css-code and replace it with appropriate import. For example:
webpack.config.js
var fs = require('fs');
var cssIndex = 0;
// Do not forget to create and clean temporary folder "cssTemp" before
var webpackConfig = {
...
resolve: {
alias: {
cssTemp: path.resolve('./cssTemp')
}
},
module: {
loaders: [
{ test: /\.jsx$/, loader: "callback!babel" }
]
},
callbackLoader: {
cssCallback: function(code) {
var filename = cssIndex + '.less';
cssIndex++;
// Save the css code from the callback argument
fs.writeFileSync('./cssTemp/' + filename, code);
// Return the import statement which will replace the callback statement
return 'import styles from "cssTemp/' + filename + '";';
}
}
...
};
button.jsx
import React from 'react';
cssCallback(`
#import '~semantic-ui/src/definitions/elements/button.less';
.common {
composes: ui button;
}
.primary {
composes: common primary;
}
`);
export default class Button extends React.Component {
render() {
return <button className={styles.primary}>{this.props.text}</button>;
}
}

Resources