- Before contributing
- New Feature Checklist
- New Package Checklist
- New Package Dependency Checklist
- Objectives
- Framework Structure
- Docs
- Theme
- Documentation
- Release
- create a new component guide
- Playground
- TODO
- Don’t overcomplicate
- Don’t make things too abstract
- Use tslint, styles-lint to check the code style
- Use lifecycle interfaces
- Use default angular view encapsulation
- Use changeDetection: ChangeDetectionStrategy.OnPush where applicable
- Never forget document your changes add create some examples
- Write tests
- Create playground page per each new component/feature
- lint checks are passing
- tests are added/updated and passing
- showcase in the playground updated
- Styles variables added/updated
- tsdocs added/updated
- commit message is properly formatted
- for the override styles - registered in a list of overrides
- component *.theme registered in a list of component themes
- looks great on all default themes
- supports bidirectionality
- requires approval from several core team contributors
- add the package into bump-version.ts which bumps package version and its dependencies
- add the package external dependencies into rollup-config.ts which gives rollup capability build package correctly
- add the package into bundle.ts which build umd modules for our packages
- add the package into
JS_PACKAGES
inscripts/gulp/tasks/config.ts
which used to add es2015 bundles for our packages - add the package into packages-smoke application dependencies to verify it works properly in isolation.
- add the package into change-prefix.ts which builds our packages with custom prefix.
- run
npm run update-packages-smoke-lock
to update packages-smoke/package-lock.json and commit updated package lock
The aim of the project is to create a set of useful Angular modules which help to bootstrap the development.
We have to:
- make it modular
- publish it as npm package
- customizable color themes with HOT reload support
- create a library of custom layout components
- expanded documentation and guides
- replace ng2-bootstrap with ng-bootstrap
- get rid of jQuery
- follow Angular code style
- use Angular CLI
- docs - Documentation and framework website built on top on the framework
- src
- app - runner app for components playground
- playground - independent module with runnable examples for each feature
- backend - Small backend example
- framework - Framework itself, divided into npm packages
- theme -
@nebular/theme
npm package, main framework package - auth -
@nebular/auth
npm package, auth package (login, register, etc) - icons -
nebular-icons
npm package, cool icons font - security -
@nebular/security
npm package, security framework package
- theme -
Docs is a separate Angular application located right in this project in docs/
folder.
The pages structure is taken from structure.ts
file.
The components documentation is take from the component comment sections.
Runnable examples - an iframe to the same Angular application to a different route (/#/examples) where playground module
is connected.
In the build mode documentation and runnable examples are built in TWO separate apps and placed to docs/dist
for the docs website
and docs/dist/run
for the examples. This is done so that we can reference an example in an iframe avoiding "same page iframe policy" which won't allow
us to load the same page in the iframe on that page (and different pages starting only differentiated by #something
are considered as one page in some
browsers.
Theme module is the main framework module, consisting of:
- custom UI Kit components (layout, cards, tabs, etc)
- css-themes with hot reload support
- appearance overrides for 3rd party libraries.
Located in theme/components
.
Each component consists of the standard angular component structure + *.theme.scss
file,
which is a customizable part (customizable here means dependable on a specific theme variables) of component's styles.
Located in theme/services
.
Global theme services.
Located in theme/styles
- core/ - Common mixins and functions
- global/ - Root of the 3rd party components overrides and other global styles
- prebuilt/ - Technical files of which css themes will be compiled
- themes/ - built-in themes
- common/ - Shared components styles
- all.scss -Exports all themes' variables, theming engine and global styles
- components.scss - Exports all themes' variables and theming engine but DOES NOT export global styles (should be used in a component)
- globals.scss - Exports all global styles (overrides, components'
*.theme.scss
themes, fonts, etc) - themes.scss - All built-in themes
- theming.scss - Theme system engine
-
Problem Customizable themes support doesn't work good with angular, as encapsulated in framework components' styles can't access user app variables unless you make them non-encapsulated and export as scss-files). Thus, we need to ask a user to include the framework styles separately as global styles, so that it is possible to change SASS variables before the theme styles are processed.
-
Solution The solution is to separate component's styles into configurable (with SASS variables) and non-configurable (hardcoded) styles. Then place hardcoded styles into
*.component.scss
, and dynamic styles into*.theme.scss
. The*.theme
files will be included into one*theme
file with access to the theme variables. This file has to be included by the user into their project. -
Disadvantages
- We separate styles, thus it's hard to read the styles in the development mode.
- Theme styles are not encapsulated, basically are global styles.
-
Possible future solution
- CSS variables (currently lack of browsers support)
-
Problem We cannot change SCSS variables in the runtime as user change the theme (possible with CSS variables but browser support is quite limited).
-
Solution Thus, we need to build multiple instances of styles in the runtime and encapsulate each theme's bunch of styles under some .theme-name class:
.nb-theme-default { nb-layout { color: black; } } .nb-theme-red { nb-layout { color: red; } }
Then, by changing a css class on the root element (nb-layout) we can change the page appearance in the runtime.
- SCSS MAP
Moreover, to have an arbitrary amount of themes we need to store the variables as an
SCSS
. Then, each component' styles (user components' styles) needs to be wrapped intonb-install-component
mixing, which will be called in a loop for each theme, setting its own variables. Variables then accessible throughnb-theme(var-name)
function. Finally, example of such component will look like:@import '@nebular/theme/styles/component'; @include nb-install-component() { div { color: nb-theme(primary-fg); } }
- SCSS MAP
Moreover, to have an arbitrary amount of themes we need to store the variables as an
-
Disadvantages
- Double (triple, multiple) sizes of generated css file.
-
Possible future solution
- CSS variables
TBD
Nebular
- Add new js theme to the
theme/services
with variables for common settings, you can inherit them from an existing theme, indicating in propertybase
name of the theme or create new theme, update test. - Add new Theme to the
theme/styles/themes
also you can inherit from an existing theme, in anb-register-theme
specifying the name of the theme as the third parameter. - Import new theme to the
theme/styles/themes.scss
. - Add new Theme to the
theme/styles/prebuilt
. - Register a new Theme in the
playground/styles/themes.scss
. - For docs in the
docs/structure.ts
add item with new theme in section with nameThemes
. - Add new theme for
live-example-block
.
ngx-admin
- Register a new Theme in the
app/@theme/styles/themes.scss
- Add new js theme to the
app/@theme/styles
(variables for charts and etc.) for new Theme. - Import a new Theme to the
app/@theme/theme.module.ts
. - In
ThemeSwitcherListComponent
add item with new theme.
Documentation is generated by the custom generator built on top of @nebular/theme. You have to use typedoc everywhere for the documentation purpose.
Docs application splitted on the sections which you can find in the apps sidebar.
Each section contains some pages.
If you wanna add new page in the documentation, please, open structure.ts
file in the root of docs application and add new page in the required section:
{
type: 'page',
name: 'Awesom page',
children: [
... blocks
],
},
If it's completely new feature, maybe it would be better to create a new section:
{
type: 'section',
name: 'New super section',
children: [
... pages
],
},
Page can contain multiple blocks of the following types:
Renders plain markdown file from the articles
dir.
For example, if you wanna add getting started article you have to do the following:
- put
getting-started.md
file in thearticles
folder. - add markdown block to the page children:
{
type: 'block',
block: 'markdown',
source: 'getting-started.md',
},
If you have to render all the information about componend parsed with typedoc you have to use component blocks:
{
type: 'block',
block: 'component',
source: 'MyNewComponentName',
},
Tabbed component block will render component description splitted on the following tabs:
- Overview - This is typedoc comment above component
- Theme - Theme variables listed in the typedoc comment above component with
@styles
tag, for example:
/**
* ...
*
* @styles
*
* var1
* var2
*
* ...
*/
- API - parsing result of the typedoc above public methods and props
- Examples - live examples listed in the typedoc comment above component
When you're developing new funcitonality, please, always add some examples describing it. You have the following ways to add examples in your component documentation:
- Add raw code
- Display inline examples from playground
- Render live examples from playground
- Render stacked examples from palyground(live + inline)
If you wan't to describe small thing in two lines of code you can just add something similar in your typedoc comment:
```html
<my-component></my-component>
```
And don't forget specify language above your example.
Inline example is an example file from our playground. Let's see how can we add inline example on the page:
- Create example file in the playground folder. All files from playground folder will be coppied to the assets of the docs app.
- Add
@inline-example(my-component/my-component.component.html)
somewhere in your typedoc comment.
Also, if you wanna render all the component, not only one file from it, you can specify it's without file extension:
@inline-example(my-component/my-component.component)
in this case all the files with my-component.component
name will be rendered.
Live example it's just playground page rendered in the iframe. So, to be able to use it
you have to add example component in the playground and specify route for it.
Then you need to pass this route name in @live-example(my-super-route)
tag.
It's combination of the live and inline examples. When you add @example(my-example)
in your typedoc comment, docs'll try to find component with name my-example
and route with the same name and render them with switch.
To give the user capability switch between live and inline representation of the example.
- For major version, search for
@breaking-change
to make sure all breaking changes are covered.
To start a new release (publish the framework packages on NPM) you need:
- create a new release branch called
release:v1.0.2
npm run release:validate
- this will create ready for publishing packages in src/.lib then build prod & AOT builds of the playground app using prepared packages and then run e2e tests again it.- MANUALLY update a version in main ./package.json to a new one
npm run update-packages-smoke-lock
to updatepackages-smoke/package-lock.json
npm run version:bump
- update version in
package-lock.json
andpackages-smoke/package-lock.json
- update
docs/versions.json
:- When releasing minor/patch update (both LTS and current):
- Replace latest current or LTS version in
version.json
with currently released
- Replace latest current or LTS version in
- When releasing major update:
- Replace LTS version with latest mentioned in version.json
- Add currently released version
path
of the current version should be set to/nebular
, others to/nebular/<version-name>
- When releasing minor/patch update (both LTS and current):
- update
versions
array indocs/assets/ghspa.js
. It should include all versions fromdocs/versions.json
except currently released (latest).
npm run version:changelog
- fix/expand changelog manually
- push the branch, create PR, approve - merge
- pull the upstream (master or other version branch (e.g. 3.6.0, next))
- If publishing LTS release add
--tag=v<version>-lts
(for examplev3-lts
) to publish command inscripts/publish.sh:7
- In case of beta, rc or any other unstable release add
--tag=next
to publish command inscripts/publish.sh:7
npm run release
- run prepare & validate and finally publish the packages to NPM- create and push git tag
- create release on github
- publish docs
- Build docs for currently released version
- Copy
docs/dist
outside ofnebular/docs
directory - Loop over other versions mentioned in
docs/versions.json
:- Run
git checkout <version tag>
- Run
npm ci
- Run
npm run docs:prepare
- Run
npm run build -- docs --prod --base-href '/nebular/<version>/'
(for example--base-href '/nebular/3.6.1/'
) - Run
npm run docs:dirs
. - Rename
docs/dist
todocs/<version>
. - Copy renamed folder to the directory from step
13.2
.
- Run
- Checkout current version
- Run
npm install
- Remove
docs/dist
- Move resulting directory from step
13.2
to 'docs/dist'. - Run
npm run ngh -- --dir ./docs/dist
- add release notes to Nebular Releases
#ngx-admin development on the latest Nebular sources
rm -rf node_modules/@nebular
to remove the package installed- run
npm link
for each Nebular module in nebular/src/framework except for icons - make sure you don't have node_modules in Nebular project (this may cause an issue an issue the angular-cli)
- link Nebular in ngx-admin:
npm link @nebular/{auth,theme}
- run ngx-admin with corresponding flag
npm start -- --preserve-symlinks
#ngx-admin release
- update version
- create changelog
- create PR, approve, pull
- rebase sandbox on master, push
- rebase demo on master, push
- create a tag
- create github release
- build demo with npm run build:prod
- upload demo using
scp -r dist/ server_details
- create directory in
src/framework/theme/components/your-component
with following files:
your-component.component.ts (component file)
your-component.module.ts (module file)
your-component.component.html (optional, html file)
your-component.component.scss (optional, common styles for your component)
_your-component.component.theme.scss (optional, styles that depends on theme vars)
- register your component in framework
src/framework/theme/index.ts (add exports of your component and module)
src/framework/theme/styles/global/_components.scss (if you create _your-component.component.theme.scss you have to register mixin)
- tests
src/framework/theme/components/your-component/your-component.spec.ts if you want to test basic rendering
e2e/your-component.e2e-spec.ts if you need to test complex actions such as user interaction
- register your component in docs
add it to docs/structure.ts
create example usage of your component
src/playground/[with-layout|without-layout]/your-component/your-component-showcase.component.ts
run 'npm run gen:playground' to generate boilerplate code, such as modules, routes, etc.
your-component.component.ts (add line in docs section- * @stacked-example(Your component, your-component/your-component-showcase.component)
- after
npm run docs:serve
you can see your component athttp://localhost:4100/#/docs/components/your-component
Playground is a set of modules containing all Nebular examples.
It has two base directories: with-layout
and without-layout
. All components in with-layout
directory will be nested inside of nb-layout
component. Components from without-layout
directory will be direct children of router outlet. Put components into without-layout
directory, if they don't need to or can't be children of layout component, such as a layout itself.
Playground schematic generates all boilerplate code for you. Basically, after adding a new component, directive or service declaration, all needed modules and components routes will be generated or modified.
You can run it via 'npm run gen:playground' command.
Schematic goes through all playground directories deeply. For direct children of base playground directories, it generates feature and routing modules.
Each component, directive or service declaration found, will be declared in the closest module. Also for each component which has a routing module in directory schematic adds a route. Route path set to file name without extension. If a component is just a helper and shouldn't has it's own route, you can put in a subdirectory (typically './components').
Each module found will be added as a lazy route for closest parent module. Route path will be set to a module directory name.
Then schematic will collect all component routes and write list into ./src/app/playground-components.ts
(used by docs app).
- steps to start the development
- describe framework and demo dependencies
- create a new component guide
- usage guide
- move nebular-icons in separate repository