Skip to content

Commit

Permalink
1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
jimmylee committed Aug 3, 2023
0 parents commit c1ce833
Show file tree
Hide file tree
Showing 28 changed files with 1,174 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.next
.nova
.env
.env.local
.env-custom-development
.env-development
.env-textile
.env-production
.DS_STORE
DS_STORE
yarn.lock
node_modules
dist
analytics.txt
package-lock.json

/**/*/.DS_STORE
/**/*/node_modules
/**/*/.next
/**/*/.data
23 changes: 23 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"printWidth":180,
"tabWidth":2,
"useTabs":false,
"semi":true,
"singleQuote":true,
"trailingComma":"es5",
"bracketSpacing":true,
"jsxBracketSameLine":false,
"arrowParens":"always",
"requirePragma":false,
"insertPragma":false,
"proseWrap":"preserve",
"parser":"babel",
"overrides": [
{
"files": "*.js",
"options": {
"parser": "babel"
}
}
]
}
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# NEXT-SASS-STARTER

Why would I use this?

- Quickly start a project with TypeScript, SASS, and NextJS.
- You want to make a website quickly.

### Setup (MacOS)

Start by cloning the repository, or by clicking on **Use this template** above.

Then run the server

```sh
npm install
npm run dev
```

Go to `http://localhost:3005` in your browser of choice. Enjoy!

### Scripts

If you need to run node script without running the server, use this example to get started

```sh
npm run script example
```

### Env Variables

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.

```sh
DOCUMENT_DATABASE_NAME=xxxx
DOCUMENT_DATABASE_USERNAME=xxxx
DOCUMENT_DATABASE_HOST=xxxx
DOCUMENT_DATABASE_PORT=5432
DOCUMENT_DATABASE_PASSWORD=xxxx
```

### Contact

If you have questions ping me on Twitter, [@wwwjim](https://www.twitter.com/wwwjim).
29 changes: 29 additions & 0 deletions app/head.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import DefaultMetaTags from '@components/DefaultMetaTags';

export default async function Head({ params }) {
const title = 'example';
const description = 'CHANGEME: description for your application using next-sass';
const url = 'CHANGEME: your-production-url.tld';

// SUMMARY_LARGE_IMAGE: 1500x785
return (
<>
<title>{title}</title>
<DefaultMetaTags />
<meta name="title" content={title} />
<meta name="description" content={description} />

<meta property="og:type" content="website" />
<meta property="og:url" content={url} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content="" />

<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={url} />
<meta property="twitter:title" content={title} />
<meta property="twitter:description" content={description} />
<meta property="twitter:image" content="" />
</>
);
}
7 changes: 7 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
7 changes: 7 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import '@root/global.scss';

import DefaultLayout from '@components/DefaultLayout';

export default async function Page(props) {
return <DefaultLayout>Hello World</DefaultLayout>;
}
18 changes: 18 additions & 0 deletions common/http.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const REQUEST_HEADERS = {
Accept: 'application/json',
'Content-Type': 'application/json',
};

const getHeaders = (key) => {
return { ...REQUEST_HEADERS, Authorization: `Bearer ${key}` };
};

export async function placeholder(key) {
const response = await fetch('/api', {
method: 'GET',
headers: getHeaders(key),
});

const json = await response.json();
return json;
}
19 changes: 19 additions & 0 deletions common/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Cors from '@modules/cors';

export function initMiddleware(middleware) {
return (req, res) =>
new Promise((resolve, reject) => {
middleware(req, res, (result) => {
if (result instanceof Error) {
return reject(result);
}
return resolve(result);
});
});
}

export const cors = initMiddleware(
Cors({
methods: ['GET', 'POST', 'OPTIONS'],
})
);
168 changes: 168 additions & 0 deletions common/utilities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
const hasOwn = {}.hasOwnProperty;
const protocolAndDomainRE = /^(?:\w+:)?\/\/(\S+)$/;
const localhostDomainRE = /^localhost[\:?\d]*(?:[^\:?\d]\S*)?$/;
const nonLocalhostDomainRE = /^[^\s\.]+\.\S{2,}$/;

export const noop = () => {};

export const pluralize = (text, count) => {
return count > 1 || count === 0 ? `${text}s` : text;
};

export function toDateISOString(data: string) {
const date = new Date(data);
return date.toLocaleDateString('en-US', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric',
});
}

export const elide = (string, length = 140, emptyState = '...') => {
if (isEmpty(string)) {
return emptyState;
}

if (string.length < length) {
return string.trim();
}

return `${string.substring(0, length)}...`;
};

