diff --git a/.gitignore b/.gitignore index 4c9ee91..411d6bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ # misc -.DS_Store +**/.DS_Store *.pem -*.zip \ No newline at end of file +*.zip +node_modules +.cache +package-lock.json +dist/ \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..9953bdf --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "trailingComma": "es5", + "tabWidth": 2, + "semi": false, + "singleQuote": true +} \ No newline at end of file diff --git a/README.md b/README.md index 40b13af..3f3c01d 100644 --- a/README.md +++ b/README.md @@ -24,4 +24,11 @@ Speed Up Your Development Workflow For developers, every second counts. Why squint at unformatted JSON when you can view, interact, and even edit it seamlessly? With JSON Formatter, you're not just reading data; you're experiencing it. Whether you're debugging, analyzing, or just curious, our tool is designed to speed up your workflow. -Install JSON Formatter today and transform chaos into clarity! \ No newline at end of file +Install JSON Formatter today and transform chaos into clarity! + +## Getting Started + +1. Run `npm install` to install the required dependencies. +2. Run `npm run dev` to watch the file changes. +3. Load `dist` as the unpacked extension during the development. +4. Run `npm run build` to build the file for distribution. diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..37b0298 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,34 @@ +const gulp = require('gulp'); +const postcss = require('gulp-postcss'); +const autoprefixer = require('autoprefixer'); +const postcssNested = require('postcss-nested'); +const cssmin = require('gulp-cssmin'); + +const srcFiles = [ + 'src/content.js', + 'src/manifest.json', + 'src/fonts/**/*', + 'src/icons/**/*', +]; + +function copyAll() { + return gulp + .src(srcFiles, { base: './src/' }) + .pipe(gulp.dest('dist')); +} + +function processCSS() { + const plugins = [autoprefixer(), postcssNested()]; + + return gulp + .src('src/styles.css') + .pipe(postcss(plugins)) + .pipe(cssmin()) + .pipe(gulp.dest('dist')); +} + +gulp.task('build', gulp.series(copyAll, processCSS)); +gulp.task('watch', function () { + gulp.watch(srcFiles, copyAll); + gulp.watch('src/styles.css', processCSS); +}); \ No newline at end of file diff --git a/icons/.DS_Store b/icons/.DS_Store deleted file mode 100644 index 00b6692..0000000 Binary files a/icons/.DS_Store and /dev/null differ diff --git a/package.json b/package.json new file mode 100644 index 0000000..2e0d4f2 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "jsonformatter", + "version": "1.0.0", + "description": "A simple, clean, functional JSON formatter for Chrome", + "scripts": { + "dev": "gulp watch", + "build": "gulp build" + }, + "dependencies": { + "autoprefixer": "^10.4.16", + "gulp": "^4.0.2", + "gulp-postcss": "^9.0.1" + }, + "devDependencies": { + "gulp-cssmin": "^0.2.0", + "postcss-nested": "^6.0.1" + } +} diff --git a/content.js b/src/content.js similarity index 100% rename from content.js rename to src/content.js diff --git a/fonts/MonoLisaVariableItalic.woff2 b/src/fonts/MonoLisaVariableItalic.woff2 similarity index 100% rename from fonts/MonoLisaVariableItalic.woff2 rename to src/fonts/MonoLisaVariableItalic.woff2 diff --git a/fonts/MonoLisaVariableNormal.woff2 b/src/fonts/MonoLisaVariableNormal.woff2 similarity index 100% rename from fonts/MonoLisaVariableNormal.woff2 rename to src/fonts/MonoLisaVariableNormal.woff2 diff --git a/icons/icon128.png b/src/icons/icon128.png similarity index 100% rename from icons/icon128.png rename to src/icons/icon128.png diff --git a/icons/icon16.png b/src/icons/icon16.png similarity index 100% rename from icons/icon16.png rename to src/icons/icon16.png diff --git a/icons/icon48.png b/src/icons/icon48.png similarity index 100% rename from icons/icon48.png rename to src/icons/icon48.png diff --git a/manifest.json b/src/manifest.json similarity index 100% rename from manifest.json rename to src/manifest.json diff --git a/src/styles.css b/src/styles.css new file mode 100644 index 0000000..8939c7e --- /dev/null +++ b/src/styles.css @@ -0,0 +1,328 @@ +body[data-view='raw'] { + margin-top: 50px; +} + +#jsonformatter { + color: #2b2b2b; + font-size: 11.5px; + line-height: 16px; + font-family: 'MonoLisa', monospace; + font-display: swap; + + > div { + padding: 5px 10px; + } + + span, + .string { + display: inline-block; + } + + .k { + color: #b16b2a; + } + + .string { + color: green; + } + + .number { + color: darkblue; + } + + .boolean.false { + color: red; + } + .boolean.true { + color: green; + } + + .null { + color: magenta; + } + + .collapsible { + display: inline-block; + cursor: pointer; + } + + .content { + display: block; + margin-left: 21px; + padding-left: 15px; + border-left: 1px dotted #dedede; + } + + .content > div { + line-height: 18px; + } + + .ellipsis { + display: none; + } + + .arrow-right .ellipsis { + display: inline-block; + } + + .arrow-right svg, + .arrow-down svg { + float: left; + } + + .arrow-right path, + .arrow-down path { + fill: #e1e1e1; + } + + .placeholder-arrow { + display: inline-block; + width: 15px; + height: 15px; + } + + .arrow-down svg { + transform: rotate(90deg); + } + + .kvp { + display: block; + } + + .kvr { + display: flex; + flex-wrap: wrap; + align-items: flex-start; + } + + .k, + .c { + white-space: nowrap; + } + + .c { + margin-right: 5px; + } + + .v { + word-wrap: break-word; + flex-grow: 1; + margin-left: 0; + } + + button { + position: fixed; + top: 13px; + right: 15px; + width: 140px; + height: 28px; + padding: 4px 8px 3px; + border: none; + border-radius: 3px; + font-weight: 600; + font-family: 'MonoLisa'; + cursor: pointer; + transition: background-color 0.3s; + } + + button::before { + display: flex; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + align-items: center; + justify-content: center; + content: ''; + } + + button { + background-color: #4caf50; + color: white; + } + + button::before { + content: 'Formatted JSON'; + } +} + +#jsonformatter { + [data-view='raw'] button { + background-color: #ededed; + color: #6a6a6a; + } + + [data-view='raw'] button::before { + content: 'Raw JSON'; + } +} + +#jsonformatter { + > div:nth-child(1) > span.collapsible > span.opening, + span.closing { + display: inline-block; + } + + span.closing { + padding-left: 19px; + } + span.empty { + padding-left: 17px; + } + + .content[style*='display: none'] + .closing { + padding-left: 0; + } + + .content[style*='display: none'] + .closing:before { + position: relative; + content: '...'; + } + + .item-count::before { + display: none; + content: '// ' attr(count); + color: #888; + font-style: italic; + } + + .content[style*='display: none'] + .closing + .item-count::before { + display: inline; + padding-left: 5px; + } + + .color-preview { + display: inline-block; + width: 10px; + height: 10px; + margin-right: 2px; + border: 1px solid #e1e1e1; + border-radius: 15px; + vertical-align: middle; + } + + .timestamp::after { + margin-right: 3px; + margin-left: 3px; + content: ' /* ' attr(data-timestamp-comment) ' */ '; + color: #888; + font-style: italic; + } + + .jsonLintIcon { + fill: #6b6b6b; + position: fixed; + top: 13px; + right: 165px; + padding: 3px 4px; + border: 1px solid #cdcdcd; + border-radius: 3px; + cursor: pointer; + transition: fill 0.3s; + } + + [data-view='raw'] .jsonLintIcon { + fill: #6a6a6a; + } + + .jsonLintIcon:hover { + fill: #3a3a3a; + } + + .image-wrapper { + display: inline-block; + position: relative; + cursor: pointer; + } + + .image-wrapper img { + z-index: 10; + position: absolute; + top: 100%; + left: 50%; + max-width: 200px; + max-height: 200px; + padding: 8px; + transform: translateX(-50%); + border: 1px solid #ccc; + border-radius: 4px; + background-image: linear-gradient( + 45deg, + #fff 25%, + transparent 25%, + transparent 75%, + #fff 75%, + #fff + ), + linear-gradient( + 45deg, + #fff 25%, + transparent 25%, + transparent 75%, + #fff 75%, + #fff + ); + background-position: 0 0, 10px 10px; + background-size: 20px 20px; + + background-color: #dadada; + opacity: 0; + pointer-events: none; + transition: opacity 0.3s ease; + } + + .image-wrapper:hover img { + opacity: 1; + } +} + +@media (prefers-color-scheme: dark) { + #jsonformatter { + background-color: #2b2b2b; + color: #e1e1e1; + + .k { + color: #ffb86c; + } + + .string { + color: #50fa7b; + } + + .number { + color: #8be9fd; + } + + .boolean { + color: #ff79c6; + } + + .null { + color: #bd93f9; + } + + .content { + border-left: 1px dotted #555; + } + + .arrow-right path, + .arrow-down path { + fill: #888; + } + + .item-count::before { + color: #666; + } + } + + #jsonformatter[data-view='formatted'] button { + background-color: #6272a4; + color: #f8f8f2; + } + + #jsonformatter[data-view='raw'] button { + background-color: #44475a; + color: #f8f8f2; + } +} diff --git a/styles.css b/styles.css deleted file mode 100644 index be51401..0000000 --- a/styles.css +++ /dev/null @@ -1,305 +0,0 @@ -#jsonformatter { - color: #2b2b2b; - font-display: swap; - font-family: 'MonoLisa', monospace; - font-size: 11.5px; - line-height: 16px; -} - -body[data-view="raw"] { - margin-top: 50px; -} - -#jsonformatter > div { - padding: 5px 10px; -} - -#jsonformatter span, #jsonformatter .string { - display: inline-block; -} - -#jsonformatter .k { - color: #b16b2a; -} - -#jsonformatter .string { - color: green; -} - -#jsonformatter .number { - color: darkblue; -} - -#jsonformatter .boolean.false { - color: red; -} -#jsonformatter .boolean.true { - color: green; -} - -#jsonformatter .null { - color: magenta; -} - -#jsonformatter .collapsible { - cursor: pointer; - display: inline-block; -} - -#jsonformatter .content { - display: block; - margin-left: 21px; - padding-left: 15px; - border-left: 1px dotted #dedede; -} - -#jsonformatter .content > div { - line-height: 18px; -} - -#jsonformatter .ellipsis { - display: none; -} - -#jsonformatter .arrow-right .ellipsis { - display: inline-block; -} - -#jsonformatter .arrow-right svg, #jsonformatter .arrow-down svg { - float: left; -} - -#jsonformatter .arrow-right path, #jsonformatter .arrow-down path { - fill: #e1e1e1; -} - -#jsonformatter .placeholder-arrow { - display: inline-block; - width: 15px; - height: 15px; -} - -#jsonformatter .arrow-down svg { - transform: rotate(90deg); -} - -#jsonformatter .kvp { - display: block; -} - -#jsonformatter .kvr { - display: flex; - flex-wrap: wrap; - align-items: flex-start; -} - -#jsonformatter .k, #jsonformatter .c { - white-space: nowrap; -} - -#jsonformatter .c { - margin-right: 5px; -} - -#jsonformatter .v { - flex-grow: 1; - margin-left: 0; - word-wrap: break-word; -} - -#jsonformatter button { - border-radius: 3px; - padding: 4px 8px 3px; - font-weight: 600; - font-family: 'MonoLisa'; - position: fixed; - right: 15px; - top: 13px; - border: none; - cursor: pointer; - transition: background-color 0.3s; - height: 28px; - width: 140px; -} - -#jsonformatter button::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - display: flex; - align-items: center; - justify-content: center; -} - -#jsonformatter button { - background-color: #4CAF50; - color: white; -} - -#jsonformatter button::before { - content: "Formatted JSON"; -} - -#jsonformatter[data-view="raw"] button { - background-color: #ededed; - color: #6a6a6a; -} - -#jsonformatter[data-view="raw"] button::before { - content: "Raw JSON"; -} - -#jsonformatter > div:nth-child(1) > span.collapsible > span.opening, span.closing { - display: inline-block; -} - -#jsonformatter span.closing { - padding-left: 19px; -} -#jsonformatter span.empty { - padding-left: 17px; -} - -#jsonformatter .content[style*="display: none"] + .closing { - padding-left: 0; -} - -#jsonformatter .content[style*="display: none"] + .closing:before { - content: '...'; - position: relative; -} - -#jsonformatter .item-count::before { - content: "// " attr(count); - color: #888; - font-style: italic; - display: none; -} - -#jsonformatter .content[style*="display: none"] + .closing + .item-count::before { - display: inline; - padding-left: 5px; -} - -#jsonformatter .color-preview { - display: inline-block; - border-radius: 15px; - width: 10px; - height: 10px; - border: 1px solid #e1e1e1; - margin-right: 2px; - vertical-align: middle; -} - -#jsonformatter .timestamp::after { - content: " /* " attr(data-timestamp-comment) " */ "; - color: #888; - font-style: italic; - margin-left: 3px; - margin-right: 3px; -} - -#jsonformatter .jsonLintIcon { - cursor: pointer; - position: fixed; - right: 165px; - top: 13px; - fill: #6b6b6b; - transition: fill 0.3s; - border: 1px solid #cdcdcd; - border-radius: 3px; - padding: 3px 4px; -} - -#jsonformatter[data-view="raw"] .jsonLintIcon { - fill: #6a6a6a; -} - -#jsonformatter .jsonLintIcon:hover { - fill: #3a3a3a; -} - -#jsonformatter .image-wrapper { - position: relative; - display: inline-block; - cursor: pointer; -} - -#jsonformatter .image-wrapper img { - position: absolute; - top: 100%; - left: 50%; - transform: translateX(-50%); - max-width: 200px; - max-height: 200px; - padding: 8px; - border: 1px solid #ccc; - border-radius: 4px; - z-index: 10; - opacity: 0; - pointer-events: none; - transition: opacity 0.3s ease; - - background-color: #dadada; - background-image: - linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff), - linear-gradient(45deg, #fff 25%, transparent 25%, transparent 75%, #fff 75%, #fff); - background-size: 20px 20px; - background-position: 0 0, 10px 10px; -} - -#jsonformatter .image-wrapper:hover img { - opacity: 1; -} - -@media (prefers-color-scheme: dark) { - #jsonformatter { - color: #e1e1e1; - background-color: #2b2b2b; - } - - #jsonformatter .k { - color: #ffb86c; - } - - #jsonformatter .string { - color: #50fa7b; - } - - #jsonformatter .number { - color: #8be9fd; - } - - #jsonformatter .boolean { - color: #ff79c6; - } - - #jsonformatter .null { - color: #bd93f9; - } - - #jsonformatter .content { - border-left: 1px dotted #555; - } - - #jsonformatter .arrow-right path, #jsonformatter .arrow-down path { - fill: #888; - } - - #jsonformatter[data-view="formatted"] button { - background-color: #6272a4; - color: #f8f8f2; - } - - #jsonformatter[data-view="raw"] button { - background-color: #44475a; - color: #f8f8f2; - } - - #jsonformatter .item-count::before { - color: #666; - } -} \ No newline at end of file