Skip to content

Commit c1ce833

Browse files
committed
1.0.0
0 parents  commit c1ce833

28 files changed

+1174
-0
lines changed

.gitignore

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.next
2+
.nova
3+
.env
4+
.env.local
5+
.env-custom-development
6+
.env-development
7+
.env-textile
8+
.env-production
9+
.DS_STORE
10+
DS_STORE
11+
yarn.lock
12+
node_modules
13+
dist
14+
analytics.txt
15+
package-lock.json
16+
17+
/**/*/.DS_STORE
18+
/**/*/node_modules
19+
/**/*/.next
20+
/**/*/.data

.prettierrc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"printWidth":180,
3+
"tabWidth":2,
4+
"useTabs":false,
5+
"semi":true,
6+
"singleQuote":true,
7+
"trailingComma":"es5",
8+
"bracketSpacing":true,
9+
"jsxBracketSameLine":false,
10+
"arrowParens":"always",
11+
"requirePragma":false,
12+
"insertPragma":false,
13+
"proseWrap":"preserve",
14+
"parser":"babel",
15+
"overrides": [
16+
{
17+
"files": "*.js",
18+
"options": {
19+
"parser": "babel"
20+
}
21+
}
22+
]
23+
}

README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# NEXT-SASS-STARTER
2+
3+
Why would I use this?
4+
5+
- Quickly start a project with TypeScript, SASS, and NextJS.
6+
- You want to make a website quickly.
7+
8+
### Setup (MacOS)
9+
10+
Start by cloning the repository, or by clicking on **Use this template** above.
11+
12+
Then run the server
13+
14+
```sh
15+
npm install
16+
npm run dev
17+
```
18+
19+
Go to `http://localhost:3005` in your browser of choice. Enjoy!
20+
21+
### Scripts
22+
23+
If you need to run node script without running the server, use this example to get started
24+
25+
```sh
26+
npm run script example
27+
```
28+
29+
### Env Variables
30+
31+
If you want to connect to a Postgres database, something I do all the time, provide the following `.env` file. `5432` is the default Postgres port.
32+
33+
```sh
34+
DOCUMENT_DATABASE_NAME=xxxx
35+
DOCUMENT_DATABASE_USERNAME=xxxx
36+
DOCUMENT_DATABASE_HOST=xxxx
37+
DOCUMENT_DATABASE_PORT=5432
38+
DOCUMENT_DATABASE_PASSWORD=xxxx
39+
```
40+
41+
### Contact
42+
43+
If you have questions ping me on Twitter, [@wwwjim](https://www.twitter.com/wwwjim).

app/head.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import DefaultMetaTags from '@components/DefaultMetaTags';
2+
3+
export default async function Head({ params }) {
4+
const title = 'example';
5+
const description = 'CHANGEME: description for your application using next-sass';
6+
const url = 'CHANGEME: your-production-url.tld';
7+
8+
// SUMMARY_LARGE_IMAGE: 1500x785
9+
return (
10+
<>
11+
<title>{title}</title>
12+
<DefaultMetaTags />
13+
<meta name="title" content={title} />
14+
<meta name="description" content={description} />
15+
16+
<meta property="og:type" content="website" />
17+
<meta property="og:url" content={url} />
18+
<meta property="og:title" content={title} />
19+
<meta property="og:description" content={description} />
20+
<meta property="og:image" content="" />
21+
22+
<meta property="twitter:card" content="summary_large_image" />
23+
<meta property="twitter:url" content={url} />
24+
<meta property="twitter:title" content={title} />
25+
<meta property="twitter:description" content={description} />
26+
<meta property="twitter:image" content="" />
27+
</>
28+
);
29+
}

app/layout.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function RootLayout({ children }: { children: React.ReactNode }) {
2+
return (
3+
<html lang="en">
4+
<body>{children}</body>
5+
</html>
6+
);
7+
}

app/page.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import '@root/global.scss';
2+
3+
import DefaultLayout from '@components/DefaultLayout';
4+
5+
export default async function Page(props) {
6+
return <DefaultLayout>Hello World</DefaultLayout>;
7+
}

common/http.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const REQUEST_HEADERS = {
2+
Accept: 'application/json',
3+
'Content-Type': 'application/json',
4+
};
5+
6+
const getHeaders = (key) => {
7+
return { ...REQUEST_HEADERS, Authorization: `Bearer ${key}` };
8+
};
9+
10+
export async function placeholder(key) {
11+
const response = await fetch('/api', {
12+
method: 'GET',
13+
headers: getHeaders(key),
14+
});
15+
16+
const json = await response.json();
17+
return json;
18+
}

common/server.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Cors from '@modules/cors';
2+
3+
export function initMiddleware(middleware) {
4+
return (req, res) =>
5+
new Promise((resolve, reject) => {
6+
middleware(req, res, (result) => {
7+
if (result instanceof Error) {
8+
return reject(result);
9+
}
10+
return resolve(result);
11+
});
12+
});
13+
}
14+
15+
export const cors = initMiddleware(
16+
Cors({
17+
methods: ['GET', 'POST', 'OPTIONS'],
18+
})
19+
);

common/utilities.ts

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
const hasOwn = {}.hasOwnProperty;
2+
const protocolAndDomainRE = /^(?:\w+:)?\/\/(\S+)$/;
3+
const localhostDomainRE = /^localhost[\:?\d]*(?:[^\:?\d]\S*)?$/;
4+
const nonLocalhostDomainRE = /^[^\s\.]+\.\S{2,}$/;
5+
6+
export const noop = () => {};
7+
8+
export const pluralize = (text, count) => {
9+
return count > 1 || count === 0 ? `${text}s` : text;
10+
};
11+
12+
export function toDateISOString(data: string) {
13+
const date = new Date(data);
14+
return date.toLocaleDateString('en-US', {
15+
weekday: 'long',
16+
day: 'numeric',
17+
month: 'long',
18+
year: 'numeric',
19+
});
20+
}
21+
22+
export const elide = (string, length = 140, emptyState = '...') => {
23+
if (isEmpty(string)) {
24+
return emptyState;
25+
}
26+
27+
if (string.length < length) {
28+
return string.trim();
29+
}
30+
31+
return `${string.substring(0, length)}...`;
32+
};
33+
34+
export function bytesToSize(bytes: number, decimals: number = 2) {
35+
if (bytes === 0) return '0 Bytes';
36+
37+
const k = 1000;
38+
const dm = decimals < 0 ? 0 : decimals;
39+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
40+
41+
const i = Math.floor(Math.log(bytes) / Math.log(k));
42+
43+
return `${(bytes / Math.pow(k, i)).toFixed(dm)} ${sizes[i]}`;
44+
}
45+
46+
export function isEmpty(text: any) {
47+
// NOTE(jim): If a number gets passed in, it isn't considered empty for zero.
48+
if (text === 0) {
49+
return false;
50+
}
51+
52+
if (!text) {
53+
return true;
54+
}
55+
56+
if (typeof text === 'object') {
57+
return true;
58+
}
59+
60+
if (text.length === 0) {
61+
return true;
62+
}
63+
64+
text = text.toString();
65+
66+
return Boolean(!text.trim());
67+
}
68+
69+
export function createSlug(text: any) {
70+
if (isEmpty(text)) {
71+
return 'untitled';
72+
}
73+
74+
const a = 'æøåàáäâèéëêìíïîòóöôùúüûñçßÿœæŕśńṕẃǵǹḿǘẍźḧ·/_,:;';
75+
const b = 'aoaaaaaeeeeiiiioooouuuuncsyoarsnpwgnmuxzh------';
76+
const p = new RegExp(a.split('').join('|'), 'g');
77+
78+
return text
79+
.toString()
80+
.toLowerCase()
81+
.replace(/\s+/g, '-') // Replace spaces with -
82+
.replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special chars
83+
.replace(/&/g, '-and-') // Replace & with 'and'
84+
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
85+
.replace(/\-\-+/g, '-') // Replace multiple - with single -
86+
.replace(/^-+/, '') // Trim - from start of text
87+
.replace(/-+$/, ''); // Trim - from end of text
88+
}
89+
90+
export function isUrl(string: any) {
91+
if (typeof string !== 'string') {
92+
return false;
93+
}
94+
95+
var match = string.match(protocolAndDomainRE);
96+
if (!match) {
97+
return false;
98+
}
99+
100+
var everythingAfterProtocol = match[1];
101+
if (!everythingAfterProtocol) {
102+
return false;
103+
}
104+
105+
if (localhostDomainRE.test(everythingAfterProtocol) || nonLocalhostDomainRE.test(everythingAfterProtocol)) {
106+
return true;
107+
}
108+
109+
return false;
110+
}
111+
112+
export function debounce<Args extends unknown[]>(fn: (...args: Args) => void, delay: number) {
113+
let timeoutID: number | undefined;
114+
let lastArgs: Args | undefined;
115+
116+
const run = () => {
117+
if (lastArgs) {
118+
fn(...lastArgs);
119+
lastArgs = undefined;
120+
}
121+
};
122+
123+
const debounced = (...args: Args) => {
124+
clearTimeout(timeoutID);
125+
lastArgs = args;
126+
timeoutID = window.setTimeout(run, delay);
127+
};
128+
129+
debounced.flush = () => {
130+
clearTimeout(timeoutID);
131+
};
132+
133+
return debounced;
134+
}
135+
136+
export function classNames(...args: any[]): string {
137+
var classes = [];
138+
139+
for (var i = 0; i < arguments.length; i++) {
140+
var arg = arguments[i];
141+
if (!arg) continue;
142+
143+
var argType = typeof arg;
144+
145+
if (argType === 'string' || argType === 'number') {
146+
classes.push(arg);
147+
} else if (Array.isArray(arg)) {
148+
if (arg.length) {
149+
var inner = classNames.apply(null, arg);
150+
if (inner) {
151+
classes.push(inner);
152+
}
153+
}
154+
} else if (argType === 'object') {
155+
if (arg.toString !== Object.prototype.toString) {
156+
classes.push(arg.toString());
157+
} else {
158+
for (var key in arg) {
159+
if (hasOwn.call(arg, key) && arg[key]) {
160+
classes.push(key);
161+
}
162+
}
163+
}
164+
}
165+
}
166+
167+
return classes.join(' ');
168+
}

components/DefaultLayout.module.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.body {
2+
color: red;
3+
}

0 commit comments

Comments
 (0)