export function bytesToSize(bytes: number, decimals: number = 2) {
if (bytes === 0) return '0 Bytes';

const k = 1000;
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

const i = Math.floor(Math.log(bytes) / Math.log(k));

return `${(bytes / Math.pow(k, i)).toFixed(dm)} ${sizes[i]}`;
}

export function isEmpty(text: any) {
// NOTE(jim): If a number gets passed in, it isn't considered empty for zero.
if (text === 0) {
return false;
}

if (!text) {
return true;
}

if (typeof text === 'object') {
return true;
}

if (text.length === 0) {
return true;
}

text = text.toString();

return Boolean(!text.trim());
}

export function createSlug(text: any) {
if (isEmpty(text)) {
return 'untitled';
}

const a = 'æøåàáäâèéëêìíïîòóöôùúüûñçßÿœæŕśńṕẃǵǹḿǘẍźḧ·/_,:;';
const b = 'aoaaaaaeeeeiiiioooouuuuncsyoarsnpwgnmuxzh------';
const p = new RegExp(a.split('').join('|'), 'g');

return text
.toString()
.toLowerCase()
.replace(/\s+/g, '-') // Replace spaces with -
.replace(p, (c) => b.charAt(a.indexOf(c))) // Replace special chars
.replace(/&/g, '-and-') // Replace & with 'and'
.replace(/[^\w\-]+/g, '') // Remove all non-word chars
.replace(/\-\-+/g, '-') // Replace multiple - with single -
.replace(/^-+/, '') // Trim - from start of text
.replace(/-+$/, ''); // Trim - from end of text
}

export function isUrl(string: any) {
if (typeof string !== 'string') {
return false;
}

var match = string.match(protocolAndDomainRE);
if (!match) {
return false;
}

var everythingAfterProtocol = match[1];
if (!everythingAfterProtocol) {
return false;
}

if (localhostDomainRE.test(everythingAfterProtocol) || nonLocalhostDomainRE.test(everythingAfterProtocol)) {
return true;
}

return false;
}

export function debounce<Args extends unknown[]>(fn: (...args: Args) => void, delay: number) {
let timeoutID: number | undefined;
let lastArgs: Args | undefined;

const run = () => {
if (lastArgs) {
fn(...lastArgs);
lastArgs = undefined;
}
};

const debounced = (...args: Args) => {
clearTimeout(timeoutID);
lastArgs = args;
timeoutID = window.setTimeout(run, delay);
};

debounced.flush = () => {
clearTimeout(timeoutID);
};

return debounced;
}

export function classNames(...args: any[]): string {
var classes = [];

for (var i = 0; i < arguments.length; i++) {
var arg = arguments[i];
if (!arg) continue;

var argType = typeof arg;

if (argType === 'string' || argType === 'number') {
classes.push(arg);
} else if (Array.isArray(arg)) {
if (arg.length) {
var inner = classNames.apply(null, arg);
if (inner) {
classes.push(inner);
}
}
} else if (argType === 'object') {
if (arg.toString !== Object.prototype.toString) {
classes.push(arg.toString());
} else {
for (var key in arg) {
if (hasOwn.call(arg, key) && arg[key]) {
classes.push(key);
}
}
}
}
}

return classes.join(' ');
}
3 changes: 3 additions & 0 deletions components/DefaultLayout.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.body {
color: red;
}
7 changes: 7 additions & 0 deletions components/DefaultLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import styles from '@components/DefaultLayout.module.scss';

import * as React from 'react';

export default function App(props) {
return <div className={styles.body}>{props.children}</div>;
}
11 changes: 11 additions & 0 deletions components/DefaultMetaTags.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function DefaultMetaTags() {
return (
<>
<meta httpEquiv="content-language" content="en-us" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-16x16.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-32x32.png" />
<link rel="shortcut icon" href="/favicon.ico" />
</>
);
}
21 changes: 21 additions & 0 deletions data/db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}

import knex from 'knex';

const ssl = process.env.EXAMPLE_DATABASE_HOST === '127.0.0.1' ? false : true;

const DB = knex({
client: 'pg',
connection: {
ssl: ssl,
port: Number(process.env.EXAMPLE_DATABASE_PORT),
host: process.env.EXAMPLE_DATABASE_HOST,
database: process.env.EXAMPLE_DATABASE_NAME,
user: process.env.EXAMPLE_DATABASE_USERNAME,
password: process.env.EXAMPLE_DATABASE_PASSWORD,
},
});

export default DB;
Loading

0 comments on commit c1ce833

Please sign in to comment.