create-application-template 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.husky/pre-commit CHANGED
@@ -1,3 +1,5 @@
1
1
  npm run lint:fix
2
2
  npm run stylelint:fix
3
+ # use below if you wish to use .css (see README.md "styles")
4
+ # npm run stylelint:css:fix
3
5
  npm run test
package/.stylelintrc.js CHANGED
@@ -3,6 +3,9 @@ module.exports = {
3
3
  'stylelint-config-standard',
4
4
  'stylelint-config-recess-order',
5
5
  ],
6
+ // NOTE remove customSyntax and use "npm stylelint:css"
7
+ // if you wish to use .css (see README.md "styles")
8
+ customSyntax: 'postcss-styled-components',
6
9
  ignoreFiles: [],
7
10
  rules: {
8
11
  'selector-class-pattern': null,
package/README.md CHANGED
@@ -62,6 +62,19 @@ css linting rules are in `.stylelintrc.js`; install the Stylelint pluggin if usi
62
62
  npm run stylelint
63
63
  ```
64
64
 
65
+ ## styles
66
+ styling is done using the style-components module, but straight CSS is supported
67
+
68
+ after instillation it is recommended to proceed using styled-components or CSS, but not both
69
+
70
+ if you proceed with styled-components:
71
+ - remove the single `.css` example in `/src/styles/`
72
+ - that's it!
73
+
74
+ if you prefer CSS:
75
+ - alter `.stylintrc.js` and `.husky/pre-commint` per the files' notes
76
+ - remove `.ts` files from `/src/styles/` or "recreate" them in `.css`
77
+
65
78
  ## environmental settings
66
79
  access environmental variables in code like so
67
80
  ```
@@ -0,0 +1,12 @@
1
+ // turning font file imports into empty objects
2
+
3
+ module.exports = {
4
+ process() {
5
+ return {
6
+ code: 'module.exports = {}',
7
+ }
8
+ },
9
+ getCacheKey() {
10
+ return 'fontTransform'
11
+ },
12
+ }
package/jest.config.js CHANGED
@@ -36,6 +36,7 @@ module.exports = async () => {
36
36
  '^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': 'babel-jest',
37
37
  '^.+\\.css$': '<rootDir>/jest/cssTransform.js',
38
38
  '^.+\\.svg$': '<rootDir>/jest/svgTransform.js',
39
+ '^.+\\.woff2$': '<rootDir>/jest/fontTransform.js',
39
40
  },
40
41
  // transformIgnorePatterns: [
41
42
  // '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-application-template",
3
- "version": "0.8.1",
3
+ "version": "0.9.0",
4
4
  "description": "provides a configured application template for you to build upon",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -15,14 +15,17 @@
15
15
  "dev": "concurrently \"npm run test:watch\" \"npm run start\"",
16
16
  "lint": "eslint \"src/**/*.{js,jsx,ts,tsx,json}\"",
17
17
  "lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx,json}\"",
18
- "stylelint": "npx stylelint \"src/**/*.css\"",
19
- "stylelint:fix": "npx stylelint --fix \"src/**/*.css\"",
18
+ "stylelint": "npx stylelint \"src/**/*.{js,ts}\"",
19
+ "stylelint:fix": "npx stylelint --fix \"src/**/*.{js,ts}\"",
20
+ "stylelint:css": "npx stylelint \"src/**/*.css\"",
21
+ "stylelint:css:fix": "npx stylelint --fix \"src/**/*.css\"",
20
22
  "prepare": "husky"
21
23
  },
22
24
  "keywords": [
23
25
  "template",
24
26
  "react",
25
27
  "typescript",
28
+ "styled-components",
26
29
  "webpack",
27
30
  "jest",
28
31
  "eslint",
@@ -45,6 +48,7 @@
45
48
  "husky": "9.0.11",
46
49
  "react": "18.3.1",
47
50
  "react-dom": "18.3.1",
51
+ "styled-components": "6.1.12",
48
52
  "yargs": "17.7.2"
49
53
  },
