diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..cf01b6ad4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +src/docs/* linguist-documentation +scripts/* linguist-documentation +gatsby-browser.js linguist-documentation +gatsby-config.js linguist-documentation +gatsby-node.js linguist-documentation +gatsby-ssr.js linguist-documentation +.travis/* linguist-documentation +config.js linguist-documentation diff --git a/.travis.yml b/.travis.yml index 0a3613911..ad4d6e410 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,12 @@ language: node_js -node_js: - - node -install: - - npm install -script: - - npm run build -after_script: - - test $TRAVIS_EVENT_TYPE = cron - && echo -e "\e[95mDeploying to Repository" - && chmod +x .travis/push.sh - && ./.travis/push.sh - - chmod +x .travis/forcepush.sh && ./.travis/forcepush.sh cache: directories: - - node_modules \ No newline at end of file + - node_modules +node_js: +- lts/* +script: +- npm run extractor +- npm run builder +after_success: +- chmod +x .travis/push.sh +- .travis/push.sh \ No newline at end of file diff --git a/.travis/forcepush.sh b/.travis/forcepush.sh deleted file mode 100644 index 54f15f5a5..000000000 --- a/.travis/forcepush.sh +++ /dev/null @@ -1,3 +0,0 @@ -if [[ $TRAVIS_COMMIT_MESSAGE == *"--force-build"* ]]; - then echo -e "\e[95mFORCE-DEPLOY: Deploying to Repository" && chmod +x .travis/push.sh && ./.travis/push.sh; -fi diff --git a/.travis/push.sh b/.travis/push.sh index a6c1eb6b1..fdd85ca67 100644 --- a/.travis/push.sh +++ b/.travis/push.sh @@ -12,8 +12,10 @@ commit_website_files() { git add * if [ $TRAVIS_EVENT_TYPE == "cron" ]; then git commit --message "Travis build: $TRAVIS_BUILD_NUMBER [cron]" + elif [ $TRAVIS_EVENT_TYPE == "api" ]; then + git commit --message "Travis build: $TRAVIS_BUILD_NUMBER [custom]" else - git commit --message "Travis build: $TRAVIS_BUILD_NUMBER [FORCED]" + git commit --message "Travis build: $TRAVIS_BUILD_NUMBER" fi fi fi diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0f6746904..45cbfd919 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,34 +1,43 @@ -### Snippet name +# Contribution guidelines -Brief description +**30 seconds of CSS** is a community effort, so feel free to contribute in any way you can. Every contribution helps! -#### HTML +Here's what you can do to help: -```html +- Submit [pull requests](https://github.com/30-seconds/30-seconds-of-css/pulls) with snippets and tests that you have created (see below for guidelines). +- [Open issues](https://github.com/30-seconds/30-seconds-of-css/issues/new) for things you want to see added or modified. +- Be part of the discussion by helping out with [existing issues](https://github.com/30-seconds/30-seconds-of-css/issues). +- Tag uncategorized snippets by adding the appropriate in the snippet's frontmatter in `tags`. +- Fix typos in existing snippets, improve snippet descriptions and explanations or provide better examples. -``` +### Snippet submission and Pull request guidelines -#### CSS - -```css -``` - -#### Demo - - - -#### Explanation - - - -#### Browser support - - - -⚠️ Caveat? - - - -- https://caniuse.com/#feat=some-feature - - +- **DO NOT MODIFY THE README.md FILE!** Make changes to individual snippet files. **Travis CI** will automatically build the `README.md` file when your pull request is merged. +- **Snippet filenames** must correspond to the title of the snippet. For example, if your snippet is titled `awesomeSnippet` the filename should be `awesomeSnippet.md`. + - Use `camelCase` or `kebab-case`, not `snake_case`. + - Avoid capitalization of words, except if the whole word is capitalized (e.g. `URL` should be capitalized in the filename and the snippet title). +- **Snippet metadata** must be included in all snippets in the form of frontmatter. + - All snippets must contain a title. + - All snippets must contain tags, prefixed with `tags:` and separated by commas (optional spaces in-between). + - Make sure the first tag in your snippet's tags is one of the main categories, as seen in the `README.md` file or the website. + - Snippet tags must include a difficulty setting (`begginer`, `intermediate` or `advanced`), preferrably at the end of the list. +- **Snippet titles** should be the same as the name of the function that is present in the snippet. + - All snippet titles must be prefixed with `title:` and be at the very first line of your snippet's frontmatter. + - Snippet titles must be unique (although if you cannot find a better title, just add some placeholder at the end of the filename and title and we will figure it out). + - Follow snippet titles with an empty line. +- **Snippet descriptions** must be short and to the point. Try to explain *what* the snippet does and *how* the snippet works and what Javascript features are used. Remember to include what functions you are using and why. + - Follow snippet descriptions with an empty line. +- **Snippet code** must be enclosed inside ` ```html `, ` ```css ` or ` ```js ` and ` ``` `. + - Remember to start your snippet's code on a new line below the opening backticks. + - Please use Javascript [Semi-Standard Style](https://github.com/Flet/semistandard). + - Try to keep your snippet's code short and to the point. Use modern techniques and features. Make sure to test your code before submitting. + - Try to make your snippet's name unique, so that it does not conflict with existing snippets. +- **Snippet explanations** should be written as lists of points, describing the implemented functionality. + - Use unordered lists if you have a few points, otherwise use an ordered list. + - If you have JavaScript functionality in your snippet, it might be worthwhile separating the explanation with it, by adding a new list or a horizontal line break (`---`). +- **Snippet browser support** should be specified as a list of links to https://www.caniuse.com/ features. + - Use the `#` next to the feature that you want in the website to get a link to it. +- Snippets should be short. If your snippet is long, you can still submit it, and we can help you shorten it or figure out ways to improve it. +- Snippets *should* solve real-world problems, no matter how simple. +- Snippets *should* be abstract enough to be applied to different scenarios. +- You can start creating a new snippet, by using the [snippet template](snippet-template.md) to format your snippets. diff --git a/_headers b/_headers new file mode 100644 index 000000000..4c2f41f08 --- /dev/null +++ b/_headers @@ -0,0 +1,4 @@ +[[headers]] +for = "/static/*" +[headers.values] +Cache-Control = "public, max-age=360000" \ No newline at end of file diff --git a/advanced.svg b/advanced.svg new file mode 100644 index 000000000..428312a3c --- /dev/null +++ b/advanced.svg @@ -0,0 +1 @@ + diff --git a/assets/30s-icon.png b/assets/30s-icon.png new file mode 100644 index 000000000..56350cc81 Binary files /dev/null and b/assets/30s-icon.png differ diff --git a/assets/NotoSans-Italic.ttf b/assets/NotoSans-Italic.ttf new file mode 100644 index 000000000..6d2c71c86 Binary files /dev/null and b/assets/NotoSans-Italic.ttf differ diff --git a/assets/NotoSans-Light.ttf b/assets/NotoSans-Light.ttf new file mode 100644 index 000000000..404ed0787 Binary files /dev/null and b/assets/NotoSans-Light.ttf differ diff --git a/assets/NotoSans-LightItalic.ttf b/assets/NotoSans-LightItalic.ttf new file mode 100644 index 000000000..4c338dba3 Binary files /dev/null and b/assets/NotoSans-LightItalic.ttf differ diff --git a/assets/NotoSans-Medium.ttf b/assets/NotoSans-Medium.ttf new file mode 100644 index 000000000..5dbefd372 Binary files /dev/null and b/assets/NotoSans-Medium.ttf differ diff --git a/assets/NotoSans-MediumItalic.ttf b/assets/NotoSans-MediumItalic.ttf new file mode 100644 index 000000000..3641525ea Binary files /dev/null and b/assets/NotoSans-MediumItalic.ttf differ diff --git a/assets/NotoSans-Regular.ttf b/assets/NotoSans-Regular.ttf new file mode 100644 index 000000000..0a01a062f Binary files /dev/null and b/assets/NotoSans-Regular.ttf differ diff --git a/assets/NotoSans-SemiBold.ttf b/assets/NotoSans-SemiBold.ttf new file mode 100644 index 000000000..8b7fd1302 Binary files /dev/null and b/assets/NotoSans-SemiBold.ttf differ diff --git a/assets/NotoSans-SemiBoldItalic.ttf b/assets/NotoSans-SemiBoldItalic.ttf new file mode 100644 index 000000000..a7e904c38 Binary files /dev/null and b/assets/NotoSans-SemiBoldItalic.ttf differ diff --git a/assets/RobotoMono-Italic.woff2 b/assets/RobotoMono-Italic.woff2 new file mode 100644 index 000000000..65d8c7b76 Binary files /dev/null and b/assets/RobotoMono-Italic.woff2 differ diff --git a/assets/RobotoMono-Medium.woff2 b/assets/RobotoMono-Medium.woff2 new file mode 100644 index 000000000..ec09ab18f Binary files /dev/null and b/assets/RobotoMono-Medium.woff2 differ diff --git a/assets/RobotoMono-Regular.woff2 b/assets/RobotoMono-Regular.woff2 new file mode 100644 index 000000000..53d4b505c Binary files /dev/null and b/assets/RobotoMono-Regular.woff2 differ diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 000000000..e1536f79a Binary files /dev/null and b/assets/logo.png differ diff --git a/gatsby-browser.js b/gatsby-browser.js new file mode 100644 index 000000000..09c615eb2 --- /dev/null +++ b/gatsby-browser.js @@ -0,0 +1,8 @@ +/** + * Implement Gatsby's Browser APIs in this file. + * + * See: https://www.gatsbyjs.org/docs/browser-apis/ + */ + +// You can delete this file if you're not using it +export { default as wrapRootElement } from './src/docs/state/ReduxWrapper'; diff --git a/gatsby-config.js b/gatsby-config.js new file mode 100644 index 000000000..f467e9bd2 --- /dev/null +++ b/gatsby-config.js @@ -0,0 +1,84 @@ +const config = require('./config'); + +module.exports = { + siteMetadata: { + title: `${config.name}`, + description: `${config.description}`, + author: `@30-seconds`, + siteUrl: `${config.siteUrl}`, + }, + plugins: [ + `gatsby-plugin-sitemap`, + `gatsby-plugin-transition-link`, + { + resolve: `gatsby-source-filesystem`, + options: { + name: `snippets`, + path: `${__dirname}/${config.snippetPath}`, + }, + }, + { + resolve: `gatsby-source-filesystem`, + options: { + name: `snippet_data`, + path: `${__dirname}/${config.snippetDataPath}`, + }, + }, + { + resolve: `gatsby-source-filesystem`, + options: { + name: `assets`, + path: `${__dirname}/${config.assetPath}`, + }, + }, + { + resolve: `gatsby-plugin-page-creator`, + options: { + path: `${__dirname}/${config.pagePath}`, + }, + }, + { + resolve: `gatsby-transformer-remark`, + options: { + plugins: [ + { + resolve: `gatsby-remark-images`, + options: { + maxWidth: 590, + }, + }, + `gatsby-remark-prismjs`, + `gatsby-remark-copy-linked-files`, + ], + }, + }, + `gatsby-plugin-sass`, + `gatsby-transformer-json`, + `gatsby-transformer-sharp`, + `gatsby-plugin-sharp`, + { + resolve: `gatsby-plugin-google-analytics`, + options: { + //trackingId: `ADD YOUR TRACKING ID HERE`, + anonymize: true, // Always set this to true, try to comply with GDPR out of the box + respectDNT: true, // Always set to true, be respectful of people who ask not to be tracked + cookieExpires: 0, // Always set to 0, minimum tracking for your users + }, + }, + { + resolve: `gatsby-plugin-manifest`, + options: { + name: `${config.name}`, + short_name: `${config.shortName}`, + start_url: `/`, + background_color: `#1e253d`, + theme_color: `#1e253d`, + display: `standalone`, + icon: `assets/30s-icon.png`, // This path is relative to the root of the site. + }, + }, + `gatsby-plugin-offline`, + `gatsby-plugin-react-helmet`, + `gatsby-plugin-netlify`, + ], +}; diff --git a/gatsby-node.js b/gatsby-node.js new file mode 100644 index 000000000..9221ea486 --- /dev/null +++ b/gatsby-node.js @@ -0,0 +1,93 @@ +const path = require(`path`); +const { createFilePath } = require(`gatsby-source-filesystem`); + +const toKebabCase = str => + str && + str + .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g) + .map(x => x.toLowerCase()) + .join('-'); + +exports.createPages = ({ graphql, actions }) => { + const { createPage } = actions; + + const snippetPage = path.resolve(`./src/docs/templates/SnippetPage.js`); + const tagPage = path.resolve(`./src/docs/templates/TagPage.js`); + return graphql( + ` + { + allMarkdownRemark( + sort: { fields: [frontmatter___title], order: ASC } + limit: 1000 + ) { + edges { + node { + fields { + slug + } + frontmatter { + tags + } + fileAbsolutePath + } + } + } + } + `, + ).then(result => { + if (result.errors) { + throw result.errors; + } + + // Create individual snippet pages. + const snippets = result.data.allMarkdownRemark.edges; + + snippets.forEach((post, index) => { + if (post.node.fileAbsolutePath.indexOf('README') !== -1) + return; + createPage({ + path: `/snippet${post.node.fields.slug}`, + component: snippetPage, + context: { + slug: post.node.fields.slug, + }, + }); + }); + + // Create tag pages. + const tags = snippets.reduce((acc, post) => { + if (!post.node.frontmatter || !post.node.frontmatter.tags) return acc; + const primaryTag = post.node.frontmatter.tags.split(',')[0]; + if (!acc.includes(primaryTag)) acc.push(primaryTag); + return acc; + }, []); + + tags.forEach(tag => { + const tagPath = `/tag/${toKebabCase(tag)}/`; + const tagRegex = `/^\\s*${tag}/`; + createPage({ + path: tagPath, + component: tagPage, + context: { + tag, + tagRegex, + }, + }); + }); + + return null; + }); +}; + +exports.onCreateNode = ({ node, actions, getNode }) => { + const { createNodeField } = actions; + + if (node.internal.type === `MarkdownRemark`) { + const value = createFilePath({ node, getNode }); + createNodeField({ + name: `slug`, + node, + value, + }); + } +}; diff --git a/gatsby-ssr.js b/gatsby-ssr.js new file mode 100644 index 000000000..3513ab31a --- /dev/null +++ b/gatsby-ssr.js @@ -0,0 +1,8 @@ +/** + * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. + * + * See: https://www.gatsbyjs.org/docs/ssr-apis/ + */ + +// You can delete this file if you're not using it +export { default as wrapRootElement } from './src/docs/state/ReduxWrapper'; diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 000000000..3bcf87c32 --- /dev/null +++ b/netlify.toml @@ -0,0 +1,6 @@ +[build] + publish = "public" + command = "npm run webber" +[build.environment] + YARN_VERSION = "1.9.4" + YARN_FLAGS = "--no-ignore-optional" \ No newline at end of file diff --git a/snippet_template.md b/snippet_template.md new file mode 100644 index 000000000..8fcf5b88a --- /dev/null +++ b/snippet_template.md @@ -0,0 +1,32 @@ +--- +title: Snippet Name +tags: other,intermediate +--- + +Explain briefly what the snippet does. + +```html +
+``` + +```css +.my-snippet { + background-color: #fff; + border: 1px solid #000; + border-radius: 4px; +} +``` + +```js +console.log("This is optional, if your snippet doesn't require JavaScript, be sure to delete this block!") +``` + +#### Explanation + +- Explain briefly how the snippet works. +- Use bullet points for your snippet's explanation. +- Try to explain everything briefly but clearly. + +#### Browser support + +- https://www.caniuse.com/#feat=border-radius diff --git a/static/robots.txt b/static/robots.txt new file mode 100644 index 000000000..6f27bb66a --- /dev/null +++ b/static/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: \ No newline at end of file