├── .editorconfig
├── .gitignore
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── bin
└── clarion
├── lib
├── clarion.js
├── commands
│ ├── add.js
│ ├── config.js
│ ├── new.js
│ └── remove.js
├── data
│ ├── newProject.js
│ ├── newProjectQuestions.js
│ ├── projectData.js
│ └── styleContentData.js
├── services
│ ├── configService.js
│ ├── directoryService.js
│ ├── fileService.js
│ ├── logService.js
│ ├── projectService.js
│ └── shellService.js
└── taskManager.js
├── package-lock.json
├── package.json
├── src
├── clarion.ts
├── commands
│ ├── add.ts
│ ├── new.ts
│ └── remove.ts
├── data
│ ├── newProject.ts
│ ├── projectData.ts
│ └── styleContentData.ts
└── services
│ ├── configService.ts
│ ├── directoryService.ts
│ ├── fileService.ts
│ ├── logService.ts
│ ├── projectService.ts
│ └── shellService.ts
├── tests
├── commands
│ ├── add.spec.ts
│ └── new.spec.ts
└── services
│ ├── configService.spec.ts
│ └── projectDataService.spec.ts
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = tab
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
6 |
7 | ## Our Standards
8 |
9 | Examples of behavior that contributes to creating a positive environment include:
10 |
11 | * Using welcoming and inclusive language
12 | * Being respectful of differing viewpoints and experiences
13 | * Gracefully accepting constructive criticism
14 | * Focusing on what is best for the community
15 | * Showing empathy towards other community members
16 |
17 | Examples of unacceptable behavior by participants include:
18 |
19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances
20 | * Trolling, insulting/derogatory comments, and personal or political attacks
21 | * Public or private harassment
22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission
23 | * Other conduct which could reasonably be considered inappropriate in a professional setting
24 |
25 | ## Our Responsibilities
26 |
27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
28 |
29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
30 |
31 | ## Scope
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
34 |
35 | ## Enforcement
36 |
37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at burton@breakstuff.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
38 |
39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
40 |
41 | ## Attribution
42 |
43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
44 |
45 | [homepage]: http://contributor-covenant.org
46 | [version]: http://contributor-covenant.org/version/1/4/
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 break-stuff
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Clarion
2 |
3 |
4 |
5 |
6 |
7 | ## A CSS and Design System Framework for well crafted applications.
8 |
9 | _Check out the official Documentation here: [projectclarion.com](http://projectclarion.com)_
10 |
11 | ## Installation
12 |
13 | Install [Node.js](https://nodejs.org/), if you don't already have it installed.
14 |
15 | In your terminal or command prompt type:
16 |
17 | ```bash
18 | npm install -g clarion
19 | - or -
20 | yarn global add clarion
21 | ```
22 |
23 | ## Start a New Project
24 |
25 | ```bash
26 | clarion new
27 | ```
28 |
29 | Answer a few questions about you would like to configure your project and it will be scaffolded out for you.
30 |
31 | Your dependencies will also automatically be installed!
32 |
33 | ## Run Your New Project
34 |
35 | After your dependencies are installed you can run your project.
36 |
37 | ```bash
38 | cd ProjectName
39 | npm run dev
40 | ```
41 |
42 | ## About Your New Project
43 |
44 | The default project is configured with [SASS](http://sass-lang.com/) using the `.scss` syntax and [webpack](https://webpack.js.org/) as the compiler and module manager.
45 |
46 | The project architecture implements the Clarion Style Architecture.
47 |
48 | ```bash
49 | MyProject/
50 | |
51 | |--build/
52 | |
53 | |--src/
54 | | |--sass/
55 | | | |--00_Abstracts/ # Variables, Functions, Mixins, and Placeholders
56 | | | |
57 | | | |--01_Base/ # Resets/Normalize, Typography Rules, Etc.
58 | | | | |--index.scss # Manifest File
59 | | | |
60 | | | |--02_Vendors/ # Style sheets provided by a third party such as themes or plug-ins
61 | | | | |--index.scss # Manifest File
62 | | | |
63 | | | |--03_Elements/ # Styles for HTML tags, such as a form label, an input or a button
64 | | | | |--index.scss # Manifest File
65 | | | |
66 | | | |--04_Components/ # Cards, Carousels, and Navbars
67 | | | | |--index.scss # Manifest File
68 | | | |
69 | | | |--05_Layouts/ # Grid System, Header, Footer, and Sidebars
70 | | | | |--index.scss # Manifest File
71 | | | |
72 | | | |--06_Pages/ # Page specific styles
73 | | | | |--index.scss # Manifest File
74 | | | |
75 | | | |--07_Utilities/ # Utilities and Helper Classes
76 | | | | |--index.scss # Manifest File
77 | | | |
78 | | | |--styles.scss/ # Main Sass Manifest
79 | | |
80 | | |--scripts/
81 | | |--components/ # Component-Specific Scripts
82 | | |--services/ # Reusable Functionality
83 | | |--main.js
84 | |
85 | |--index.html
86 | |--package.json
87 | |--postcss.config.js
88 | |--webpack.config.js
89 | ```
90 |
91 | ## Adding a New File
92 |
93 | Additional style files can easily be manged through the CLI as well.
94 |
95 | ### Usage
96 |
97 | ```bash
98 | clarion add
99 | ```
100 |
101 | #### Example
102 |
103 | ```bash
104 | clarion add element headings
105 | ```
106 |
107 | This will create the file _headings.scss in the 03_Elements directory as well as add "@import '_headings.scss'" import statement to the directory manifest file so it can be included in your final CSS file.
108 |
109 | ## Removing a File
110 |
111 | Similar to adding a file, removing files can also be done through the CLI.
112 |
113 | ### Usage
114 |
115 | ```bash
116 | clarion remove
117 | ```
118 |
119 | #### Example
120 |
121 | ```bash
122 | clarion remove element headings
123 | ```
124 |
125 | This will remove the file _headings.scss in the 03_Elements directory as well as remove "@import '_headings.scss'" import statement from the directory manifest file.
126 |
127 | ## Building Your Project
128 |
129 | To build your application for final use, run the build command.
130 |
131 | ```bash
132 | npm run build
133 | ```
134 |
135 | The final compiled JavaScript and CSS file are in build directory in the root of your project.
136 |
137 | ## Options
138 |
139 | These are options you can run when initializing you project.
140 |
141 | ## Project Content
142 |
143 | | Option | Description |
144 | | --- | --- |
145 | | Starter Project | generate the style architecture, the style framework, as well as any task runners/bundlers and optimizers needed to begin developing a web application.
146 | | Styles Only | generate the style architecture only (great for integrating into frameworks) |
147 | | Architecture Only | generate a the style architecture without any of the start-up files |
148 |
149 | ## Style Format
150 |
151 | | Option | Description |
152 | | --- | --- |
153 | | [SCSS](https://sass-lang.com/) | files are in .scss format |
154 | | [SASS](https://sass-lang.com/) | files are in .sass format |
155 | | [LESS](http://lesscss.org/) | files are in .less format |
156 |
157 | ## Task Runners and Bundlers
158 |
159 | | Option | Description |
160 | | --- | --- |
161 | | [Webpack](https://webpack.js.org/) | configure project for WebPack bundler |
162 | | [Parcel](https://parceljs.org/) | configure project for Parcel bundler |
163 | | [Gulp](https://gulpjs.com/) | configure project for Gulp task runner |
164 | | [Grunt](https://gruntjs.com/) | configure project for Grunt task runner |
165 |
166 | ## Changelog
167 |
168 | 3.8.4 - Fix color palette.
169 |
170 | 3.8.3 - Updated pipeline config files to handle 'less' and 'sass' configurations better.
171 |
172 | 3.8.1 - Fix Grunt build
173 |
174 | 3.8.0 - Miscellaneous bug fixes and added mixins such as: `z-index` mixin, updated default color pallet for accessibility, `$content-width` variable, font families variables are now a map and use the `font` mixin, media queries now use `rem`s instead of `px`s, and spacing mixins now follow standard CSS patterns.
175 |
176 | 3.7.1 - Fixed bug in `Pow` function for some bundlers/task runners for decimals.
177 |
178 | 3.7.0 - Added [display mixins](https://projectclarion.com/framework/documentation/mixins/display.html) - `full-width`, `full-height`, `full-screen`, and `screen-reader-only`
179 |
180 | 3.6.0 - Added `important` parameter on mixins
181 |
182 | 3.5.1 - Updated spacing variable to be more inline with naming convention
183 |
184 | 3.5.0 - Add [border mixin](https://projectclarion.com/framework/documentation/mixins/border.html)
185 |
186 | 3.4.0 - Fix [padding and margin mixin](https://projectclarion.com/framework/documentation/mixins/spacing.html) parameter order
187 |
188 | 3.4.0 - Fix [directory creation](https://projectclarion.com/cli/documentation/add.html#adding-directories) logic
189 |
190 | 3.2.2 - Fix CleanWebpackPlugin error for WebPack projects.
191 |
192 | 3.2.1 - Fix color functions to handle "black" and "white" values
193 |
194 | 3.2.0 - Streamlined new project setup.
195 |
196 | 3.1.0 - Updated variables, added new color contrast logic, and fixed SASS file references.
197 |
198 | 3.0.2 - Fixed file reference error in SCSS.
199 |
200 | 3.0.1 - Added additional border radius mixins and fixed some error messages.
201 |
202 | 3.0.0 - Added style framework for SASS and SCSS.
203 |
204 | 2.1.0 - Added a default configuration option and some bug fixes.
205 |
206 | 2.0.1 - Updated documentation.
207 |
208 | 2.0.0 - Added new CLI interface.
209 |
210 | 1.1.2 - Fixed hot reloading for Webpack.
211 |
212 | 1.1.1 - Added ability to add new Directories [via the CLI](https://projectclarion.com/documentation/architecture/).
213 |
214 | 1.0.3 - Replaced failing 'extract-text-webpack-plugin' with 'mini-css-extract-plugin' for Webpack 4.
215 |
216 | 1.0.1 - Fixed an type-o in the Grunt project.
217 |
218 | 1.0.0 - Final testing and added documentation via markdown files in each directory.
219 |
220 | 0.9.2 - Fixed bugs in SASS projects.
221 |
222 | 0.9.1 - Fixed Webpack build error.
223 |
224 | 0.9.0 - Refactored to use a better templating system and added unit tests.
225 |
226 | 0.8.7 - Updated documentation to include new site URL and install instructions.
227 |
228 | 0.8.6 - Temporarily removed "extract-text-webpack-plugin" as it is currently incompatible with Webpack v4.
229 |
230 | 0.8.5 - Updated Webpack project for changes in version 4.
231 |
232 | 0.8.1 - Added option for Parcel project creation.
233 |
234 | 0.7.1 - Added missing dependency for Gulp project.
235 |
236 | 0.7.0 - Revised dependency management so the latest packages are always installed, added Grunt, and added 'pixrem' to postcss.
237 |
238 | 0.6.1 - Fixed error in gulpfile.js.
239 |
240 | 0.6.0 - Modified add feature to find any directory name rather than only those in the Clarion Style Architecture.
241 |
242 | 0.5.0 - Renamed 02_Themes to 02_Vendors.
243 |
244 | 0.4.1 - Added link to documentation site.
245 |
--------------------------------------------------------------------------------
/bin/clarion:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | require('../lib/clarion.js');
--------------------------------------------------------------------------------
/lib/clarion.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | return new (P || (P = Promise))(function (resolve, reject) {
4 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 | step((generator = generator.apply(thisArg, _arguments || [])).next());
8 | });
9 | };
10 | Object.defineProperty(exports, "__esModule", { value: true });
11 | const commander = require("commander");
12 | const inquirer_1 = require("inquirer");
13 | const newProject_1 = require("./data/newProject");
14 | const new_1 = require("./commands/new");
15 | const add_1 = require("./commands/add");
16 | const remove_1 = require("./commands/remove");
17 | const configService_1 = require("./services/configService");
18 | commander
19 | .version("3.8.4")
20 | .usage("");
21 | commander
22 | .command("new")
23 | .description('Create a new project')
24 | .action(() => __awaiter(this, void 0, void 0, function* () {
25 | let projectName = '';
26 | let pipeline = '';
27 | const projectStartResponse = yield inquirer_1.prompt(newProject_1.starterQuestions.projectStart);
28 | const newProject = new new_1.NewProject();
29 | if (projectStartResponse.projectStart === 'Manual Configuration') {
30 | const projectTypeResponse = yield inquirer_1.prompt(newProject_1.starterQuestions.projectType);
31 | if (projectTypeResponse.projectType === 'Starter Project') {
32 | const projectNameResponse = yield inquirer_1.prompt(newProject_1.starterQuestions.projectName);
33 | const pipelineResponse = yield inquirer_1.prompt(newProject_1.starterQuestions.pipeline);
34 | projectName = projectNameResponse.projectName;
35 | pipeline = pipelineResponse.pipeline;
36 | }
37 | const styleFormatResponses = yield inquirer_1.prompt(newProject_1.starterQuestions.styleFormat);
38 | newProject.init(projectTypeResponse.projectType, projectName, styleFormatResponses.styleFormat, pipeline);
39 | }
40 | else {
41 | const projectNameResponse = yield inquirer_1.prompt(newProject_1.starterQuestions.projectName);
42 | newProject.init('default', projectNameResponse.projectName, 'SCSS', 'Webpack');
43 | }
44 | }));
45 | commander
46 | .command('add [filename]')
47 | .description('Use "add " to add a style sheet to a specific directory || Use "add " to add a style sheet to current directory')
48 | .action((dir, filename) => {
49 | let add = new add_1.Add();
50 | if (dir === 'directory') {
51 | add.addNewDirectory(filename);
52 | }
53 | else {
54 | if (filename)
55 | add.addFileToSpecifiedDirectory(dir, filename);
56 | else
57 | add.addFileToCurrentDirectory(dir);
58 | }
59 | });
60 | commander
61 | .command('mkdir ')
62 | .description('Add new style directory to architecture')
63 | .action((foldername) => {
64 | let add = new add_1.Add();
65 | add.addNewDirectory(foldername);
66 | });
67 | commander
68 | .command('remove [filename]')
69 | .description('Use "add " to add a style sheet to a specific directory || Use "add " to add a style sheet to current directory')
70 | .action((dir, filename) => {
71 | let remove = new remove_1.Remove();
72 | if (filename)
73 | remove.removeFileFromSpecifiedDirectory(dir, filename);
74 | else
75 | remove.removeFileFromCurrentDirectory(dir);
76 | });
77 | commander
78 | .command('config')
79 | .description('Configure Clarion to your development environment')
80 | .action(() => {
81 | let configService = new configService_1.ConfigService();
82 | configService.updateConfigInfo();
83 | });
84 | commander.parse(process.argv);
85 |
--------------------------------------------------------------------------------
/lib/commands/add.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | const fileService_1 = require("../services/fileService");
4 | const logService_1 = require("../services/logService");
5 | const directoryService_1 = require("../services/directoryService");
6 | const configService_1 = require("../services/configService");
7 | class Add {
8 | constructor() {
9 | this._fileService = new fileService_1.FileService();
10 | this._logService = new logService_1.LogService();
11 | this._directoryService = new directoryService_1.DirectoryService();
12 | this._configService = new configService_1.ConfigService();
13 | this._config = this._configService.getConfigData();
14 | }
15 | addFileToCurrentDirectory(fileName) {
16 | if (!this._fileService.getManifestFile("./")) {
17 | this._logService.warning("Sorry, this is not a directory you can add styles to or you may be missing parameters.");
18 | }
19 | else {
20 | this.processNewFile(".", fileName);
21 | }
22 | }
23 | addNewDirectory(folderName) {
24 | let extension = this._fileService.getFileExtension("/");
25 | let rootDirectory = this._directoryService.findStyleRootDirectory();
26 | this._directoryService.createDirectory(`${rootDirectory}/${folderName}`);
27 | this._fileService.saveFile(`${rootDirectory}/${folderName}/index.${extension}`, "");
28 | this._fileService.addFileToManifest(`@import './${folderName}/index${this._fileService.getImportExtension(extension)}`, `${rootDirectory}/styles.${extension}`, true);
29 | }
30 | addFileToSpecifiedDirectory(dir, fileName) {
31 | let directoryName = this._directoryService.findDirectoryByName(dir);
32 | if (directoryName) {
33 | let pathToDirectory = this._directoryService.findDirectory(directoryName);
34 | if (pathToDirectory) {
35 | this.processNewFile(pathToDirectory, fileName);
36 | }
37 | else {
38 | this._logService.warning("Sorry, the directory you specified was not found.");
39 | }
40 | }
41 | else {
42 | this._directoryService.promptForMissingDirectory()
43 | .then(directory => this.addFileToSpecifiedDirectory(directory, fileName));
44 | }
45 | }
46 | processNewFile(pathToDirectory, fileName) {
47 | let extension = this._fileService.getFileExtension(pathToDirectory);
48 | let newFile = this.getNewFile(fileName, extension);
49 | let manifestFile = `${pathToDirectory}/${this._fileService.getManifestFile(pathToDirectory)}`;
50 | if (!this._fileService.fileExists(`${pathToDirectory}/${newFile}`)) {
51 | let pathToRoot = this.getPathToRoot(fileName);
52 | let importStatement = this._config.importAbstracts &&
53 | !pathToDirectory.includes("00_Abstracts")
54 | ? `@import '${pathToRoot}00_Abstracts/index${this._fileService.getImportExtension(extension)}`
55 | : "";
56 | this._fileService.saveFile(`${pathToDirectory}/${newFile}`, importStatement);
57 | if (this._config.addToManifest)
58 | this._fileService.addFileToManifest(extension === 'sass' || extension === 'scss' ? fileName : newFile, manifestFile, false);
59 | }
60 | else {
61 | this._logService.warning(newFile + " already exists.");
62 | }
63 | }
64 | getNewFile(fileName, extension) {
65 | let directories = fileName.split("/");
66 | if (directories.length > 1) {
67 | directories[directories.length - 1] = `_${directories[directories.length - 1]}.${extension}`;
68 | return directories.join("/");
69 | }
70 | return `_${fileName}.${extension}`;
71 | }
72 | getPathToRoot(fileName) {
73 | let pathDepth = fileName.split("/").length;
74 | let pathToRoot = "../";
75 | for (let i = 1; i < pathDepth; i++) {
76 | pathToRoot += "../";
77 | }
78 | return pathToRoot;
79 | }
80 | }
81 | exports.Add = Add;
82 |
--------------------------------------------------------------------------------
/lib/commands/config.js:
--------------------------------------------------------------------------------
1 | // import { ILogService, LogService } from "../services/logService";
2 | // import { IConfigService, ConfigService } from "../services/configService";
3 | // export interface IConfig {
4 | // updateConfig(): void;
5 | // }
6 | // export class Config implements IConfig {
7 | // _logger: ILogService = new LogService();
8 | // _configService: IConfigService = new ConfigService();
9 | // updateConfig(): void {
10 | // let config = {
11 | // paths: {
12 | // styles: "./src",
13 | // },
14 | // format: {
15 | // styles: "scss",
16 | // },
17 | // addToManifest: true,
18 | // importAbstracts: true
19 | // };
20 | // // switch (program.args.length) {
21 | // // case 1:
22 | // // this._logger.warning('Please be sure to include the configuration property and value or initialize a config file using the "init" keyword.')
23 | // // break;
24 | // // case 2:
25 | // // this.initializeConfig();
26 | // // break;
27 | // // case 3:
28 | // // this._configService.saveConfig(program.args[1], program.args[2]);
29 | // // break;
30 | // // default:
31 | // // this._logger.warning('Sorry, we were not able to process your request.');
32 | // // break;
33 | // // }
34 | // }
35 | // initializeConfig(): void {
36 | // if (program.args[1].toLowerCase() === 'init') {
37 | // this._configService.saveConfig();
38 | // } else {
39 | // this._logger.warning('Please be sure to include the configuration property and value');
40 | // }
41 | // }
42 | // }
43 |
--------------------------------------------------------------------------------
/lib/commands/new.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | const newProject_1 = require("../data/newProject");
4 | const fileService_1 = require("../services/fileService");
5 | const projectService_1 = require("../services/projectService");
6 | const logService_1 = require("../services/logService");
7 | const directoryService_1 = require("../services/directoryService");
8 | const shellService_1 = require("../services/shellService");
9 | const projectData_1 = require("../data/projectData");
10 | const styleContentData_1 = require("../data/styleContentData");
11 | class NewProject {
12 | constructor() {
13 | this._fileService = new fileService_1.FileService();
14 | this._logService = new logService_1.LogService();
15 | this._directoryService = new directoryService_1.DirectoryService();
16 | this._shellService = new shellService_1.ShellService();
17 | this._styleFileRootPath = '';
18 | }
19 | init(projectType, projectName, styleFormat, pipeline) {
20 | this._projectType = projectType;
21 | this._projectName = projectName;
22 | this._styleFormat = styleFormat;
23 | this._pipeline = pipeline;
24 | this._projectService = new projectService_1.ProjectDataService(pipeline, styleFormat);
25 | this.createNewProject();
26 | }
27 | createNewProject() {
28 | if (this._projectType !== newProject_1.newProject.options.projectType.architectureOnly
29 | && this._projectType !== newProject_1.newProject.options.projectType.stylesOnly) {
30 | this.createScriptScaffolding();
31 | this.createTaskRunner();
32 | this.createPackageJson();
33 | this.createIndexHtml();
34 | }
35 | this.createStyleScaffolding();
36 | this.addStyleFramework();
37 | this.displayStartupInstructions();
38 | }
39 | createScriptScaffolding() {
40 | let extension = this._styleFormat.toLowerCase();
41 | this._styleFileRootPath = `./src/${extension}/styles.${extension}`;
42 | let mainContents = this._pipeline === newProject_1.newProject.options.pipeline.webpack ? `import '../${extension}/styles.${extension}';` : '';
43 | if (this._projectName) {
44 | this._directoryService.createDirectory(this._projectName);
45 | }
46 | projectData_1.projectData.projectDirectories.forEach(x => {
47 | this._directoryService.createDirectory(x.replace('%%projectName%%', this._projectName));
48 | });
49 | this._fileService.saveFile(`./${this._projectName}/src/scripts/main.js`, mainContents);
50 | }
51 | createStyleScaffolding() {
52 | let extension = this._styleFormat.toLowerCase();
53 | this.createStyleRootDirectory(extension);
54 | let importStatements = this.createStyleDirectories(extension);
55 | this.createRootManifest(extension, importStatements);
56 | }
57 | createStyleRootDirectory(extension) {
58 | this._styleRootPath = `./${extension}`;
59 | if (this._projectType !== newProject_1.newProject.options.projectType.architectureOnly
60 | && this._projectType !== newProject_1.newProject.options.projectType.stylesOnly) {
61 | this._styleRootPath = `./${this._projectName}/src/${extension}`;
62 | }
63 | this._directoryService.createDirectory(this._styleRootPath);
64 | }
65 | createStyleDirectories(extension) {
66 | let importStatements = '';
67 | projectData_1.projectData.styleDirectories.forEach(styleDirectory => {
68 | this._directoryService.createDirectory(`${this._styleRootPath}/${styleDirectory.name}`);
69 | this._fileService.saveFile(`${this._styleRootPath}/${styleDirectory.name}/index.${extension}`, '');
70 | this._fileService.saveFile(`${this._styleRootPath}/${styleDirectory.name}/README.md`, styleDirectory.readMe);
71 | importStatements += `@import './${styleDirectory.name}/index${this._fileService.getImportExtension(extension)}\n`;
72 | });
73 | return importStatements;
74 | }
75 | createRootManifest(extension, importStatements) {
76 | this._fileService.saveFile(`${this._styleRootPath}/styles.${extension}`, importStatements);
77 | }
78 | createPackageJson() {
79 | projectData_1.projectData.packageJson.name = this.convertToKebabCase(this._projectName);
80 | projectData_1.projectData.packageJson.scripts = this._projectData.projectCommands;
81 | this._fileService.saveFile(`./${this._projectName}/package.json`, JSON.stringify(projectData_1.projectData.packageJson, null, '\t'));
82 | this._shellService.installNPMDependencies(this._projectName, this._projectData.devDependencies, true);
83 | }
84 | convertToKebabCase(text) {
85 | return text.replace(/\s+/g, '-')
86 | .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
87 | .toLowerCase();
88 | }
89 | createTaskRunner() {
90 | this._projectData = this._projectService.getProjectData(this._projectName);
91 | }
92 | createIndexHtml() {
93 | let isParcel = this._pipeline === newProject_1.newProject.options.pipeline.parcel;
94 | let jsDir = isParcel ? './src/scripts/main.js' : './dist/scripts.js';
95 | let cssDir = isParcel ? this._styleFileRootPath : './dist/styles.css';
96 | let contents = this._projectService.getHtmlTemplate(cssDir, jsDir);
97 | this._fileService.saveFile(`./${this._projectName}/index.html`, contents);
98 | }
99 | displayStartupInstructions() {
100 | if (this._projectType !== newProject_1.newProject.options.projectType.architectureOnly
101 | && this._projectType !== newProject_1.newProject.options.projectType.stylesOnly) {
102 | this._logService.info('\nTo get started run the following command:');
103 | if (this._projectName)
104 | this._logService.info(`cd ${this._projectName}`);
105 | this._logService.info('npm run dev');
106 | }
107 | }
108 | addStyleFramework() {
109 | if (this._projectType !== newProject_1.newProject.options.projectType.architectureOnly) {
110 | this._directoryService.createDirectory(`${this._styleRootPath}/00_Abstracts/mixins`);
111 | this._directoryService.createDirectory(`${this._styleRootPath}/00_Abstracts/functions`);
112 | styleContentData_1.styleContent
113 | .filter(x => x.format === this._styleFormat.toLowerCase())
114 | .forEach(x => x.styles
115 | .forEach(y => this._fileService.saveFile(`${this._styleRootPath}/${y.file}`, y.content)));
116 | }
117 | }
118 | }
119 | exports.NewProject = NewProject;
120 |
--------------------------------------------------------------------------------
/lib/commands/remove.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | const fileService_1 = require("../services/fileService");
4 | const logService_1 = require("../services/logService");
5 | const directoryService_1 = require("../services/directoryService");
6 | class Remove {
7 | constructor() {
8 | this._fileService = new fileService_1.FileService();
9 | this._logService = new logService_1.LogService();
10 | this._directoryService = new directoryService_1.DirectoryService();
11 | }
12 | removeFileFromCurrentDirectory(fileName) {
13 | if (!this._fileService.getManifestFile('./')) {
14 | this._logService.warning('Sorry, this is not a directory you can remove styles from or you may be missing parameters.');
15 | }
16 | else {
17 | this.processFileRemoval('.', fileName);
18 | }
19 | }
20 | removeFileFromSpecifiedDirectory(dir, fileName) {
21 | let directoryName = this._directoryService.findDirectoryByName(dir);
22 | if (directoryName) {
23 | let pathToDirectory = this._directoryService.findDirectory(directoryName);
24 | if (pathToDirectory) {
25 | this.processFileRemoval(pathToDirectory, fileName);
26 | }
27 | else {
28 | this._logService.warning("Sorry, the directory you specified was not found.");
29 | }
30 | }
31 | else {
32 | this._directoryService.promptForMissingDirectory()
33 | .then(directory => this.removeFileFromSpecifiedDirectory(directory, fileName));
34 | }
35 | }
36 | processFileRemoval(pathToDirectory, fileName) {
37 | let extension = this._fileService.getFileExtension(pathToDirectory);
38 | let fileToRemove = `_${fileName}.${extension}`;
39 | let manifestFile = `${pathToDirectory}/${this._fileService.getManifestFile(pathToDirectory)}`;
40 | this._fileService.removeFile(`${pathToDirectory}/${fileToRemove}`);
41 | this._fileService.removeFileFromManifest(extension === 'sass' || extension === 'scss' ? fileName : fileToRemove, manifestFile);
42 | }
43 | }
44 | exports.Remove = Remove;
45 |
--------------------------------------------------------------------------------
/lib/data/newProject.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.starterQuestions = {
4 | projectStart: [
5 | {
6 | type: "list",
7 | name: "projectStart",
8 | message: "Start with default settings or would you like to customize your setup?",
9 | choices: ["Default (Starter Project, SCSS, Webpack)", "Manual Configuration"]
10 | }
11 | ],
12 | projectType: [
13 | {
14 | type: "list",
15 | name: "projectType",
16 | message: "What can we get you started with?",
17 | choices: ["Starter Project", "Styles Only", "Architecture Only"]
18 | }
19 | ],
20 | projectName: [
21 | {
22 | type: "input",
23 | name: "projectName",
24 | message: "Project Name:",
25 | validate: (value) => value.length > 0 || "Project Name is required."
26 | }
27 | ],
28 | styleFormat: [
29 | {
30 | type: "list",
31 | name: "styleFormat",
32 | message: "What style format would you like to use?",
33 | choices: ["SCSS", "SASS", "LESS"]
34 | }
35 | ],
36 | pipeline: [
37 | {
38 | type: "list",
39 | name: "pipeline",
40 | message: "What bundler or task-runner would you like to use?",
41 | choices: ["Webpack", "Parcel", "Gulp", "Grunt"]
42 | }
43 | ]
44 | };
45 | exports.newProject = {
46 | options: {
47 | projectType: {
48 | starter: "Starter Project",
49 | stylesOnly: "Styles Only",
50 | architectureOnly: "Architecture Only"
51 | },
52 | styleFormat: {
53 | scss: "SCSS",
54 | sass: "SASS",
55 | less: "LESS"
56 | },
57 | pipeline: {
58 | webpack: "Webpack",
59 | parcel: "Parcel",
60 | gulp: "Gulp",
61 | grunt: "Grunt"
62 | }
63 | }
64 | };
65 |
--------------------------------------------------------------------------------
/lib/data/newProjectQuestions.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.newProjectQuestions = [
4 | {
5 | type: 'input',
6 | name: 'projectName',
7 | message: 'Project Name:',
8 | validate: value => value.length > 0 || 'Project Name is required.'
9 | },
10 | {
11 | type: 'list',
12 | name: 'projectType',
13 | message: 'What can we get you started with?',
14 | choices: ['Starter Project', 'Styles Only', 'Architecture Only']
15 | },
16 | {
17 | type: 'list',
18 | name: 'styleFormat',
19 | message: 'What style format would you like to use?',
20 | choices: ['SCSS', 'SASS', 'LESS']
21 | },
22 | {
23 | type: 'list',
24 | name: 'pipeline',
25 | message: 'What bundler or task-runner would you like to use?',
26 | choices: ['Webpack', 'Parcel', 'Gulp', 'Grunt']
27 | }
28 | ];
29 |
--------------------------------------------------------------------------------
/lib/data/projectData.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.projectData = {
4 | styleDirectories: [
5 | {
6 | name: "00_Abstracts",
7 | readMe: '# Abstracts\n\nThis folder is for your style tools and helpers used across the project. Your reusable code such as global variables, functions, mixins and placeholders should be put in here.\n\nThe code contained in this folder should not be code that outputs CSS directly.\n\nWith larger projects you may want to break this into subdirectories like variables, functions, and mixins. Subdirectories are supported in the Clarion CLI.'
8 | },
9 | {
10 | name: "01_Base",
11 | readMe: '# Base\n\nThis folder holds the boilerplate code for the project. You would add your reset files and typographic rules. Keep in mind that most front-end frameworks like Bootstrap and Foundation already have their own CSS resets built into their styles, so additional resets may not be necessary.'
12 | },
13 | {
14 | name: "02_Vendors",
15 | readMe: '# Vendors\n\nThe Themes folder contains third-party themes for your website and for things like styles for plugins. This folder has been added higher in the architecture so that if you would like to create customizations, you can do so in the subsequent folders like Components, Layouts, and Pages. This will allow you to override the theme\'s rules without modifying the theme directly and ruining the integrity of the code.'
16 | },
17 | {
18 | name: "03_Elements",
19 | readMe: '# Elements\n\nThe Elements folder is for styling specific elements such as links, buttons, form inputs, and header tags. These are the smallest building blocks in the web and cannot be broken up into smaller parts. Browsers, by default, have their own styling in place for these elements, but tend to be inconsistent. Because of this, adding a reset to the 01_Base directory or adding one to the build pipeline is recommended.'
20 | },
21 | {
22 | name: "04_Components",
23 | readMe: '# Components\n\nComponents are groups of elements. This can be things like a search box, navbar, or carousel. These groups of elements together have a specific purpose.'
24 | },
25 | {
26 | name: "05_Layouts",
27 | readMe: '# Layouts\n\nThis folder contains everything that takes part in laying out the web site or application. These could be containers used for organizing elements and components within them like like a header, footer, or sidebar. This could also be used for your grid-system.'
28 | },
29 | {
30 | name: "06_Pages",
31 | readMe: '# Pages\n\nThis folder is for any page-specific styles, if you have any. Some sites may have custom styling for the Home page or the Contact Us page.'
32 | },
33 | {
34 | name: "07_Utilities",
35 | readMe: '# Utilities\n\nThe Utilities are used to create overrides or call out specific rules for an elements or components. For example, you could have a class for making text bold or aligning it to the right. The rule of thumb is to make it specific and make it simple.'
36 | }
37 | ],
38 | styleTypes: [
39 | "less",
40 | "sass",
41 | "scss"
42 | ],
43 | projectDirectories: [
44 | './%%projectName%%/dist',
45 | './%%projectName%%/src',
46 | './%%projectName%%/src/scripts',
47 | './%%projectName%%/src/scripts/components',
48 | './%%projectName%%/src/scripts/services'
49 | ],
50 | packageJson: {
51 | name: '',
52 | version: "0.1.0",
53 | description: "",
54 | main: "index.js",
55 | scripts: {},
56 | keywords: [],
57 | author: "",
58 | license: "ISC",
59 | },
60 | clarionConfig: {
61 | paths: {
62 | styles: './src',
63 | scripts: './src'
64 | },
65 | format: {
66 | styles: 'scss',
67 | scripts: 'js'
68 | },
69 | addToManifest: "true",
70 | importAbstracts: "true"
71 | },
72 | postCssConfig: {
73 | plugins: {
74 | autoprefixer: {},
75 | cssnano: {}
76 | }
77 | },
78 | grunt: {
79 | configFile: 'gruntfile.js',
80 | devDependencies: [
81 | "autoprefixer",
82 | "cssnano",
83 | "grunt",
84 | "grunt-postcss",
85 | "grunt-contrib-watch",
86 | "grunt-contrib-connect",
87 | "cross-env"
88 | ],
89 | lessDependencies: [
90 | 'grunt-contrib-less'
91 | ],
92 | sassDependencies: [
93 | 'grunt-sass',
94 | "node-sass"
95 | ],
96 | npmCommands: {
97 | "dev": "cross-env NODE_ENV=development grunt dev",
98 | "build": "cross-env NODE_ENV=production grunt build"
99 | },
100 | configContents: `module.exports = function(grunt) {
101 | grunt.initConfig({
102 | pkg: grunt.file.readJSON("package.json"),
103 | %%styleFormat%%: {
104 | dist: {
105 | files: {
106 | "dist/styles.css": "src/%%extension%%/styles.%%extension%%"
107 | }
108 | }
109 | },
110 | watch: {
111 | css: {
112 | files: "**/*.%%extension%%",
113 | tasks: ["%%styleFormat%%", "postcss"],
114 | options: {
115 | livereload: true
116 | }
117 | }
118 | },
119 | postcss: {
120 | options: {
121 | map: true,
122 | processors: [
123 | require("autoprefixer")(),
124 | require("cssnano")()
125 | ]
126 | },
127 | dist: {
128 | src: "dist/*.css"
129 | }
130 | },
131 | connect: {
132 | server: {
133 | options: {
134 | port: 8000,
135 | hostname: "*",
136 | open: true,
137 | onCreateServer: function(server, connect, options) {}
138 | }
139 | }
140 | }
141 | });
142 | grunt.loadNpmTasks("grunt-%%styleFormat%%");
143 | grunt.loadNpmTasks("grunt-postcss");
144 | grunt.loadNpmTasks("grunt-contrib-watch");
145 | grunt.loadNpmTasks("grunt-contrib-connect");
146 | grunt.registerTask("dev", ["%%styleFormat%%", "postcss", "connect", "watch"]);
147 | grunt.registerTask("build", ["%%styleFormat%%", "postcss"]);
148 | };
149 | `
150 | },
151 | gulp: {
152 | configFile: 'gulpfile.js',
153 | devDependencies: [
154 | "autoprefixer",
155 | "cssnano",
156 | "cross-env",
157 | "gulp",
158 | "gulp-postcss",
159 | "gulp-webserver",
160 | "gulp-sourcemaps"
161 | ],
162 | lessDependencies: [
163 | 'gulp-less'
164 | ],
165 | sassDependencies: [
166 | 'gulp-sass'
167 | ],
168 | npmCommands: {
169 | "dev": "cross-env NODE_ENV=development gulp dev",
170 | "build": "cross-env NODE_ENV=production gulp build"
171 | },
172 | configContents: `'use strict';
173 |
174 | const { src, watch, dest, parallel } = require("gulp");
175 | const %%styleFormat%% = require("gulp-%%styleFormat%%");
176 | const postcss = require("gulp-postcss");
177 | const webserver = require("gulp-webserver");
178 | const sourcemaps = require("gulp-sourcemaps");
179 |
180 | function localServer() {
181 | return src(".").pipe(
182 | webserver({
183 | livereload: true,
184 | directoryListing: false,
185 | open: true
186 | })
187 | );
188 | }
189 |
190 | function css() {
191 | return src("./src/%%extension%%/styles.%%extension%%")
192 | .pipe(sourcemaps.init())
193 | .pipe(%%styleFormat%%().on("error", %%styleFormat%%.logError))
194 | .pipe(postcss())
195 | .pipe(sourcemaps.write("./"))
196 | .pipe(dest("./dist"));
197 | }
198 |
199 | exports.dev = function() {
200 | localServer();
201 | css();
202 | watch("./src/%%extension%%/**/*.%%extension%%", css);
203 | };
204 |
205 | exports.build = function() {
206 | parallel(css);
207 | };`
208 | },
209 | parcel: {
210 | configFile: null,
211 | devDependencies: [
212 | "autoprefixer",
213 | "cssnano",
214 | "cross-env",
215 | ],
216 | lessDependencies: [],
217 | sassDependencies: [],
218 | npmCommands: {
219 | "dev": "cross-env NODE_ENV=development parcel index.html",
220 | "build": "cross-env NODE_ENV=production parcel build index.html -d ./dist"
221 | },
222 | configContents: null
223 | },
224 | webpack: {
225 | configFile: 'webpack.config.js',
226 | devDependencies: [
227 | "autoprefixer",
228 | "css-loader",
229 | "style-loader",
230 | "cross-env",
231 | "mini-css-extract-plugin",
232 | "postcss-loader",
233 | "webpack",
234 | "webpack-cli",
235 | "webpack-dev-server",
236 | "cssnano",
237 | "clean-webpack-plugin",
238 | "html-webpack-plugin",
239 | ],
240 | lessDependencies: [
241 | 'less-loader'
242 | ],
243 | sassDependencies: [
244 | 'node-sass',
245 | 'sass-loader'
246 | ],
247 | npmCommands: {
248 | "dev": "cross-env NODE_ENV=development webpack-dev-server --progress --open --hot --mode development",
249 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules -p --mode production"
250 | },
251 | configContents: `const path = require('path');
252 | const {CleanWebpackPlugin} = require('clean-webpack-plugin');
253 | const HtmlWebpackPlugin = require('html-webpack-plugin');
254 | const MiniCssExtractPlugin = require("mini-css-extract-plugin");
255 | const webpack = require('webpack');
256 |
257 | module.exports = {
258 | entry: './src/scripts/main.js',
259 | output: {
260 | filename: 'scripts.js',
261 | path: path.resolve(__dirname, 'dist')
262 | },
263 | devServer: {
264 | contentBase: path.resolve(__dirname, '.'),
265 | inline: true,
266 | hot: true
267 | },
268 | module: {
269 | rules: [
270 | {
271 | test: /\.(scss|sass)$/,
272 | use: [
273 | MiniCssExtractPlugin.loader,
274 | 'css-loader',
275 | 'sass-loader',
276 | 'postcss-loader'
277 | ]
278 | }
279 | ]
280 | },
281 | plugins: [
282 | new CleanWebpackPlugin(),
283 | new MiniCssExtractPlugin({
284 | filename: "styles.css"
285 | }),
286 | new HtmlWebpackPlugin({
287 | filename: 'index.html',
288 | template: 'index.html'
289 | }),
290 | new webpack.NamedModulesPlugin(),
291 | new webpack.HotModuleReplacementPlugin()
292 | ]
293 | }`
294 | },
295 | indexHtml: `
296 |
297 |
298 |
299 |
300 | Clarion
301 |
302 |
303 |
304 |
305 |
306 |
Congratulations! You did it!
307 |
308 |
This page is intentionally ugly!
309 |
Create some styles and start having fun!
310 |
311 |
Modify headings by creating a headings file:
312 | clarion add element headings
313 |
314 |
Modify lists by creating a lists file:
315 | clarion add element lists
316 |
317 |
318 |
Here is some sweet, sweet dummy text to play with
319 |
Bacon ipsum dolor amet ball tip hamburger adipisicing chicken prosciutto non. Shoulder venison quis, flank leberkas turducken dolor tenderloin nostrud. Ham strip steak swine boudin tempor. Shoulder doner mollit brisket. Cillum strip steak picanha kevin et culpa commodo lorem pastrami.
320 |
Bacon ipsum
321 |
Elit est ut prosciutto sausage spare ribs tenderloin pork loin cupidatat brisket dolore pancetta occaecat. Elit meatball leberkas burgdoggen ham hock beef ribs ut bresaola voluptate pork belly eu culpa t-bone esse pork loin. Quis corned beef minim eu velit excepteur. Quis consequat bacon corned beef boudin chicken anim sint labore kielbasa do ipsum sed. Frankfurter laborum turkey do brisket elit exercitation adipisicing doner irure jowl leberkas. Culpa flank kevin drumstick sunt porchetta kielbasa pancetta picanha ea dolor ad. Irure tongue in pork belly alcatra sirloin mollit reprehenderit tri-tip dolore.
322 |
Tri-tip Meatball Pork Belly
323 |
Id tri-tip meatball pork belly, mollit burgdoggen leberkas cupim. Do nostrud sirloin jerky capicola ham hock deserunt, spare ribs pork belly boudin culpa salami in duis. Biltong ut aute chuck nostrud drumstick short ribs et ham hock in lorem. Prosciutto exercitation salami in enim. Laborum shoulder ribeye kielbasa exercitation bacon officia ut alcatra rump pork turkey. Excepteur ut voluptate, qui labore est pork chop pastrami hamburger cupim laborum doner shank.
Modify headings by creating a headings file:
362 | clarion add element headings
363 |
364 |
Modify lists by creating a lists file:
365 | clarion add element lists
366 |
367 |
368 |
Here is some sweet, sweet dummy text to play with
369 |
Bacon ipsum dolor amet ball tip hamburger adipisicing chicken prosciutto non. Shoulder venison quis, flank leberkas turducken dolor tenderloin nostrud. Ham strip steak swine boudin tempor. Shoulder doner mollit brisket. Cillum strip steak picanha kevin et culpa commodo lorem pastrami.
370 |
Bacon ipsum
371 |
Elit est ut prosciutto sausage spare ribs tenderloin pork loin cupidatat brisket dolore pancetta occaecat. Elit meatball leberkas burgdoggen ham hock beef ribs ut bresaola voluptate pork belly eu culpa t-bone esse pork loin. Quis corned beef minim eu velit excepteur. Quis consequat bacon corned beef boudin chicken anim sint labore kielbasa do ipsum sed. Frankfurter laborum turkey do brisket elit exercitation adipisicing doner irure jowl leberkas. Culpa flank kevin drumstick sunt porchetta kielbasa pancetta picanha ea dolor ad. Irure tongue in pork belly alcatra sirloin mollit reprehenderit tri-tip dolore.
372 |
Tri-tip Meatball Pork Belly
373 |
Id tri-tip meatball pork belly, mollit burgdoggen leberkas cupim. Do nostrud sirloin jerky capicola ham hock deserunt, spare ribs pork belly boudin culpa salami in duis. Biltong ut aute chuck nostrud drumstick short ribs et ham hock in lorem. Prosciutto exercitation salami in enim. Laborum shoulder ribeye kielbasa exercitation bacon officia ut alcatra rump pork turkey. Excepteur ut voluptate, qui labore est pork chop pastrami hamburger cupim laborum doner shank.