├── .babelrc
├── .gitignore
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
├── screenshot.png
├── src
├── actions
│ └── index.js
├── components
│ ├── app.js
│ └── regex.js
├── data
│ └── index.js
├── index.js
├── reducers
│ └── index.js
└── sass
│ └── style.scss
├── test
├── components
│ └── app_test.js
└── test_helper.js
├── trending.png
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["react", "es2015", "stage-1"]
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | bundle.js
3 | npm-debug.log
4 | index.html
5 | .htaccess
6 | # IntelliJ
7 | *.iml
8 | /.idea
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Luke Haas
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | 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, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Regex Hub
2 |
3 | The project is hosted here: https://lukehaas.me/projects/regexhub
4 |
5 | ### Adding a new pattern
6 |
7 | The patterns are contained in the file src/data/index.js
8 |
9 | Each pattern requires the following details:
10 | - name
11 | - regex
12 | - description
13 | - tags
14 |
15 |
16 |
17 |
18 | ### License
19 |
20 | [MIT License](https://raw.githubusercontent.com/lukehaas/RegexHub/refs/heads/master/LICENSE)
21 |
22 | Browser testing via [](https://www.lambdatest.com/)
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "redux-simple-starter",
3 | "version": "1.0.0",
4 | "description": "Simple starter package for Redux with React and Babel support",
5 | "main": "index.js",
6 | "repository": "git@github.com:StephenGrider/ReduxSimpleStarter.git",
7 | "scripts": {
8 | "start": "node ./node_modules/webpack-dev-server/bin/webpack-dev-server.js",
9 | "test": "mocha --compilers js:babel-core/register --require ./test/test_helper.js --recursive ./test",
10 | "test:watch": "npm run test -- --watch",
11 | "build": "webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors"
12 | },
13 | "author": "",
14 | "license": "ISC",
15 | "devDependencies": {
16 | "babel-core": "^6.2.1",
17 | "babel-loader": "^6.2.0",
18 | "babel-preset-es2015": "^6.1.18",
19 | "babel-preset-react": "^6.1.18",
20 | "chai": "^3.5.0",
21 | "chai-jquery": "^2.0.0",
22 | "css-loader": "^0.26.0",
23 | "jquery": "^3.3.1",
24 | "jsdom": "^8.1.0",
25 | "mocha": "^2.4.5",
26 | "node-sass": "^4.13.1",
27 | "react-addons-test-utils": "^0.14.7",
28 | "sass-loader": "^4.0.2",
29 | "style-loader": "^0.13.1",
30 | "webpack": "^1.12.9",
31 | "webpack-dev-server": "^1.14.0"
32 | },
33 | "dependencies": {
34 | "babel-preset-stage-1": "^6.1.18",
35 | "lodash": "^4.17.19",
36 | "react": "^0.14.3",
37 | "react-dom": "^0.14.3",
38 | "react-redux": "^4.0.0",
39 | "react-router": "^2.0.1",
40 | "redux": "^3.0.4"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukehaas/RegexHub/d1d9f19d259745dfdd21935b9ef3e747b62b9bfb/screenshot.png
--------------------------------------------------------------------------------
/src/actions/index.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukehaas/RegexHub/d1d9f19d259745dfdd21935b9ef3e747b62b9bfb/src/actions/index.js
--------------------------------------------------------------------------------
/src/components/app.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Regex from './regex';
3 |
4 | import { patterns } from '../data';
5 |
6 | export default class App extends Component {
7 |
8 | renderPatterns() {
9 | var i = 0,z = 0,
10 | sortedData = [[],[],[]],
11 | index = 0;
12 |
13 | for(var j = 0;j < patterns.length;j++) {
14 | if(index%3===0) {
15 | index = 0;
16 | }
17 |
18 | sortedData[index].push(patterns[j]);
19 | index++;
20 | }
21 |
22 | return sortedData.map((data) => {
23 |
24 | i++;
25 | var panels = data.map((props) => {
26 | z++;
27 | return
28 | });
29 | return (
30 |
31 | {panels}
32 |
33 | );
34 | });
35 | }
36 | render() {
37 | return (
38 | {this.renderPatterns()}
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/components/regex.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | //import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
3 |
4 | class Regex extends Component {
5 | constructor(props) {
6 | super(props);
7 |
8 | this.state = {
9 | editableRegex: props.regex.toString(),
10 | test:"",
11 | output:[],
12 | open:false
13 | };
14 | }
15 | handleRegexChange(val) {
16 |
17 |
18 | this.setState({
19 | editableRegex:val
20 | },this.evaluateOutput);
21 |
22 | }
23 | handleTestChange(val) {
24 |
25 | this.setState({
26 | test:val
27 | },this.evaluateOutput);
28 |
29 | }
30 | evaluateOutput() {
31 |
32 | if(this.state.test.length>0 && this.state.editableRegex.length>0) {
33 | var editableRegex = this.state.editableRegex;
34 |
35 |
36 | var flags = /[^\/]+$/.exec(editableRegex);
37 | if(!flags) {
38 | flags = "";
39 | }
40 | editableRegex = editableRegex.replace(/[^\/]+$/, "");
41 |
42 | var reg = new RegExp(eval(editableRegex),flags);
43 |
44 | var out;
45 | try {
46 | out = reg.exec(this.state.test);
47 | } catch(e) {
48 | out = ["Invalid regex"];
49 | }
50 |
51 | if(!out) {
52 |
53 | out = ["null"];
54 | } else if(out[0]==="") {
55 | out = ["null"];
56 | } else {
57 | var o = [];
58 | o[0] = out[0];
59 | for(var k = 1;k < out.length;k++) {
60 |
61 | if(typeof out[k] === "string") {
62 | o.push(out[k]);
63 | }
64 | }
65 | out = o;
66 | }
67 |
68 | this.setState({
69 | output:out
70 | });
71 | } else {
72 | this.setState({
73 | output:[]
74 | });
75 | }
76 |
77 |
78 | }
79 | handleOpen(e) {
80 | e.preventDefault();
81 |
82 | if(this.state.open) {
83 | this.setState({
84 | open:false
85 | });
86 | } else {
87 | this.setState({
88 | open:true
89 | });
90 | }
91 | }
92 | render() {
93 | var output = Output:
{this.state.output.map((data,i) => {return - {data}
})}
;
94 | return (
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | this.handleRegexChange(e.target.value)} />
106 |
107 |
108 |
111 | {this.state.output.length>0 ? output : ""}
112 |
113 |
114 | );
115 | }
116 | }
117 |
118 | export default Regex;
119 |
120 | /*
121 |
122 | run: webpack -p
123 | to generate bundle.js
124 |
125 | Add reset button - once regex is edited the button will restore it?
126 |
127 |
128 | add search
129 | add details at the bottom for pull requests
130 |
131 | https://projects.lukehaas.me/regexhub//?_escaped_fragment_\=
132 |
133 | */
134 |
--------------------------------------------------------------------------------
/src/data/index.js:
--------------------------------------------------------------------------------
1 | export const patterns = [{
2 | name:"Date in format dd/mm/yyyy",
3 | regex:/^(0?[1-9]|[12][0-9]|3[01])([ /\-])(0?[1-9]|1[012])\2([0-9][0-9][0-9][0-9])(([ -])([0-1]?[0-9]|2[0-3]):[0-5]?[0-9]:[0-5]?[0-9])?$/,
4 | description:"Will match dates with dashes, slashes or with spaces (e.g. dd-mm-yyyy dd/mm/yyyy dd mm yyyy), and optional time separated by a space or a dash (e.g. dd-mm-yyyy-hh:mm:ss or dd/mm/yyyy hh:mm:ss).",
5 | tags:"date,time"
6 | },
7 | {
8 | name:"Time in 24-hour format",
9 | regex:/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/,
10 | description: "Match times in 24 hour format",
11 | tags:"date,time"
12 | },
13 | {
14 | name: "Date and time in ISO-8601 format",
15 | regex: /^(?![+-]?\d{4,5}-?(?:\d{2}|W\d{2})T)(?:|(\d{4}|[+-]\d{5})-?(?:|(0\d|1[0-2])(?:|-?([0-2]\d|3[0-1]))|([0-2]\d{2}|3[0-5]\d|36[0-6])|W([0-4]\d|5[0-3])(?:|-?([1-7])))(?:(?!\d)|T(?=\d)))(?:|([01]\d|2[0-4])(?:|:?([0-5]\d)(?:|:?([0-5]\d)(?:|\.(\d{3})))(?:|[zZ]|([+-](?:[01]\d|2[0-4]))(?:|:?([0-5]\d)))))$/,
16 | description: "Will match a valid date and times in the ISO-8601 format, excludes durations.",
17 | tags: "date,time"
18 | },
19 | {
20 | name:"HTML tags",
21 | regex:/^<([a-z1-6]+)([^<]+)*(?:>(.*)<\/\1>| *\/>)$/,
22 | description:"Match opening and closing HTML tags with content between",
23 | tags:"markup,xml,html"
24 | },
25 | {
26 | name:"Username",
27 | regex:/^[a-zA-Z0-9_-]{3,16}$/,
28 | description:"A string between 3 and 16 characters, allowing alphanumeric characters and hyphens and underscores",
29 | tags:"username,validation"
30 | },
31 | {
32 | name:"Hex Color Value",
33 | regex:/^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/,
34 | description:"RGB hex colors",
35 | tags:"hex,color"
36 | },
37 | {
38 | name:"URL Slug",
39 | regex:/^[a-z0-9-]+$/,
40 | description:"Match valid URL slugs",
41 | tags:"URL"
42 | },
43 | {
44 | name:"Email",
45 | regex:/^.+@.+$/,
46 | description:"Verify that there is an @ symbol with something before it",
47 | tags:"email,validation"
48 | },
49 | {
50 | name:"SRC of image tag",
51 | regex:/^<\s*img[^>]+src\s*=\s*(["'])(.*?)\1[^>]*>$/,
52 | description:"Match the src attribute of an HTML image tag",
53 | tags:"html,tag,image"
54 | },
55 | {
56 | name:"URL",
57 | regex:/^((https?|ftp|file):\/\/)?([\da-z-]+\.)+([a-z]{2,6})([\/\w \.-]*)*\/?$/
58 | description:"Match URL with optional protocol",
59 | tags:"url,address,http"
60 | },
61 | {
62 | name:"IPv4 Address",
63 | regex:/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
64 | description:"Match IP v4 addresses",
65 | tags:"tcpip,internet,address"
66 | },
67 | {
68 | name:"IPv6 Address",
69 | regex:/^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$/,
70 | description: "Match IP v6 addresses",
71 | tags:"tcpip,internet,address"
72 | },
73 | {
74 | name:"JWT",
75 | regex:/^[A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*$/,
76 | description: "JSON Web Token (encoded)",
77 | tags:"www"
78 | },
79 | {
80 | name:"Positive Integer",
81 | regex:/^\d+$/,
82 | descriptions:"Match whole numbers above zero",
83 | tags:"number"
84 | },
85 | {
86 | name:"Negative Integer",
87 | regex:/^-\d+$/,
88 | description:"Match whole numbers below zero",
89 | tags:"number"
90 | },
91 | {
92 | name:"Integer",
93 | regex:/^-?\d+$/,
94 | description:"Match whole numbers, above or below zero",
95 | tags:"number"
96 | },
97 | {
98 | name:"Positive number",
99 | regex:/^\d*\.?\d+$/,
100 | description:"Match integers or floats that are positive",
101 | tags:"float"
102 | },
103 | {
104 | name:"Negative number",
105 | regex:/^-\d*\.?\d+$/,
106 | description:"Match integers or floats that are negative",
107 | tags:"float"
108 | },
109 | {
110 | name:"Positive or negative number",
111 | regex:/^-?\d*\.?\d+$/,
112 | description:"Match integers or floats that are positive or negative",
113 | tags:"float"
114 | },
115 | {
116 | name:"Phone number",
117 | regex:/^\+?(\d.*){3,}$/,
118 | description:"Match phone numbers at least 3 digits long",
119 | tags:"validation"
120 | },
121 | {
122 | name:"New line",
123 | regex:/[\r\n]|$/,
124 | description:"Match new lines within text",
125 | tags:"text"
126 | },
127 | {
128 | name:"ID of Youtube video",
129 | regex:/https?:\/\/(?:youtu\.be\/|(?:[a-z]{2,3}\.)?youtube\.com\/watch(?:\?|#\!)v=)([\w-]{11}).*/gi,
130 | description:"Match the ID of a youtube video URL",
131 | tags:"video,youtube,url"
132 | },
133 | {
134 | name:"ID of Youtube Channel",
135 | regex:/https?:\/\/(www\.)?youtube.com\/channel\/UC([-_a-z0-9]{22})/i,
136 | description:"Match the ID of a youtube channel URL",
137 | tags:"channel,youtube,url"
138 | },
139 | {
140 | name:"CSS comment",
141 | regex:/\/\*[^*]*\*+([^/*][^*]*\*+)*\//,
142 | description:"Match standard CSS comments",
143 | tags:"css,comment,code"
144 | },
145 | {
146 | name:"Wordpress shortcodes",
147 | regex:/^\[([a-z-_0-9]+)([^\[]+)*(?:\](.*)\[\/\1\]|\s+\/\])$/,
148 | description:"Matches opening and closing shortcode tags with content in-between them.",
149 | tags:"wordpress,shortcodes,markup"
150 | },
151 | {
152 | name:"U.S./Canadian ZIP/Postal Code",
153 | regex:/(^\d{5}(-\d{4})?$)|(^[ABCEGHJKLMNPRSTVXY]{1}\d{1}[A-Z]{1} *\d{1}[A-Z]{1}\d{1}$)/,
154 | description:"Matches US ZIP, ZIP+4, and Canadian Postal Codes",
155 | tags:"address, postal, zip"
156 | },
157 | {
158 | name:"UK Postal Code",
159 | regex:/^(([gG][iI][rR] {0,}0[aA]{2})|(([aA][sS][cC][nN]|[sS][tT][hH][lL]|[tT][dD][cC][uU]|[bB][bB][nN][dD]|[bB][iI][qQ][qQ]|[fF][iI][qQ][qQ]|[pP][cC][rR][nN]|[sS][iI][qQ][qQ]|[iT][kK][cC][aA]) {0,}1[zZ]{2})|((([a-pr-uwyzA-PR-UWYZ][a-hk-yxA-HK-XY]?[0-9][0-9]?)|(([a-pr-uwyzA-PR-UWYZ][0-9][a-hjkstuwA-HJKSTUW])|([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y][0-9][abehmnprv-yABEHMNPRV-Y]))) {0,}[0-9][abd-hjlnp-uw-zABD-HJLNP-UW-Z]{2}))$/,
160 | description:"Matches all UK postcodes",
161 | tags:"address, postal, zip"
162 | },
163 | {
164 | name:"Brazilian ZIP/Postal Code",
165 | regex:/^[0-9]{5}-[0-9]{3}$/,
166 | description:"Matches BR ZIP/Postal Code",
167 | tags:"address, postal, zip"
168 | },
169 | {
170 | name:"Morse Code",
171 | regex:/^[.-]{1,5}(?:[ \t]+[.-]{1,5})*(?:[ \t]+[.-]{1,5}(?:[ \t]+[.-]{1,5})*)*$/,
172 | description:"Matches valid Morse Code",
173 | tags:"morse, code"
174 | },
175 | {
176 | name:"Image shortcode",
177 | regex:/\[img\](.*?)\[\/img\]/,
178 | description:"Matches the content in between [img][/img]. Useful for making dynamic WYSIWYG editors",
179 | tags:"img, shortcode, wysiwyg"
180 | },
181 | {
182 | name:"Brainfuck Code",
183 | regex:/^[+-<>.,\[\] \t\n\r]+$/,
184 | description:"Matches valid code for a brainfuck program.",
185 | tags:"brainfuck, code"
186 | },
187 | {
188 | name:"Semver",
189 | regex:/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-((?:0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/,
190 | description:"Matches valid semantic versioning.",
191 | tags:"semver,semantic,versioning,version"
192 | }
193 | ];
194 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { Provider } from 'react-redux';
4 | import { createStore, applyMiddleware } from 'redux';
5 |
6 | import App from './components/app';
7 | import reducers from './reducers';
8 |
9 | import './sass/style.scss';
10 |
11 | const createStoreWithMiddleware = applyMiddleware()(createStore);
12 |
13 | ReactDOM.render(
14 |
15 |
16 |
17 | , document.querySelector('.app'));
18 |
--------------------------------------------------------------------------------
/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 |
3 | const rootReducer = combineReducers({
4 | state: (state = {}) => state
5 | });
6 |
7 | export default rootReducer;
8 |
--------------------------------------------------------------------------------
/src/sass/style.scss:
--------------------------------------------------------------------------------
1 | $panel-bg:#222;
2 | $panel-border:#444;
3 | $body-bg:#111;
4 | $link-color:#85C1E9;
5 | $text-color:#eee;
6 | $desc-bg: #292929;
7 |
8 | .container-fluid {
9 | max-width:1200px;
10 | min-width:300px;
11 | }
12 | h1 {
13 | margin:40px 0 20px 0;
14 | }
15 | .social {
16 | margin:20px 0;
17 | }
18 | .social iframe {
19 | margin-right:3px;
20 | }
21 | a:link,
22 | a:visited {
23 | color:$link-color;
24 | }
25 | .regex-hub {
26 |
27 | color:$text-color;
28 | background-color: $body-bg;
29 | .desc {
30 | -webkit-transition: 0.5s height ease;
31 | transition: 0.5s height ease;
32 | background:$desc-bg;
33 | padding:8px;
34 | color:$text-color;
35 | p {
36 | margin-bottom:0;
37 | }
38 |
39 | &.closed {
40 | /*height:0%;
41 | padding:0;
42 | overflow: hidden;*/
43 |
44 | display:none;
45 | }
46 | }
47 | .panel-default {
48 | color:$text-color;
49 | border-color:$panel-border;
50 | background-color: $panel-bg;
51 |
52 | input {
53 | width:100%;
54 | background-color:#444;
55 | border:1px solid #333;
56 | color:$text-color;
57 | padding:5px;
58 | }
59 | }
60 | .panel-default>.panel-heading {
61 | background-color: $panel-bg;
62 |
63 | border-color:$panel-border;
64 | border-bottom:0 none;
65 | h2 {
66 | font-size:1em;
67 | font-weight:normal;
68 | padding:0;
69 | margin:0;
70 | }
71 | a {
72 | font-size:1.2em;
73 | padding:5px 10px 10px 0px;
74 | display: block;
75 |
76 | }
77 |
78 | padding:11px 15px 0px 15px;
79 | }
80 | .panel-body {
81 | padding:12px 15px 15px 15px;
82 | input {
83 | background-color: #111;
84 | padding:10px;
85 | color:#AF7AC5;
86 | }
87 | }
88 | .panel-footer {
89 | background-color:$panel-bg;
90 | border-color:$panel-border;
91 | border-top:0 none;
92 | }
93 | .output {
94 | margin-top:10px;
95 | ul {
96 | margin:0;
97 | padding:0;
98 | list-style:none;
99 | }
100 | }
101 | }
102 |
103 | .panel-heading a {
104 | position: relative;
105 | &:before,
106 | &:after {
107 | content:'';
108 | position: absolute;
109 | background-color: #666;
110 | }
111 | &:before {
112 | width:1px;
113 | height:11px;
114 | right:5px;
115 | top:10px;
116 | }
117 | &:after {
118 | width:11px;
119 | height:1px;
120 | top:15px;
121 | right:0px;
122 | }
123 | &.open {
124 | &:before {
125 | display:none;
126 | }
127 | }
128 | }
129 |
130 | #carbonads {
131 | padding:10px 0;
132 | width:130px;
133 | margin:0 auto;
134 | font-size:10px;
135 | line-height:1.2;
136 | a {
137 | display:block;
138 | }
139 | }
140 | /* Small devices (tablets, 768px and up) */
141 | @media (min-width: 768px) {
142 | #carbonads {
143 | float:right;
144 | margin:0;
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/test/components/app_test.js:
--------------------------------------------------------------------------------
1 | import { renderComponent , expect } from '../test_helper';
2 | import App from '../../src/components/app';
3 |
4 | describe('App' , () => {
5 | let component;
6 |
7 | beforeEach(() => {
8 | component = renderComponent(App);
9 | });
10 |
11 | it('renders something', () => {
12 | expect(component).to.exist;
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/test/test_helper.js:
--------------------------------------------------------------------------------
1 | import _$ from 'jquery';
2 | import React from 'react';
3 | import ReactDOM from 'react-dom';
4 | import TestUtils from 'react-addons-test-utils';
5 | import jsdom from 'jsdom';
6 | import chai, { expect } from 'chai';
7 | import chaiJquery from 'chai-jquery';
8 | import { Provider } from 'react-redux';
9 | import { createStore } from 'redux';
10 | import reducers from '../src/reducers';
11 |
12 | global.document = jsdom.jsdom('');
13 | global.window = global.document.defaultView;
14 | global.navigator = global.window.navigator;
15 | const $ = _$(window);
16 |
17 | chaiJquery(chai, chai.util, $);
18 |
19 | function renderComponent(ComponentClass, props = {}, state = {}) {
20 | const componentInstance = TestUtils.renderIntoDocument(
21 |
22 |
23 |
24 | );
25 |
26 | return $(ReactDOM.findDOMNode(componentInstance));
27 | }
28 |
29 | $.fn.simulate = function(eventName, value) {
30 | if (value) {
31 | this.val(value);
32 | }
33 | TestUtils.Simulate[eventName](this[0]);
34 | };
35 |
36 | export {renderComponent, expect};
37 |
--------------------------------------------------------------------------------
/trending.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lukehaas/RegexHub/d1d9f19d259745dfdd21935b9ef3e747b62b9bfb/trending.png
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: [
3 | './src/index.js'
4 | ],
5 | output: {
6 | path: __dirname,
7 | publicPath: '/',
8 | filename: 'bundle.js'
9 | },
10 | module: {
11 | loaders: [{
12 | exclude: /node_modules/,
13 | loader: 'babel',
14 | query: {
15 | presets: ['react', 'es2015', 'stage-1']
16 | }
17 | },
18 | {
19 | test:/\.scss$/,
20 | loaders:["style","css","sass"]
21 | }]
22 | },
23 | resolve: {
24 | extensions: ['', '.js', '.jsx']
25 | },
26 | devServer: {
27 | historyApiFallback: true,
28 | contentBase: './'
29 | }
30 | };
31 |
--------------------------------------------------------------------------------