Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 9 additions & 24 deletions src/material/schematics/ng-add/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {SchematicTestRunner} from '@angular-devkit/schematics/testing';
import {
getProjectFromWorkspace,
getProjectIndexFiles,
getProjectStyleFile,
getProjectTargetOptions,
} from '@angular/cdk/schematics';
import {createTestApp, createTestLibrary, getFileContent} from '../../../cdk/schematics/testing';
Expand Down Expand Up @@ -87,7 +86,7 @@ describe('ng-add schematic', () => {
const workspace = await readWorkspace(tree);
const project = getProjectFromWorkspace(workspace, baseOptions.project);

expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss');
expectProjectStyleFile(project, 'projects/material/src/material-theme.scss');
});

it('should support adding a custom theme', async () => {
Expand Down Expand Up @@ -121,12 +120,12 @@ describe('ng-add schematic', () => {
);
const workspace = await readWorkspace(tree);
const project = getProjectFromWorkspace(workspace, baseOptions.project);
const expectedStylesPath = normalize(`/${project.root}/src/custom-theme.scss`);
const expectedStylesPath = normalize(`/${project.root}/src/material-theme.scss`);

expect(tree.files)
.withContext('Expected a custom theme file to be created')
.toContain(expectedStylesPath);
expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss');
expectProjectStyleFile(project, 'projects/material/src/material-theme.scss');
});

it('should add font links', async () => {
Expand Down Expand Up @@ -160,20 +159,6 @@ describe('ng-add schematic', () => {
});
});

it('should add material app styles', async () => {
const tree = await runner.runSchematic('ng-add-setup-project', baseOptions, appTree);
const workspace = await readWorkspace(tree);
const project = getProjectFromWorkspace(workspace, baseOptions.project);

const defaultStylesPath = getProjectStyleFile(project)!;
const htmlContent = tree.read(defaultStylesPath)!.toString();

expect(htmlContent).toContain('html, body { height: 100%; }');
expect(htmlContent).toContain(
'body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }',
);
});

describe('custom project builders', () => {
/** Overwrites a target builder for the workspace in the given tree */
function overwriteTargetBuilder(tree: Tree, targetName: 'build' | 'test', newBuilder: string) {
Expand Down Expand Up @@ -223,15 +208,15 @@ describe('ng-add schematic', () => {

describe('theme files', () => {
it('should not overwrite existing custom theme files', async () => {
appTree.create('/projects/material/custom-theme.scss', 'custom-theme');
appTree.create('/projects/material/material-theme.scss', 'material-theme');
const tree = await runner.runSchematic(
'ng-add-setup-project',
{...baseOptions, theme: 'azure-blue'},
appTree,
);
expect(tree.readContent('/projects/material/custom-theme.scss'))
expect(tree.readContent('/projects/material/material-theme.scss'))
.withContext('Expected the old custom theme content to be unchanged.')
.toBe('custom-theme');
.toBe('material-theme');
});
});

Expand Down Expand Up @@ -277,7 +262,7 @@ describe('ng-add schematic', () => {
const workspace = await readWorkspace(tree);
const project = getProjectFromWorkspace(workspace, baseOptions.project);

expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss');
expectProjectStyleFile(project, 'projects/material/src/material-theme.scss');
});
});

Expand Down Expand Up @@ -323,7 +308,7 @@ describe('ng-add schematic', () => {
const workspace = await readWorkspace(tree);
const project = getProjectFromWorkspace(workspace, baseOptions.project);

expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss');
expectProjectStyleFile(project, 'projects/material/src/material-theme.scss');
});
});

Expand Down Expand Up @@ -360,7 +345,7 @@ describe('ng-add schematic', () => {
const workspace = await readWorkspace(tree);
const project = getProjectFromWorkspace(workspace, baseOptions.project);

expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss');
expectProjectStyleFile(project, 'projects/material/src/material-theme.scss');
});
});
});
Expand Down
53 changes: 2 additions & 51 deletions src/material/schematics/ng-add/setup-project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import {chain, Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {getProjectFromWorkspace, getProjectStyleFile} from '@angular/cdk/schematics';
import {getProjectFromWorkspace} from '@angular/cdk/schematics';
import {readWorkspace} from '@schematics/angular/utility';
import {ProjectType} from '@schematics/angular/utility/workspace-models';
import {addFontsToIndex} from './fonts/material-fonts';
Expand All @@ -25,11 +25,7 @@ export default function (options: Schema): Rule {
const project = getProjectFromWorkspace(workspace, options.project);

if (project.extensions['projectType'] === ProjectType.Application) {
return chain([
addThemeToAppStyles(options),
addFontsToIndex(options),
addMaterialAppStyles(options),
]);
return chain([addThemeToAppStyles(options), addFontsToIndex(options)]);
}
context.logger.warn(
'Angular Material has been set up in your workspace. There is no additional setup ' +
Expand All @@ -40,48 +36,3 @@ export default function (options: Schema): Rule {
return;
};
}

/**
* Adds custom Material styles to the project style file. The custom CSS sets up the Roboto font
* and reset the default browser body margin.
*/
function addMaterialAppStyles(options: Schema) {
return async (host: Tree, context: SchematicContext) => {
const workspace = await readWorkspace(host);
const project = getProjectFromWorkspace(workspace, options.project);
const styleFilePath = getProjectStyleFile(project);
const logger = context.logger;

if (!styleFilePath) {
logger.error(`Could not find the default style file for this project.`);
logger.info(`Consider manually adding the Roboto font to your CSS.`);
logger.info(`More information at https://fonts.google.com/specimen/Roboto`);
return;
}

const buffer = host.read(styleFilePath);

if (!buffer) {
logger.error(
`Could not read the default style file within the project ` + `(${styleFilePath})`,
);
logger.info(`Please consider manually setting up the Roboto font.`);
return;
}

const htmlContent = buffer.toString();
const insertion =
'\n' +
`html, body { height: 100%; }\n` +
`body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }\n`;

if (htmlContent.includes(insertion)) {
return;
}

const recorder = host.beginUpdate(styleFilePath);

recorder.insertLeft(htmlContent.length, insertion);
host.commitUpdate(recorder);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
* found in the LICENSE file at https://angular.dev/license
*/

/** Create custom theme for the given application configuration. */
export function createCustomTheme(userPaletteChoice: string): string {
const colorPalettes = new Map<string, {primary: string; tertiary: string}>([
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we wanna keep these types ? I don't understand why remove them?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TS can easily infer them from the constructor so we don't need to specify them.

/** Create theme for the given application configuration. */
export function createTheme(userPaletteChoice: string): string {
const colorPalettes = new Map([
['azure-blue', {primary: 'azure', tertiary: 'blue'}],
['rose-red', {primary: 'rose', tertiary: 'red'}],
['magenta-violet', {primary: 'magenta', tertiary: 'violet'}],
Expand All @@ -23,6 +23,7 @@ export function createCustomTheme(userPaletteChoice: string): string {
@use '@angular/material' as mat;
html {
height: 100%;
@include mat.theme((
color: (
primary: mat.$${colorPalettes.get(userPaletteChoice)!.primary}-palette,
Expand All @@ -48,6 +49,7 @@ body {
// Reset the user agent margin.
margin: 0;
height: 100%;
}
`;
}
30 changes: 15 additions & 15 deletions src/material/schematics/ng-add/theming/theming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ import {InsertChange} from '@schematics/angular/utility/change';
import {ProjectDefinition, readWorkspace, updateWorkspace} from '@schematics/angular/utility';
import {join} from 'path';
import {Schema} from '../schema';
import {createCustomTheme} from './create-custom-theme';
import {createTheme} from './create-theme';

/** Path segment that can be found in paths that refer to a prebuilt theme. */
const prebuiltThemePathSegment = '@angular/material/prebuilt-themes';

/** Default file name of the custom theme that can be generated. */
const defaultCustomThemeFilename = 'custom-theme.scss';
const defaultThemeFilename = 'material-theme.scss';

/** Add pre-built styles to the main project style file. */
export function addThemeToAppStyles(options: Schema): Rule {
Expand All @@ -40,15 +40,15 @@ export function addThemeToAppStyles(options: Schema): Rule {
palettes = 'azure-blue';
}

return insertCustomTheme(palettes, options.project, host, context.logger);
return insertTheme(palettes, options.project, host, context.logger);
};
}

/**
* Insert an Angular Material theme to project style file. If no valid style file could be found, a new
* Scss file for the custom theme will be created.
* Insert an Angular Material theme to project style file. If no valid style file could be found,
* a new Sass file for the theme will be created.
*/
async function insertCustomTheme(
async function insertTheme(
palettes: string,
projectName: string,
host: Tree,
Expand All @@ -57,7 +57,7 @@ async function insertCustomTheme(
const workspace = await readWorkspace(host);
const project = getProjectFromWorkspace(workspace, projectName);
const stylesPath = getProjectStyleFile(project, 'scss');
const themeContent = createCustomTheme(palettes);
const themeContent = createTheme(palettes);

if (!stylesPath) {
if (!project.sourceRoot) {
Expand All @@ -69,16 +69,16 @@ async function insertCustomTheme(

// Normalize the path through the devkit utilities because we want to avoid having
// unnecessary path segments and windows backslash delimiters.
const customThemePath = normalize(join(project.sourceRoot, defaultCustomThemeFilename));
const themePath = normalize(join(project.sourceRoot, defaultThemeFilename));

if (host.exists(customThemePath)) {
logger.warn(`Cannot create a custom Angular Material theme because
${customThemePath} already exists. Skipping theme generation.`);
if (host.exists(themePath)) {
logger.warn(`Cannot create an Angular Material theme because
${themePath} already exists. Skipping theme generation.`);
return noop();
}

host.create(customThemePath, themeContent);
return addThemeStyleToTarget(projectName, 'build', customThemePath, logger);
host.create(themePath, themeContent);
return addThemeStyleToTarget(projectName, 'build', themePath, logger);
}

const insertion = new InsertChange(stylesPath, 0, themeContent);
Expand Down Expand Up @@ -122,10 +122,10 @@ function addThemeStyleToTarget(
// theme file. If a custom theme is set up, we are not able to safely replace the custom
// theme because these files can contain custom styles, while prebuilt themes are
// always packaged and considered replaceable.
if (stylePath.includes(defaultCustomThemeFilename)) {
if (stylePath.includes(defaultThemeFilename)) {
logger.error(
`Could not add the selected theme to the CLI project ` +
`configuration because there is already a custom theme file referenced.`,
`configuration because there is already a theme file referenced.`,
);
logger.info(`Please manually add the following style file to your configuration:`);
logger.info(` ${assetPath}`);
Expand Down
Loading