50
54
  "devDependencies": {
@@ -62,6 +66,7 @@
62
66
  "@types/node": "20.12.12",
63
67
  "@types/react": "18.3.2",
64
68
  "@types/react-dom": "18.3.0",
69
+ "@types/styled-components": "5.1.34",
65
70
  "@types/webpack-env": "1.18.5",
66
71
  "@typescript-eslint/eslint-plugin": "6.5.0",
67
72
  "@typescript-eslint/parser": "6.5.0",
@@ -84,8 +89,10 @@
84
89
  "jest": "29.7.0",
85
90
  "jest-environment-jsdom": "29.7.0",
86
91
  "jest-extended": "4.0.2",
92
+ "jest-styled-components": "7.2.0",
87
93
  "jest-watch-typeahead": "2.2.2",
88
94
  "mini-css-extract-plugin": "2.9.0",
95
+ "postcss-styled-components": "0.2.1",
89
96
  "react-refresh": "0.14.2",
90
97
  "style-loader": "4.0.0",
91
98
  "stylelint": "16.5.0",
package/src/app.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ declare module '*.woff2'
1
2
  declare module '*.png'
2
3
  declare module '*.svg' {
3
4
  const content: string
@@ -1,8 +1,10 @@
1
1
  import { render, screen } from '@testing-library/react'
2
+ import 'jest-styled-components'
2
3
  import { App } from './App'
3
4
 
4
5
  test('renders title', () => {
5
6
  render(<App />)
6
7
 
8
+ expect(screen).toMatchSnapshot()
7
9
  expect(screen.getByText(/create application template/i)).toBeInTheDocument()
8
10
  })
@@ -1,25 +1,33 @@
1
- import '../styles/app.css'
2
- import logo from '../assets/cat.svg'
1
+ import { ThemeProvider } from 'styled-components'
2
+ import GlobalStyles from '../styles/Global'
3
+ import theme from '../styles/theme'
4
+ import * as app from '../styles/App.styled'
5
+ import { StyledLogo } from '../styles/Logo.styled'
6
+ import '../styles/env.css'
7
+ import cat from '../assets/cat.svg'
3
8
  import { Counter } from './Counter'
4
9
 
5
10
  export const App = () => {
6
11
  return (
7
- <div className='container--main'>
8
- <header className='header--wrapper'>
9
- <h1>Create Application Template</h1>
10
- <h2>Configured and under your control!</h2>
11
- <h2>Access the template <a href='https://www.npmjs.com/package/create-application-template' rel='noreferrer' target='_blank'>here</a>...</h2>
12
- </header>
13
- <section className='section--wrapper'>
14
- <code className='card--env'>[NODE_ENV={process.env.NODE_ENV}]</code>
15
- <code className='card--env'>[EXAMPLE={process.env.EXAMPLE}]</code>
16
- </section>
17
- <section className='section--wrapper'>
18
- <img src={logo} className='logo--app' alt='logo' />
19
- </section>
20
- <section className='section--wrapper'>
21
- <Counter />
22
- </section>
23
- </div>
12
+ <ThemeProvider theme={theme}>
13
+ <GlobalStyles />
14
+ <app.StyledContainer>
15
+ <app.StyledHeader>
16
+ <h1>Create Application Template</h1>
17
+ <h2>Configured and under your control!</h2>
18
+ <h2>Access the template <app.StyledLink href='https://www.npmjs.com/package/create-application-template' rel='noreferrer' target='_blank'>here</app.StyledLink>...</h2>
19
+ </app.StyledHeader>
20
+ <app.StyledSection>
21
+ <code className='card--env'>[NODE_ENV={process.env.NODE_ENV}]</code>
22
+ <code className='card--env'>[EXAMPLE={process.env.EXAMPLE}]</code>
23
+ </app.StyledSection>
24
+ <app.StyledSection>
25
+ <StyledLogo src={cat} alt='logo'/>
26
+ </app.StyledSection>
27
+ <app.StyledSection>
28
+ <Counter />
29
+ </app.StyledSection>
30
+ </app.StyledContainer>
31
+ </ThemeProvider>
24
32
  )
25
33
  }
@@ -1,9 +1,16 @@
1
1
  import { render, screen } from '@testing-library/react'
2
+ import 'jest-styled-components'
2
3
  import { userEvent } from '@testing-library/user-event'
4
+ import { ThemeProvider } from 'styled-components'
5
+ import theme from '../styles/theme'
3
6
  import { Counter } from './Counter'
4
7
 
5
8
  test('count increases per click', async () => {
6
- render(<Counter />)
9
+ render(
10
+ <ThemeProvider theme={theme}>
11
+ <Counter />
12
+ </ThemeProvider>
13
+ )
7
14
  const button = await screen.findByRole('button', { name: /count/i })
8
15
 
9
16
  const user = userEvent.setup()
@@ -13,3 +20,19 @@ test('count increases per click', async () => {
13
20
  expect(results).toBeArrayOfSize(1)
14
21
  expect(results).toIncludeAllMembers(['1'])
15
22
  })
23
+
24
+
25
+ test('styled with palette colors', async() => {
26
+ render(
27
+ <ThemeProvider theme={theme}>
28
+ <Counter />
29
+ </ThemeProvider>
30
+ )
31
+ const button = await screen.findByRole('button', { name: /count/i })
32
+
33
+ const { primary, background } = theme.colors.palette
34
+
35
+ expect(button).toMatchSnapshot()
36
+ expect(button).toHaveStyleRule('color', primary)
37
+ expect(button).toHaveStyleRule('background-color', background)
38
+ })
@@ -1,5 +1,5 @@
1
- import '../styles/counter.css'
2
1
  import { FC, useState } from 'react'
2
+ import { StyledCounter } from '../styles/Counter.styled'
3
3
 
4
4
  // NOTE update count then edit App.tsx... thanks
5
5
  // to ReactRefreshWebpackPlugin state is preserved
@@ -13,9 +13,9 @@ export const Counter: FC = (): JSX.Element => {
13
13
 
14
14
  return (
15
15
  <div>
16
- <button id='counter' onClick={handleClickCounter}>
16
+ <StyledCounter onClick={handleClickCounter}>
17
17
  count:&nbsp;{count}
18
- </button>
18
+ </StyledCounter>
19
19
  </div>
20
20
  )
21
21
  }
@@ -0,0 +1,56 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`renders title 1`] = `
4
+ {
5
+ "debug": [Function],
6
+ "findAllByAltText": [Function],
7
+ "findAllByDisplayValue": [Function],
8
+ "findAllByLabelText": [Function],
9
+ "findAllByPlaceholderText": [Function],
10
+ "findAllByRole": [Function],
11
+ "findAllByTestId": [Function],
12
+ "findAllByText": [Function],
13
+ "findAllByTitle": [Function],
14
+ "findByAltText": [Function],
15
+ "findByDisplayValue": [Function],
16
+ "findByLabelText": [Function],
17
+ "findByPlaceholderText": [Function],
18
+ "findByRole": [Function],
19
+ "findByTestId": [Function],
20
+ "findByText": [Function],
21
+ "findByTitle": [Function],
22
+ "getAllByAltText": [Function],
23
+ "getAllByDisplayValue": [Function],
24
+ "getAllByLabelText": [Function],
25
+ "getAllByPlaceholderText": [Function],
26
+ "getAllByRole": [Function],
27
+ "getAllByTestId": [Function],
28
+ "getAllByText": [Function],
29
+ "getAllByTitle": [Function],
30
+ "getByAltText": [Function],
31
+ "getByDisplayValue": [Function],
32
+ "getByLabelText": [Function],
33
+ "getByPlaceholderText": [Function],
34
+ "getByRole": [Function],
35
+ "getByTestId": [Function],
36
+ "getByText": [Function],
37
+ "getByTitle": [Function],
38
+ "logTestingPlaygroundURL": [Function],
39
+ "queryAllByAltText": [Function],
40
+ "queryAllByDisplayValue": [Function],
41
+ "queryAllByLabelText": [Function],
42
+ "queryAllByPlaceholderText": [Function],
43
+ "queryAllByRole": [Function],
44
+ "queryAllByTestId": [Function],
45
+ "queryAllByText": [Function],
46
+ "queryAllByTitle": [Function],
47
+ "queryByAltText": [Function],
48
+ "queryByDisplayValue": [Function],
49
+ "queryByLabelText": [Function],
50
+ "queryByPlaceholderText": [Function],
51
+ "queryByRole": [Function],
52
+ "queryByTestId": [Function],
53
+ "queryByText": [Function],
54
+ "queryByTitle": [Function],
55
+ }
56
+ `;
@@ -1,4 +1,7 @@
1
- button#counter {
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`styled with palette colors 1`] = `
4
+ .c0 {
2
5
  height: 40px;
3
6
  padding: 10px;
4
7
  font-size: 18px;
@@ -9,6 +12,14 @@ button#counter {
9
12
  transition-duration: 0.5s;
10
13
  }
11
14
 
12
- button#counter:hover {
15
+ .c0:hover {
13
16
  border-radius: 20px;
14
17
  }
18
+
19
+ <button
20
+ class="c0"
21
+ >
22
+ count: 
23
+ 0
24
+ </button>
25
+ `;
package/src/index.html CHANGED
@@ -7,7 +7,7 @@
7
7
  <meta
8
8
  name='Create Application Template'
9
9
  content='provides a configured application template for you to build upon'
10
- keywords='template, react, typescript, webpack, jest, eslint, stylelint, javascript'
10
+ keywords='template, react, typescript, styled-components, webpack, jest, eslint, stylelint, javascript'
11
11
  />
12
12
  <title><%= htmlWebpackPlugin.options.title %></title>
13
13
  </head>
package/src/index.tsx CHANGED
@@ -1,6 +1,5 @@
1
1
  import { StrictMode } from 'react'
2
2
  import { createRoot } from 'react-dom/client'
3
- import './styles/index.css'
4
3
  import { App } from './components/App'
5
4
 
6
5
  const container = document.getElementById('root')
@@ -0,0 +1,27 @@
1
+ import { styled } from 'styled-components'
2
+
3
+ export const StyledContainer = styled.div(({ theme }) => `
4
+ display: flex;
5
+ flex-direction: column;
6
+ align-items: center;
7
+ justify-content: center;
8
+ min-height: 100vh;
9
+ font-size: max(1em, 18px);
10
+ color: ${theme.colors.palette.primary};
11
+ background-color: ${theme.colors.palette.background};
12
+ `)
13
+
14
+ export const StyledHeader = styled.header `
15
+ text-align: center;
16
+ `
17
+
18
+ export const StyledSection = styled.section `
19
+ display: flex;
20
+ flex-direction: column;
21
+ margin: 2vh;
22
+ `
23
+
24
+ export const StyledLink = styled.a(({ theme }) => `
25
+ color: ${theme.colors.palette.primary};
26
+ opacity: 0.6;
27
+ `)
@@ -0,0 +1,16 @@
1
+ import { styled } from 'styled-components'
2
+
3
+ export const StyledCounter = styled.button(({ theme }) => `
4
+ height: 40px;
5
+ padding: 10px;
6
+ font-size: 18px;
7
+ color: ${theme.colors.palette.primary};
8
+ background-color: ${theme.colors.palette.background};
9
+ border: 1px solid ${theme.colors.palette.primary};
10
+ border-radius: 8px;
11
+ transition-duration: 0.5s;
12
+
13
+ &:hover {
14
+ border-radius: 20px;
15
+ }
16
+ `)
@@ -0,0 +1,18 @@
1
+ import { createGlobalStyle } from 'styled-components'
2
+ import Exo2 from '../fonts/Exo2-Regular.woff2'
3
+
4
+ const GlobalStyles = createGlobalStyle`
5
+ @font-face {
6
+ font-family: '${({ theme }) => theme.font}';
7
+ src: url('${Exo2}') format('woff2');
8
+ }
9
+
10
+ body {
11
+ margin: 0;
12
+ font-family: '${({ theme }) => theme.font}', sans-serif;
13
+ -webkit-font-smoothing: antialiased;
14
+ -moz-osx-font-smoothing: grayscale;
15
+ }
16
+ `
17
+
18
+ export default GlobalStyles
@@ -0,0 +1,27 @@
1
+ import { styled, keyframes } from 'styled-components'
2
+
3
+ const logoAnimation = keyframes`
4
+ 0% {
5
+ opacity: 0.2;
6
+ transform: scale(0.8);
7
+ }
8
+
9
+ 50% {
10
+ opacity: 1.0;
11
+ transform: scale(1.2);
12
+ }
13
+
14
+ 100% {
15
+ opacity: 0.2;
16
+ transform: scale(0.8);
17
+ }
18
+ `
19
+
20
+ export const StyledLogo = styled.img`
21
+ height: 240px;
22
+ pointer-events: none;
23
+
24
+ @media (prefers-reduced-motion: no-preference) {
25
+ animation: ${logoAnimation} infinite 10s ease;
26
+ }
27
+ `
@@ -0,0 +1,11 @@
1
+ /* NOTE example of how .css works in this project (see README.md "styles") */
2
+
3
+ code {
4
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
5
+ monospace;
6
+ }
7
+
8
+ .card--env {
9
+ margin: 0.4vh;
10
+ filter: brightness(0.8);
11
+ }
@@ -0,0 +1,12 @@
1
+ const theme = {
2
+ font: 'exo2',
3
+ colors: {
4
+ palette: {
5
+ background: '#454145',
6
+ primary: '#cec2eb',
7
+ },
8
+ get link() { return this.palette.primary },
9
+ },
10
+ }
11
+
12
+ export default theme
package/tsconfig.json CHANGED
@@ -21,6 +21,7 @@
21
21
  "@types/react-dom",
22
22
  "@types/jest",
23
23
  "@types/webpack-env",
24
+ "@types/styled-components",
24
25
  "jest-extended",
25
26
  "@testing-library/jest-dom"
26
27
  ],
@@ -1,58 +0,0 @@
1
- .container--main {
2
- display: flex;
3
- flex-direction: column;
4
- align-items: center;
5
- justify-content: center;
6
- min-height: 100vh;
7
- font-size: max(1em, 18px);
8
- color: #cec2eb;
9
- background-color: #454145;
10
- }
11
-
12
- .header--wrapper {
13
- text-align: center;
14
- }
15
-
16
- .section--wrapper {
17
- display: flex;
18
- flex-direction: column;
19
- margin: 2vh;
20
- }
21
-
22
- .logo--app {
23
- height: 240px;
24
- pointer-events: none;
25
- }
26
-
27
- @media (prefers-reduced-motion: no-preference) {
28
- .logo--app {
29
- animation: logo--app-pulse infinite 10s ease;
30
- }
31
- }
32
-
33
- @keyframes logo--app-pulse {
34
- 0% {
35
- opacity: 0.2;
36
- transform: scale(0.8);
37
- }
38
-
39
- 50% {
40
- opacity: 1.0;
41
- transform: scale(1.2);
42
- }
43
-
44
- 100% {
45
- opacity: 0.2;
46
- transform: scale(0.8);
47
- }
48
- }
49
-
50
- .card--env {
51
- margin: 0.4vh;
52
- filter: brightness(0.8);
53
- }
54
-
55
- a {
56
- color: #cec2eb;
57
- opacity: 0.6;
58
- }
@@ -1,16 +0,0 @@
1
- @font-face {
2
- font-family: 'exo2-regular';
3
- src: url('../fonts/Exo2-Regular.woff2');
4
- }
5
-
6
- body {
7
- margin: 0;
8
- font-family: 'exo2-regular', sans-serif;
9
- -webkit-font-smoothing: antialiased;
10
- -moz-osx-font-smoothing: grayscale;
11
- }
12
-
13
- code {
14
- font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
15
- monospace;
16
- }