54 Commits

Author SHA1 Message Date
rektdeckard
57016742a5 payments: integrate with payment server 2021-07-03 13:46:10 -04:00
rektdeckard
7cd27c509b app: Generify Modal and restructure imports 2021-06-21 17:07:52 -04:00
rektdeckard
8a7921d082 app: Add modals and begin implementing donations
This patch adds a mechanism to open a modal, and roughs out a donation
flow using the 'braintree' payments provider.
2021-06-20 20:04:40 -04:00
rektdeckard
a885931831 app: Mobile grid improvements 2021-06-20 19:53:53 -04:00
rektdeckard
2eb51f7ca7 icons: yet more tagging and updates for v1.3.0 2021-06-14 00:53:10 -04:00
rektdeckard
7e1bd3d18e icons: more tagging 2021-06-13 12:47:11 -04:00
rektdeckard
94e5d9b305 chore: Update snippets and unused code 2021-06-13 12:46:45 -04:00
rektdeckard
02e70848b1 icons: tag additions for v1.3.0 2021-05-31 16:43:46 -04:00
rektdeckard
b8eac52689 App: browser compat updates 2021-05-30 23:31:26 -04:00
rektdeckard
73b66e2e86 App: add helper hooks 2021-05-30 23:17:33 -04:00
rektdeckard
0e50efb5ea icons: more tags 2021-05-29 23:11:31 -04:00
rektdeckard
dc6764e387 DetailsPanel: smooth panel transitions to eliminate bounce 2021-03-13 12:29:57 -05:00
Tobias Fried
2ba5ac332b Merge pull request #29 from phosphor-icons/phosphor-react-refactor
Dependencipalooza
2021-03-09 00:10:45 -05:00
rektdeckard
b9a0b93067 meta: Bump site version to match phosphor dep 2021-03-08 23:59:38 -05:00
rektdeckard
6596bce68a SearchInput: More idiomatic shortcuts 2021-03-08 23:58:29 -05:00
rektdeckard
6d74c9f719 DetailsPanel: Avoid framer-motion style value bug 2021-03-08 23:57:42 -05:00
rektdeckard
02525cabb5 deps: Bump phopshor-react, framer-motion, recoil, tinycolor 2021-03-08 23:57:09 -05:00
rektdeckard
8974b2de19 icons+meta: Update icons to phosphor-react@1.2.0 2021-03-07 23:42:08 -05:00
rektdeckard
61fe3d9de8 SearchInput: Make device detection static 2021-03-07 13:47:07 -05:00
rektdeckard
62d0524f34 README: Update icon count and related links 2021-03-07 13:46:47 -05:00
rektdeckard
b3b328876f SearchInput: Fix keystroke alignment 2021-03-07 02:48:47 -05:00
rektdeckard
f598e3ab50 SearchInput: Add keyboard shortcuts with platform detection 2021-03-06 22:41:52 -05:00
rektdeckard
78ff8e4500 icons: Reword IconCatergory name 2021-03-06 20:31:56 -05:00
rektdeckard
98ef9db51a DetailsPanel: Add close button title 2021-03-06 20:31:31 -05:00
rektdeckard
14c8807234 StyleInput: make sure component behaves as controlled on first render
We made the error of setting the value of this component statically,
rather than based on global IconWeight state. This meant that it was not
reflecting the current weight on first render, if it was anything other
than 'regular', for example when set by a URL param.
2021-01-08 15:49:53 -05:00
rektdeckard
c3787fcde0 Parameters: refactor and add more supported params
This patch replaces the component-based URL Parameter matcher with a
hook-based approach. We now watch for, parse, and normalize URL params
for 'color', 'weight', and 'size'.
2021-01-08 15:34:26 -05:00
rektdeckard
5166b0345c Parameters: grab 'color' URL param to override starting iconColor 2021-01-07 18:47:04 -05:00
rektdeckard
4d602cfce2 public: add phosphor-android wallpaper config 2020-12-12 14:26:00 -05:00
rektdeckard
e981a86dee README: add link to phosphor-webcomponents 2020-11-28 16:23:11 -05:00
rektdeckard
1390dfae4d deps: update to phosphor-react@1.1.2 2020-11-26 01:10:56 -05:00
rektdeckard
ce0d323bd5 public: modify .htaccess to redirect nonexistent routes to index.html 2020-11-26 01:07:42 -05:00
rektdeckard
7bf1833ea2 deps: update to phosphor-react@1.1.1 2020-11-24 20:15:16 -05:00
rektdeckard
de97e02427 icons+deps: update to phosphor-react@1.1.0 and enable new 2020-11-24 15:55:23 -05:00
rektdeckard
2e9c7870bd lib: retag IconCategory.MAP string 2020-11-24 13:18:53 -05:00
rektdeckard
fe656731fd DetailsPanel+README: switch to kebab-case for Vue components 2020-11-24 00:38:52 -05:00
rektdeckard
0ea6cdc930 Footer: update TF link to portfolio 2020-11-17 23:07:17 -05:00
rektdeckard
71c6a6927c icons: use "*new*" tag to disambiguate from plus/add-like 2020-11-15 17:24:09 -05:00
rektdeckard
30e777f856 icons: add "new" tags to icons making first appearance 2020-11-14 23:15:42 -05:00
rektdeckard
71eba27c92 icons: add new icons and tags for v1.1.0 2020-11-14 22:55:28 -05:00
rektdeckard
1221b5628b icons: additional tagging 2020-11-12 01:57:41 -05:00
rektdeckard
6fdef06b75 libs: update React and Recoil 2020-11-11 12:30:47 -05:00
rektdeckard
e7865e25e7 public: add Rich Search Results metadata 2020-11-11 12:29:37 -05:00
rektdeckard
8a30bc5990 public: test out adding structured data schema 2020-11-08 14:52:41 -05:00
rektdeckard
d0c4891480 IconGrid: potentially stupid-big loadtime gains
By adding 'content-visibility: auto;' we were able to see an 8x
improvement on rendering time and a 25x improvement on paint times for
first load. We may need to do some work to bring similar gains to
non-Chrome useragents.
2020-11-05 16:47:13 -05:00
rektdeckard
20b077a05f meta: remove unnecessary phosphor-icons dependency 2020-11-02 22:29:56 -05:00
rektdeckard
ea1793a0fa Links: replace Figma library link with current 2020-10-30 18:17:27 -04:00
rektdeckard
3b0d30ed04 DetailsPanel: up PNG download size to 256px 2020-10-25 20:16:43 -04:00
rektdeckard
3055fbb955 icons: add tags 2020-10-25 17:09:07 -04:00
rektdeckard
e38f82501d DetailsPanel: revert copy SVG text 2020-10-25 16:52:18 -04:00
rektdeckard
55931e9f13 meta: rename repo phosphor-web -> phosphor-home 2020-10-25 16:51:18 -04:00
rektdeckard
40f345b0d2 Links: correct Figma plugin link 2020-10-16 02:27:28 -04:00
rektdeckard
60c3aecc34 meta: bump to v1.0.1 2020-10-15 16:37:01 -04:00
rektdeckard
cdc14e8ddd Links: add Figma plugin 2020-10-15 16:36:37 -04:00
rektdeckard
5207219415 icons: add money tags 2020-10-15 12:16:58 -04:00
67 changed files with 7075 additions and 1029 deletions

View File

@@ -1,5 +1,5 @@
{
// Place your phosphor-web workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// Place your phosphor-home workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
// is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
@@ -21,10 +21,10 @@
"{",
"\tname: \"${1:name}\",",
"\tcategories: [IconCategory${2:categories}],",
"\ttags: [${3:tags}],",
"\tIcon: ${4:icon},",
"\ttags: [\"*new*\", ${3:tags}],",
"\tIcon: Icons.${4:icon},",
"},"
],
"description": "Create an IconEntry for phosphor-web"
"description": "Create an IconEntry for phosphor-home"
}
}

View File

@@ -4,7 +4,7 @@
Phosphor is a flexible icon family for interfaces, diagrams, presentations — whatever, really.
- 588 icons and counting
- 772 icons and counting
- 6 weights: **Thin**, **Light**, **Regular**, **Bold**, **Fill**, and **Duotone**
- Designed at 16 x 16px to read well small and scale up big
- Raw stroke information retained to fine-tune the style
@@ -67,9 +67,9 @@ ReactDOM.render(<App />, document.getElementById("root"));
```html
<template>
<div>
<PhHorse />
<PhHeart :size="32" color="hotpink" weight="fill" />
<PhCube />
<ph-horse />
<ph-heart :size="32" color="hotpink" weight="fill" />
<ph-cube />
</div>
</template>
@@ -86,13 +86,15 @@ ReactDOM.render(<App />, document.getElementById("root"));
</script>
```
> **Note:** Due to possible namespace collisions with built-in HTML elements, compononent names in the Vue library are prefixed with `Ph`, but otherwise follow the same naming conventions.
> **Note:** Due to possible namespace collisions with built-in HTML elements, compononent names in the Vue library are prefixed with `Ph`, but otherwise follow the same naming conventions. Both Pascal and kebab-case conventions can be used in templates.
## Related Projects
- [phosphor-react](https://github.com/phosphor-icons/phosphor-react) ▲ Phosphor icon component library for React
- [phosphor-vue](https://github.com/phosphor-icons/phosphor-vue) ▲ Phosphor icon component library for Vue
- [phosphor-icons](https://github.com/phosphor-icons/phosphor-icons) ▲ Phosphor icons for Vanilla JS
- [phosphor-flutter](https://github.com/phosphor-icons/phosphor-flutter) ▲ Phosphor IconData library for Flutter
- [phosphor-webcomponents](https://github.com/phosphor-icons/phosphor-webcomponents) ▲ Phosphor icons as Web Components
- [phosphor-figma](https://github.com/phosphor-icons/phosphor-figma) ▲ Phosphor icons Figma plugin
## License

View File

@@ -1,6 +1,6 @@
{
"name": "phosphor-web",
"version": "1.0.0",
"name": "phosphor-home",
"version": "1.2.1",
"license": "MIT",
"homepage": "https://phosphoricons.com",
"author": {
@@ -18,23 +18,26 @@
"UI",
"UX"
],
"repository": "github:phosphor-icons/phosphor-web",
"private": false,
"repository": "github:phosphor-icons/phosphor-home",
"private": true,
"dependencies": {
"@types/braintree-web-drop-in": "^1.22.3",
"axios": "^0.21.1",
"braintree-web-drop-in": "^1.30.1",
"file-saver": "^2.0.2",
"framer-motion": "^2.1.0",
"framer-motion": "^3.10.0",
"fuse.js": "^6.4.1",
"phosphor-icons": "^1.0.0",
"phosphor-react": "^0.6.0",
"react": "^17.0.0-rc.0",
"react-dom": "^17.0.0-rc.0",
"phosphor-react": "^1.2.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-dropdown-select": "^4.4.2",
"react-ga": "^3.1.2",
"react-hotkeys-hook": "^3.2.1",
"react-scripts": "3.4.1",
"react-use": "^15.3.2",
"recoil": "^0.0.13",
"recoil": "^0.1.3",
"svg2png-converter": "^1.0.0",
"tinycolor2": "^1.4.1"
"tinycolor2": "^1.4.2"
},
"scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'",

9
public/.htaccess Normal file
View File

@@ -0,0 +1,9 @@
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
Options +SymLinksIfOwnerMatch
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

View File

@@ -0,0 +1,242 @@
{
"Collections": [
{
"name": "abstract",
"preview_url": "https://i.imgur.com/xBCTxrP.png",
"preview_thumbnail_url": "https://i.imgur.com/xBCTxrPl.jpg"
},
{
"name": "architecture",
"preview_url": "https://i.imgur.com/pdV0KQ1.png",
"preview_thumbnail_url": "https://i.imgur.com/pdV0KQ1l.jpg"
},
{
"name": "landscape",
"preview_url": "https://i.imgur.com/EEBaeFE.png",
"preview_thumbnail_url": "https://i.imgur.com/EEBaeFEl.jpg"
},
{
"name": "minimal",
"preview_url": "https://i.imgur.com/peX5qVO.png",
"preview_thumbnail_url": "https://i.imgur.com/peX5qVOl.jpg"
}
],
"Wallpapers": [
{
"name": "Antelope Canyon",
"author": "Daniel Olah Nvez",
"url": "https://i.imgur.com/KYglyUn.png",
"thumbnail": "https://i.imgur.com/KYglyUl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Fractured Light",
"author": "Chris Limbrick",
"url": "https://i.imgur.com/MILbsga.png",
"thumbnail": "https://i.imgur.com/MILbsgal.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "The Forest Path",
"author": "Kristaps Ungurs",
"url": "https://i.imgur.com/95QLblG.png",
"thumbnail": "https://i.imgur.com/95QLblGl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Taken",
"author": "Touann Gatouillat",
"url": "https://i.imgur.com/otCPhH7.png",
"thumbnail": "https://i.imgur.com/otCPhH7l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Construct",
"author": "Florian Olivo",
"url": "https://i.imgur.com/7CxJsXn.png",
"thumbnail": "https://i.imgur.com/7CxJsXnl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "Redline",
"author": "Sergio Ibannez",
"url": "https://i.imgur.com/uja4O1m.png",
"thumbnail": "https://i.imgur.com/uja4O1ml.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "End Of Line",
"author": "Claudio Schwarz-Purzlbaum",
"url": "https://i.imgur.com/2ZiqhE3.png",
"thumbnail": "https://i.imgur.com/2ZiqhE3l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "Downtown",
"author": "Van Mendoza",
"url": "https://i.imgur.com/sKizrcp.png",
"thumbnail": "https://i.imgur.com/sKizrcpl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "Omnicorp",
"author": "Irina Iriser",
"url": "https://i.imgur.com/Zx11fXx.png",
"thumbnail": "https://i.imgur.com/Zx11fXxl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "Pinball Wizard",
"author": "Joey Banks",
"url": "https://i.imgur.com/XpVCRrj.png",
"thumbnail": "https://i.imgur.com/XpVCRrjl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "Chinatown",
"author": "Donny Jiang",
"url": "https://i.imgur.com/mz8mTVC.png",
"thumbnail": "https://i.imgur.com/mz8mTVCl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "FDR Drive",
"author": "Donny Jiang",
"url": "https://i.imgur.com/elbdmZk.png",
"thumbnail": "https://i.imgur.com/elbdmZkl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Through the Fog",
"author": "Zhimai Zhang",
"url": "https://i.imgur.com/KQIss5a.png",
"thumbnail": "https://i.imgur.com/KQIss5al.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Kids Will Play",
"author": "Perry C",
"url": "https://i.imgur.com/IieNbdS.png",
"thumbnail": "https://i.imgur.com/IieNbdSl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "Double Blind",
"author": "Pau Casals",
"url": "https://i.imgur.com/kKyn0dW.png",
"thumbnail": "https://i.imgur.com/kKyn0dWl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "All-Seeing Eye",
"author": "Alex Rainer",
"url": "https://i.imgur.com/HtyCalZ.png",
"thumbnail": "https://i.imgur.com/HtyCalZl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Methylene",
"author": "Pim Myten",
"url": "https://i.imgur.com/vOAYeEW.png",
"thumbnail": "https://i.imgur.com/vOAYeEWl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Nexus",
"author": "Alexander Popov",
"url": "https://i.imgur.com/3q2e7N2.png",
"thumbnail": "https://i.imgur.com/3q2e7N2l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Synthetic",
"author": "Leyy M",
"url": "https://i.imgur.com/ASKhMFU.png",
"thumbnail": "https://i.imgur.com/ASKhMFUl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Nondeterminism",
"author": "Alex Perez",
"url": "https://i.imgur.com/6dtZBAW.png",
"thumbnail": "https://i.imgur.com/6dtZBAWl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "In the Beginning",
"author": "Pawel Czerwinski",
"url": "https://i.imgur.com/gBSjMh2.png",
"thumbnail": "https://i.imgur.com/gBSjMh2l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "The Swarm",
"author": "Vino Li",
"url": "https://i.imgur.com/yljYDqp.png",
"thumbnail": "https://i.imgur.com/yljYDqpl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Moonrise",
"author": "Adrian Swancar",
"url": "https://i.imgur.com/NiSCb6W.png",
"thumbnail": "https://i.imgur.com/NiSCb6Wl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Cerro",
"author": "Tamas Tuzes Katai",
"url": "https://i.imgur.com/5u4aM1y.png",
"thumbnail": "https://i.imgur.com/5u4aM1yl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
}
]
}

View File

@@ -0,0 +1,409 @@
{
"Collections": [
{
"name": "Abstract",
"preview_url": "https://i.imgur.com/8DTRYwb.png",
"preview_thumbnail_url": "https://i.imgur.com/8DTRYwbl.jpg"
},
{
"name": "Architecture",
"preview_url":"https://i.imgur.com/t6BTASJ.png",
"preview_thumbnail_url": "https://i.imgur.com/t6BTASJl.jpg"
},
{
"name": "Landscape",
"preview_url": "https://i.imgur.com/G8cgftc.png",
"preview_thumbnail_url": "https://i.imgur.com/G8cgftcl.jpg"
},
{
"name": "Minimal",
"preview_url": "https://i.imgur.com/Srt9bP3.png",
"preview_thumbnail_url": "https://i.imgur.com/Srt9bP3l.jpg"
},
{
"name": "Solids",
"preview_url": "https://i.imgur.com/fzL4yoj.png",
"preview_thumbnail_url": "https://i.imgur.com/fzL4yojl.jpg"
}
],
"Wallpapers": [
{
"name": "Arctic",
"author": "Phosphor",
"url": "https://i.imgur.com/4qopfYy.png",
"thumbnail": "https://i.imgur.com/4qopfYyl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "solids"
},
{
"name": "Saffron",
"author": "Phosphor",
"url": "https://i.imgur.com/fzL4yoj.png",
"thumbnail": "https://i.imgur.com/fzL4yojl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "solids"
},
{
"name": "Heliotrope",
"author": "Phosphor",
"url": "https://i.imgur.com/QsrKIjp.png",
"thumbnail": "https://i.imgur.com/QsrKIjpl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "solids"
},
{
"name": "Jade",
"author": "Phosphor",
"url": "https://i.imgur.com/Z29e7f7.png",
"thumbnail": "https://i.imgur.com/Z29e7f7l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "solids"
},
{
"name": "Soft Dunes",
"author": "Kunj Parekh",
"url": "https://i.imgur.com/vIAE5jd.png",
"thumbnail": "https://i.imgur.com/vIAE5jdl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscapes"
},
{
"name": "Lake at Dawn",
"author": "Max Fuchs",
"url": "https://i.imgur.com/4Nmefrv.png",
"thumbnail": "https://i.imgur.com/4Nmefrvl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "Doors of Perception",
"author": "Philipp Berndt",
"url": "https://i.imgur.com/Srt9bP3.png",
"thumbnail": "https://i.imgur.com/Srt9bP3l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "TwoTone",
"author": "Samuel Zeller",
"url": "https://i.imgur.com/8DTRYwb.png",
"thumbnail": "https://i.imgur.com/8DTRYwbl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Empty Court",
"author": "35mm",
"url": "https://i.imgur.com/rPSLdCD.png",
"thumbnail": "https://i.imgur.com/rPSLdCDl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Edge of the Pool",
"author": "Autumn Studio",
"url": "https://i.imgur.com/qNXWTej.png",
"thumbnail": "https://i.imgur.com/qNXWTejl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "One in the Hand",
"author": "Rainon Franco",
"url": "https://i.imgur.com/QhW4UDc.png",
"thumbnail": "https://i.imgur.com/QhW4UDcl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Solitude",
"author": "Braxton Stuntz",
"url": "https://i.imgur.com/QlQ9tMO.png",
"thumbnail": "https://i.imgur.com/QlQ9tMOl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Double Fault",
"author": "Dane Deaner",
"url": "https://i.imgur.com/ERMWJSe.png",
"thumbnail": "https://i.imgur.com/ERMWJSel.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Lomo 800",
"author": "Markus Spiske",
"url": "https://i.imgur.com/bHPWGPQ.png",
"thumbnail": "https://i.imgur.com/bHPWGPQl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Clothespins",
"author": "Plush Design Studio",
"url": "https://i.imgur.com/xPyXBL9.png",
"thumbnail": "https://i.imgur.com/xPyXBL9l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Memory Tapes",
"author": "Imani Clovis",
"url": "https://i.imgur.com/cmWuvUT.png",
"thumbnail": "https://i.imgur.com/cmWuvUTl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "Contours in White",
"author": "Jean Philippe del Berghe",
"url": "https://i.imgur.com/wjxl9xT.png",
"thumbnail": "https://i.imgur.com/wjxl9xTl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "Awaiting Inspiration",
"author": "Joanna Kosinska",
"url": "https://i.imgur.com/SBtlZmn.png",
"thumbnail": "https://i.imgur.com/SBtlZmnl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Succulent",
"author": "Khai Sze Ong",
"url": "https://i.imgur.com/yDD2wz8.png",
"thumbnail": "https://i.imgur.com/yDD2wz8l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Tracks in the Sand",
"author": "Ruben Bagues",
"url": "https://i.imgur.com/G8cgftc.png",
"thumbnail": "https://i.imgur.com/G8cgftcl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape,minimal"
},
{
"name": "Starched Linen",
"author": "Annie Spratt",
"url": "https://i.imgur.com/W9nAQVR.png",
"thumbnail": "https://i.imgur.com/W9nAQVRl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Delamination",
"author": "Wesley Tingey",
"url": "https://i.imgur.com/VNJ3xWG.png",
"thumbnail": "https://i.imgur.com/VNJ3xWGl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Look Up",
"author": "Tony Dinh",
"url": "https://i.imgur.com/t6BTASJ.png",
"thumbnail": "https://i.imgur.com/t6BTASJl.jpgg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture,minimal"
},
{
"name": "Keep to the Right",
"author": "hello i m nik",
"url": "https://i.imgur.com/SHp6pkv.png",
"thumbnail": "https://i.imgur.com/SHp6pkvl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture,minimal"
},
{
"name": "Pink Paper",
"author": "Alex Koch",
"url": "https://i.imgur.com/OHPR80R.png",
"thumbnail": "https://i.imgur.com/OHPR80Rl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Lavender Dunes",
"author": "Alex Koch",
"url": "https://i.imgur.com/Sb50W4f.png",
"thumbnail": "https://i.imgur.com/Sb50W4fl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Cotton Candy Clouds",
"author": "Autumn Studio",
"url": "https://i.imgur.com/43Vf2hT.png",
"thumbnail": "https://i.imgur.com/43Vf2hTl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Pineapple",
"author": "Pineaaple Supply Co.",
"url": "https://i.imgur.com/YK9TyNk.png",
"thumbnail": "https://i.imgur.com/YK9TyNkl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Cuttings",
"author": "Alex Loup",
"url": "https://i.imgur.com/wp2S7TK.png",
"thumbnail": "https://i.imgur.com/wp2S7TKl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Textured Ombre Wall",
"author": "Bharath G.S.",
"url": "https://i.imgur.com/kxBGzva.png",
"thumbnail": "https://i.imgur.com/kxBGzval.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "The Loading Dock",
"author": "Ph. B.",
"url": "https://i.imgur.com/NmL5Ldm.png",
"thumbnail": "https://i.imgur.com/NmL5Ldml.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Leaning Dwarf Pine",
"author": "Caleb George",
"url": "https://i.imgur.com/crgckrr.png",
"thumbnail": "https://i.imgur.com/crgckrrl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Dunes in Hard Light",
"author": "Heather Shevlin",
"url": "https://i.imgur.com/LG0G1IO.png",
"thumbnail": "https://i.imgur.com/LG0G1IOl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "3 Balloons",
"author": "Amy Shamblen",
"url": "https://i.imgur.com/5HHCh12.png",
"thumbnail": "https://i.imgur.com/5HHCh12l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Bicolor Bricks",
"author": "Pawel Czerwinski",
"url": "https://i.imgur.com/i4VrEDH.png",
"thumbnail": "https://i.imgur.com/i4VrEDHl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Acrid Sky",
"author": "W",
"url": "https://i.imgur.com/RUSz9mM.png",
"thumbnail": "https://i.imgur.com/RUSz9mMl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Salmon Colored Smoke",
"author": "Pawel Czerwinski",
"url": "https://i.imgur.com/8wehlrT.png",
"thumbnail": "https://i.imgur.com/8wehlrTl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "Polygonal Grid",
"author": "Scott Webb",
"url": "https://i.imgur.com/voUtZhY.png",
"thumbnail": "https://i.imgur.com/voUtZhYl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture,minimal"
},
{
"name": "Clay Courts",
"author": "Ph. B.",
"url": "https://i.imgur.com/yd7OmyV.png",
"thumbnail": "https://i.imgur.com/yd7OmyVl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Lavender on Yellow",
"author": "Mona Eendra",
"url": "https://i.imgur.com/p8T1V7N.png",
"thumbnail": "https://i.imgur.com/p8T1V7Nl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal,landscape"
},
{
"name": "Whispering Pines",
"author": "Mads Schmidt Rasmussen",
"url": "https://i.imgur.com/FLkrDVZ.png",
"thumbnail": "https://i.imgur.com/FLkrDVZl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "All the Light Touches",
"author": "Eberhard Grossgasteiger",
"url": "https://i.imgur.com/cwUvsmS.png",
"thumbnail": "https://i.imgur.com/cwUvsmSl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

View File

@@ -0,0 +1,350 @@
{
"Collections": [
{
"name": "abstract",
"preview_url": "https://i.imgur.com/xBCTxrP.png",
"preview_thumbnail_url": "https://i.imgur.com/xBCTxrPl.jpg"
},
{
"name": "architecture",
"preview_url": "https://i.imgur.com/pdV0KQ1.png",
"preview_thumbnail_url": "https://i.imgur.com/pdV0KQ1l.jpg"
},
{
"name": "landscape",
"preview_url": "https://i.imgur.com/EEBaeFE.png",
"preview_thumbnail_url": "https://i.imgur.com/EEBaeFEl.jpg"
},
{
"name": "minimal",
"preview_url": "https://i.imgur.com/peX5qVO.png",
"preview_thumbnail_url": "https://i.imgur.com/peX5qVOl.jpg"
}
],
"Wallpapers": [
{
"name": "Dunes at Dusk",
"author": "Jeremy Bishop",
"url": "https://i.imgur.com/EEBaeFE.png",
"thumbnail": "https://i.imgur.com/EEBaeFEl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Black Sand",
"author": "Adrien Olichon",
"url": "https://i.imgur.com/Yt8zaUn.png",
"thumbnail": "https://i.imgur.com/Yt8zaUnl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Disappearing Coastline",
"author": "Chris Coe",
"url": "https://i.imgur.com/hq4aENh.png",
"thumbnail": "https://i.imgur.com/hq4aENhl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal,landscape"
},
{
"name": "Setting Out",
"author": "Tim Trad",
"url": "https://i.imgur.com/42uDJkj.png",
"thumbnail": "https://i.imgur.com/42uDJkjl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Dark Tides",
"author": "Mike Yukhtenko",
"url": "https://i.imgur.com/XSIIUAQ.png",
"thumbnail": "https://i.imgur.com/XSIIUAQl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Rogue Wave",
"author": "Jack B",
"url": "https://i.imgur.com/YVHtCTT.png",
"thumbnail": "https://i.imgur.com/YVHtCTTl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Strata",
"author": "Joshua Oluwagbemiga",
"url": "https://i.imgur.com/uvRONTa.png",
"thumbnail": "https://i.imgur.com/uvRONTal.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "Condolences",
"author": "Annie Spratt",
"url": "https://i.imgur.com/peX5qVO.png",
"thumbnail": "https://i.imgur.com/peX5qVOl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Ferns",
"author": "Andras Vas",
"url": "https://i.imgur.com/wXvAISN.png",
"thumbnail": "https://i.imgur.com/wXvAISNl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Blades of Grass",
"author": "Claudio Testa",
"url": "https://i.imgur.com/0QOoq8R.png",
"thumbnail": "https://i.imgur.com/0QOoq8Rl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Lush",
"author": "Ian Espinosa",
"url": "https://i.imgur.com/AumRAb4.png",
"thumbnail": "https://i.imgur.com/AumRAb4l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Amethyst Bloom",
"author": "Alyssa Smith",
"url": "https://i.imgur.com/96JmZIF.png",
"thumbnail": "https://i.imgur.com/96JmZIFl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Carbon",
"author": "David Jorre",
"url": "https://i.imgur.com/hkN3ioi.png",
"thumbnail": "https://i.imgur.com/hkN3ioil.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "Charred Remains",
"author": "Brian Patrick Tagalog",
"url": "https://i.imgur.com/SbyCpR2.png",
"thumbnail": "https://i.imgur.com/SbyCpR2l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "Make a Wish",
"author": "Wil Stewart",
"url": "https://i.imgur.com/VeuzvUA.png",
"thumbnail": "https://i.imgur.com/VeuzvUAl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Resonance",
"author": "Luke Stackpoole",
"url": "https://i.imgur.com/94SjlPi.png",
"thumbnail": "https://i.imgur.com/94SjlPil.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "An Endless Mist",
"author": "Yoal Desurmont",
"url": "https://i.imgur.com/Qkng6Dm.png",
"thumbnail": "https://i.imgur.com/Qkng6Dml.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Elevation",
"author": "Manuel Will",
"url": "https://i.imgur.com/yQMGOAb.png",
"thumbnail": "https://i.imgur.com/yQMGOAbl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Rock Show",
"author": "Raphael Schaller",
"url": "https://i.imgur.com/DMi6ffB.png",
"thumbnail": "https://i.imgur.com/DMi6ffBl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Motes",
"author": "Samuel Zeller",
"url": "https://i.imgur.com/kOIWSNJ.png",
"thumbnail": "https://i.imgur.com/kOIWSNJl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Birds on a Wire",
"author": "Adrian Kirkegaard",
"url": "https://i.imgur.com/M3dlKS4.png",
"thumbnail": "https://i.imgur.com/M3dlKS4l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Interleaved",
"author": "Ron Whitaker",
"url": "https://i.imgur.com/QQ7WQvD.png",
"thumbnail": "https://i.imgur.com/QQ7WQvDl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
},
{
"name": "Elliptic",
"author": "Tobias van Schneider",
"url": "https://i.imgur.com/xBCTxrP.png",
"thumbnail": "https://i.imgur.com/xBCTxrPl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
},
{
"name": "Convergence",
"author": "Josh Rose",
"url": "https://i.imgur.com/uqBhWYH.png",
"thumbnail": "https://i.imgur.com/uqBhWYHl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
},
{
"name": "Baffles",
"author": "Elena Saharova",
"url": "https://i.imgur.com/l2L6u1E.png",
"thumbnail": "https://i.imgur.com/l2L6u1El.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture,minimal"
},
{
"name": "Polygonal",
"author": "Carrie Yang",
"url": "https://i.imgur.com/pdV0KQ1.png",
"thumbnail": "https://i.imgur.com/pdV0KQ1l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
},
{
"name": "S-Curve",
"author": "Tobias van Schneider",
"url": "https://i.imgur.com/Y1A9GTi.png",
"thumbnail": "https://i.imgur.com/Y1A9GTil.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
},
{
"name": "Galaxy Swirls",
"author": "Pawel Czerwinski",
"url": "https://i.imgur.com/KrxLGxy.png",
"thumbnail": "https://i.imgur.com/KrxLGxyl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Prismatic Dreams",
"author": "Sean Sinclair",
"url": "https://i.imgur.com/byLsXXB.png",
"thumbnail": "https://i.imgur.com/byLsXXBl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Slot Canyon",
"author": "Meric Dagli",
"url": "https://i.imgur.com/hB90xvB.png",
"thumbnail": "https://i.imgur.com/hB90xvBl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Crescent Moonrise",
"author": "Val Vesa",
"url": "https://i.imgur.com/nfoPdRd.png",
"thumbnail": "https://i.imgur.com/nfoPdRdl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Eye of the Storm",
"author": "Breno Machado",
"url": "https://i.imgur.com/BliGpTl.png",
"thumbnail": "https://i.imgur.com/BliGpTll.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Thundercloud",
"author": "Bryan Minear",
"url": "https://i.imgur.com/mK8JE0t.png",
"thumbnail": "https://i.imgur.com/mK8JE0tl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Departmental Security",
"author": "Bartosz Wanot",
"url": "https://i.imgur.com/wRN7lDd.png",
"thumbnail": "https://i.imgur.com/wRN7lDdl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "CMatrix",
"author": "Maekus Spiske",
"url": "https://i.imgur.com/QAsjQkP.png",
"thumbnail": "https://i.imgur.com/QAsjQkPl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Neon Serif",
"author": "Zuzanna Adamcyzk",
"url": "https://i.imgur.com/3edF6DE.png",
"thumbnail": "https://i.imgur.com/3edF6DEl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
}
]
}

View File

@@ -0,0 +1,422 @@
{
"Collections": [
{
"name": "abstract",
"preview_url": "",
"preview_thumbnail_url": ""
},
{
"name": "architecture",
"preview_url": "",
"preview_thumbnail_url": ""
},
{
"name": "landscape",
"preview_url": "",
"preview_thumbnail_url": ""
},
{
"name": "minimal",
"preview_url": "",
"preview_thumbnail_url": ""
}
],
"Wallpapers": [
{
"name": "Retro Sunrise",
"author": "Maxim Medvedev",
"url": "https://i.imgur.com/kCtyGwT.png",
"thumbnail": "https://i.imgur.com/kCtyGwTl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Tawny Peak",
"author": "Andreas Kind",
"url": "https://i.imgur.com/fqxcpJU.png",
"thumbnail": "https://i.imgur.com/fqxcpJUl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "First Light",
"author": "Adrien Olichon",
"url": "https://i.imgur.com/EakVjSC.png",
"thumbnail": "https://i.imgur.com/EakVjSCl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Rosy Dunes",
"author": "Paxel Nolbert",
"url": "https://i.imgur.com/lD06npE.png",
"thumbnail": "https://i.imgur.com/lD06npEl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Waking Up",
"author": "Dhaval Parmar",
"url": "https://i.imgur.com/eBenVs8.png",
"thumbnail": "https://i.imgur.com/eBenVs8l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "The Great Outdoors",
"author": "Gauravdeep Singh Bansal",
"url": "https://i.imgur.com/gJ40ptR.png",
"thumbnail": "https://i.imgur.com/gJ40ptRl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Make a Wish",
"author": "Diego Ph",
"url": "https://i.imgur.com/vJagBNf.png",
"thumbnail": "https://i.imgur.com/vJagBNfl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Lateral Strike",
"author": "Damon Lam",
"url": "https://i.imgur.com/BeZHVcY.png",
"thumbnail": "https://i.imgur.com/BeZHVcYl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Starfield",
"author": "Guilherme Stecanella",
"url": "https://i.imgur.com/pDjDeVr.png",
"thumbnail": "https://i.imgur.com/pDjDeVrl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Smallness",
"author": "Melanie Magdalena",
"url": "https://i.imgur.com/658blVF.png",
"thumbnail": "https://i.imgur.com/658blVFl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Alone at the Summit",
"author": "Aleks Dahlberg",
"url": "https://i.imgur.com/YKeQ9sc.png",
"thumbnail": "https://i.imgur.com/YKeQ9scl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Like Waves",
"author": "Calvin Ma",
"url": "https://i.imgur.com/wbNiiie.png",
"thumbnail": "https://i.imgur.com/wbNiiiel.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Cloud Cover",
"author": "Adrian",
"url": "https://i.imgur.com/02uf66E.png",
"thumbnail": "https://i.imgur.com/02uf66El.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Tiled",
"author": "Fabrizio Conti",
"url": "https://i.imgur.com/mAfbAsG.png",
"thumbnail": "https://i.imgur.com/mAfbAsGl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal,architecture"
},
{
"name": "Brutalism",
"author": "Andrej Lisakov",
"url": "https://i.imgur.com/9JlGo4m.png",
"thumbnail": "https://i.imgur.com/9JlGo4ml.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal,architecture"
},
{
"name": "Arrayed",
"author": "Robert Haverly",
"url": "https://i.imgur.com/SGA180g.png",
"thumbnail": "https://i.imgur.com/SGA180gl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal,architecture"
},
{
"name": "Placidity",
"author": "Julian Bock",
"url": "https://i.imgur.com/T7PwRnh.png",
"thumbnail": "https://i.imgur.com/T7PwRnhl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Sea Change",
"author": "Samara Doole",
"url": "https://i.imgur.com/ekcUJ2M.png",
"thumbnail": "https://i.imgur.com/ekcUJ2Ml.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Choppy",
"author": "Imleedh Ali",
"url": "https://i.imgur.com/2bk3vxM.png",
"thumbnail": "https://i.imgur.com/2bk3vxMl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Below the Crush",
"author": "Jeremy Bishop",
"url": "https://i.imgur.com/h244SGI.png",
"thumbnail": "https://i.imgur.com/h244SGIl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Betta",
"author": "Aung Soe Min",
"url": "https://i.imgur.com/YOBYine.png",
"thumbnail": "https://i.imgur.com/YOBYinel.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Last One in the Pack",
"author": "Alfaz Sayed",
"url": "https://i.imgur.com/tP0SOFS.png",
"thumbnail": "https://i.imgur.com/tP0SOFSl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Basement Window",
"author": "Taylor Young",
"url": "https://i.imgur.com/V7srimE.png",
"thumbnail": "https://i.imgur.com/V7srimEl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Cellular",
"author": "Christina Kirschnerova",
"url": "https://i.imgur.com/lePTybt.png",
"thumbnail": "https://i.imgur.com/lePTybtl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Ignition",
"author": "Roland Larsson",
"url": "https://i.imgur.com/v4si6N2.png",
"thumbnail": "https://i.imgur.com/v4si6N2l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Falling Light",
"author": "Rene Bohmer",
"url": "https://i.imgur.com/1U953Cb.png",
"thumbnail": "https://i.imgur.com/1U953Cbl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Vices",
"author": "Jaredd Craig",
"url": "https://i.imgur.com/a2xwnHK.png",
"thumbnail": "https://i.imgur.com/a2xwnHKl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Your Worst Nightmare",
"author": "Elti Meshau",
"url": "https://i.imgur.com/9ajAMtL.png",
"thumbnail": "https://i.imgur.com/9ajAMtLl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Tail Lights",
"author": "Shaunak Mirashi",
"url": "https://i.imgur.com/tL6d50t.png",
"thumbnail": "https://i.imgur.com/tL6d50tl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "Rapid Transit",
"author": "Kevin Clyde Berbano",
"url": "https://i.imgur.com/JxXJxDZ.png",
"thumbnail": "https://i.imgur.com/JxXJxDZl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "Storms Ahead",
"author": "Luke Stackpoole",
"url": "https://i.imgur.com/ZBMCKbt.png",
"thumbnail": "https://i.imgur.com/ZBMCKbtl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Truss",
"author": "Phil Botha",
"url": "https://i.imgur.com/q4qNcui.png",
"thumbnail": "https://i.imgur.com/q4qNcuil.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "T",
"author": "Joshua Rivera",
"url": "https://i.imgur.com/84O8dFa.png",
"thumbnail": "https://i.imgur.com/84O8dFal.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture,minimal"
},
{
"name": "Shadows on the Wall",
"author": "Rene Bohmer",
"url": "https://i.imgur.com/09GgsVW.png",
"thumbnail": "https://i.imgur.com/09GgsVWl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Fluid Dynamics",
"author": "Pawel Czerwinski",
"url": "https://i.imgur.com/AaD8SLO.png",
"thumbnail": "https://i.imgur.com/AaD8SLOl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Ombre",
"author": "Elliott Engelmann",
"url": "https://i.imgur.com/5jsq9Jg.png",
"thumbnail": "https://i.imgur.com/5jsq9Jgl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Black Sand",
"author": "Adrien Olichon",
"url": "https://i.imgur.com/Yt8zaUn.png",
"thumbnail": "https://i.imgur.com/Yt8zaUnl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Carbon",
"author": "David Jorre",
"url": "https://i.imgur.com/hkN3ioi.png",
"thumbnail": "https://i.imgur.com/hkN3ioil.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "Charred Remains",
"author": "Brian Patrick Tagalog",
"url": "https://i.imgur.com/SbyCpR2.png",
"thumbnail": "https://i.imgur.com/SbyCpR2l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,minimal"
},
{
"name": "Water Fountain",
"author": "Quin Stevenson",
"url": "https://i.imgur.com/Bz5u4HA.png",
"thumbnail": "https://i.imgur.com/Bz5u4HAl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "minimal"
},
{
"name": "Interleaved",
"author": "Ron Whitaker",
"url": "https://i.imgur.com/QQ7WQvD.png",
"thumbnail": "https://i.imgur.com/QQ7WQvDl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
},
{
"name": "Elliptic",
"author": "Tobias van Schneider",
"url": "https://i.imgur.com/xBCTxrP.png",
"thumbnail": "https://i.imgur.com/xBCTxrPl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
},
{
"name": "Convergence",
"author": "Josh Rose",
"url": "https://i.imgur.com/uqBhWYH.png",
"thumbnail": "https://i.imgur.com/uqBhWYHl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
},
{
"name": "S-Curve",
"author": "Tobias van Schneider",
"url": "https://i.imgur.com/Y1A9GTi.png",
"thumbnail": "https://i.imgur.com/Y1A9GTil.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
}
]
}

View File

@@ -0,0 +1,207 @@
{
"Collections": [
{
"name": "abstract",
"preview_url": "https://i.imgur.com/xBCTxrP.png",
"preview_thumbnail_url": "https://i.imgur.com/xBCTxrPl.jpg"
},
{
"name": "architecture",
"preview_url": "https://i.imgur.com/pdV0KQ1.png",
"preview_thumbnail_url": "https://i.imgur.com/pdV0KQ1l.jpg"
},
{
"name": "landscape",
"preview_url": "https://i.imgur.com/EEBaeFE.png",
"preview_thumbnail_url": "https://i.imgur.com/EEBaeFEl.jpg"
},
{
"name": "minimal",
"preview_url": "https://i.imgur.com/peX5qVO.png",
"preview_thumbnail_url": "https://i.imgur.com/peX5qVOl.jpg"
}
],
"Wallpapers": [
{
"name": "Echoes Of",
"author": "Zoltan Tasi",
"url": "https://i.imgur.com/OVKso33.png",
"thumbnail": "https://i.imgur.com/OVKso33l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Gradient #4B",
"author": "Luke Chesser",
"url": "https://i.imgur.com/iFrJbfE.png",
"thumbnail": "https://i.imgur.com/iFrJbfEl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Orthogonal",
"author": "Etienne Beauregard",
"url": "https://i.imgur.com/cFyjq7V.png",
"thumbnail": "https://i.imgur.com/cFyjq7Vl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "Filters Through",
"author": "Martin Adams",
"url": "https://i.imgur.com/r7MFJxM.png",
"thumbnail": "https://i.imgur.com/r7MFJxMl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Gehry",
"author": "Sascha Yeryomin",
"url": "https://i.imgur.com/jf5NX7F.png",
"thumbnail": "https://i.imgur.com/jf5NX7Fl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "The Benevolent Corp.",
"author": "Alex Iby",
"url": "https://i.imgur.com/SrgJtef.png",
"thumbnail": "https://i.imgur.com/SrgJtefl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "Bokehd",
"author": "Kristaps Solims",
"url": "https://i.imgur.com/HzU9KSK.png",
"thumbnail": "https://i.imgur.com/HzU9KSKl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Confluence",
"author": "Ash Edmonds",
"url": "https://i.imgur.com/HWwYY1t.png",
"thumbnail": "https://i.imgur.com/HWwYY1tl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "What Lies Beyond",
"author": "Cheng Feng",
"url": "https://i.imgur.com/BjdQkxh.png",
"thumbnail": "https://i.imgur.com/BjdQkxhl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Stairstep",
"author": "Dawid Sokolowski",
"url": "https://i.imgur.com/VXzW2tV.png",
"thumbnail": "https://i.imgur.com/VXzW2tVl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Bluesmoke",
"author": "Albert Bleeker",
"url": "https://i.imgur.com/mrltonO.png",
"thumbnail": "https://i.imgur.com/mrltonOl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Tensegrity",
"author": "Luca Bravo",
"url": "https://i.imgur.com/N69Gk81.png",
"thumbnail": "https://i.imgur.com/N69Gk81l.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "architecture"
},
{
"name": "Vertical Integration",
"author": "Pawl Czerwinski",
"url": "https://i.imgur.com/rWVitPA.png",
"thumbnail": "https://i.imgur.com/rWVitPAl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "T",
"author": "Joshua Rivera",
"url": "https://i.imgur.com/84O8dFa.png",
"thumbnail": "https://i.imgur.com/84O8dFal.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Ripples",
"author": "Julian Bock",
"url": "https://i.imgur.com/T7PwRnh.png",
"thumbnail": "https://i.imgur.com/T7PwRnhl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Light Speed",
"author": "Adrien Olichon",
"url": "https://i.imgur.com/cprtb1M.png",
"thumbnail": "https://i.imgur.com/cprtb1Ml.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract"
},
{
"name": "Dunes at Dusk",
"author": "Jeremy Bishop",
"url": "https://i.imgur.com/EEBaeFE.png",
"thumbnail": "https://i.imgur.com/EEBaeFEl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Black Sand",
"author": "Adrien Olichon",
"url": "https://i.imgur.com/Yt8zaUn.png",
"thumbnail": "https://i.imgur.com/Yt8zaUnl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "landscape"
},
{
"name": "Interleaved",
"author": "Ron Whitaker",
"url": "https://i.imgur.com/QQ7WQvD.png",
"thumbnail": "https://i.imgur.com/QQ7WQvDl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
},
{
"name": "Elliptic",
"author": "Tobias van Schneider",
"url": "https://i.imgur.com/xBCTxrP.png",
"thumbnail": "https://i.imgur.com/xBCTxrPl.jpg",
"downloadable": true,
"copyright": "CC0",
"collections": "abstract,architecture"
},
]
}

View File

@@ -18,7 +18,21 @@
itemprop="description"
content="A flexible icon family for interfaces, diagrams, presentations — whatever, really."
/>
<meta itemprop="image" content="https://phosphoricons.com/phosphor-opengraph.png" />
<meta
itemprop="image"
content="https://phosphoricons.com/phosphor-opengraph.png"
/>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Project",
"url": "https://phosphoricons.com",
"email": "hello@phosphoricons.com",
"location": "Brooklyn, NY",
"description": "A flexible icon family for interfaces, diagrams, presentations — whatever, really.",
"logo": "https://phosphoricons.com/favicon-512.png"
}
</script>
<!-- FACEBOOK META -->
<meta property="og:title" content="Phosphor Icons" />
@@ -29,7 +43,10 @@
/>
<meta property="og:type" content="website" />
<meta property="og:url" content="https://phosphoricons.com" />
<meta property="og:image" content="https://phosphoricons.com/phosphor-opengraph.png" />
<meta
property="og:image"
content="https://phosphoricons.com/phosphor-opengraph.png"
/>
<meta property="og:image:type" content="image/png" />
<meta property="og:image:alt" content="Phosphor Icons logo" />
<meta property="og:image:width" content="1200" />
@@ -42,7 +59,10 @@
name="twitter:description"
content="A flexible icon family for interfaces, diagrams, presentations — whatever, really."
/>
<meta name="twitter:image" content="https://phosphoricons.com/phosphor-opengraph.png" />
<meta
name="twitter:image"
content="https://phosphoricons.com/phosphor-opengraph.png"
/>
<meta name="twitter:site" content="@_phosphoricons" />
<meta name="twitter:creator" content="@friedtm" />

View File

@@ -15,10 +15,10 @@ h2 {
}
img {
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-webkit-user-drag: none;
user-select: none;
}
pre,
@@ -49,6 +49,7 @@ button {
justify-content: flex-start;
}
input.main-button,
button.main-button {
height: 64px;
padding: 0 48px 0 40px;
@@ -65,25 +66,36 @@ button.main-button {
transform: translate(0, 0);
transition: all 0.2s ease;
cursor: pointer;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
-webkit-user-drag: none;
user-select: none;
margin: 0 24px 24px 0;
}
input.main-button:active,
button.main-button:active {
transform: translate(4px, 4px);
box-shadow: 0 0 0 0 black;
}
input.main-button:focus,
button.main-button:focus {
outline: none;
}
input.main-button:disabled,
button.main-button:disabled {
border: 2px solid gray;
box-shadow: 4px 4px 0 0 gray;
cursor: not-allowed;
}
/* button.main-button:not(:last-child) {
margin: 0 24px 24px 0;
} */
input.main-button,
button.main-button svg {
margin-right: 12px;
}
@@ -113,3 +125,55 @@ a.main-link:after {
a.main-link:hover:after {
width: 0%;
}
button.text-button {
display: flex;
align-items: center;
padding: 8px;
background-color: transparent;
font-size: 16px;
cursor: pointer;
border-radius: 8px;
}
button.text-button svg {
margin: 8px;
}
.radio-group {
display: flex;
flex-flow: row wrap;
justify-content: space-around;
row-gap: 8px;
}
.radio-button input[type="radio"] {
display: none;
}
.radio-button label {
display: inline-block;
padding: 8px;
min-width: 50px;
background-color: white;
border-radius: 8px;
border: 2px solid black;
font-weight: bold;
cursor: pointer;
text-align: center;
user-select: none;
}
.radio-button label:hover {
background-color: #E0E0E0;
}
.radio-button input[type="radio"]:checked + label {
color: white;
background-color: black;
}
.radio-button label input {
margin-left: 8px;
}

View File

@@ -1,18 +1,24 @@
import React, { Suspense } from "react";
import Header from "components/Header";
import Modal from "components/Modal";
import Toolbar from "components/Toolbar";
import IconGrid from "components/IconGrid";
import Footer from "components/Footer";
import ErrorBoundary from "components/ErrorBoundary";
import Notice from "components/Notice";
import useIconParameters from "hooks/useIconParameters";
import "./App.css";
import Header from "../Header/Header";
import Toolbar from "../Toolbar/Toolbar";
import IconGrid from "../IconGrid/IconGrid";
import Footer from "../Footer/Footer";
import ErrorBoundary from "../ErrorBoundary/ErrorBoundary";
import Notice from "../Notice/Notice";
const errorFallback = <Notice message="Search error" />;
// const waitingFallback = <Notice type="wait" message="Loading..." />;
const paymentFallback = <Notice message="Could not connect to payments" />;
const waitingFallback = <Notice type="none" message="" />;
const App: React.FC<any> = () => {
useIconParameters();
return (
<React.StrictMode>
<Header />
@@ -24,6 +30,9 @@ const App: React.FC<any> = () => {
</Suspense>
</ErrorBoundary>
</main>
<Suspense fallback={paymentFallback}>
<Modal />
</Suspense>
<Footer />
</React.StrictMode>
);

View File

@@ -0,0 +1,2 @@
import App from "./App";
export default App;

View File

@@ -16,10 +16,11 @@
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
pointer-events: none;
text-transform: uppercase;
}
input.color-input {

View File

@@ -1,9 +1,10 @@
import React, { useCallback } from "react";
import { useRecoilState, useRecoilValue } from "recoil";
import { iconColorAtom } from "../../state/atoms";
import { isDarkThemeSelector } from "../../state/selectors";
import useThrottled from "../../hooks/useThrottled";
import { iconColorAtom } from "state/atoms";
import { isDarkThemeSelector } from "state/selectors";
import useThrottled from "hooks/useThrottled";
import "./ColorInput.css";
type ColorInputProps = {};

View File

@@ -0,0 +1,2 @@
import ColorInput from "./ColorInput";
export default ColorInput;

View File

@@ -0,0 +1,2 @@
import ErrorBoundary from "./ErrorBoundary";
export default ErrorBoundary;

View File

@@ -48,9 +48,9 @@ footer .links {
.illustrations-footer {
display: none;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
pointer-events: none;
}

View File

@@ -1,10 +1,12 @@
import React from "react";
import { Coffee, Heart } from "phosphor-react";
import uArrowUpLeft from "../../assets/u-arrow-up-left.svg";
import markerGreen from "../../assets/marker-green.svg";
import postIt from "../../assets/footer-mobile.svg";
import Links from "../Links/Links";
import uArrowUpLeft from "assets/u-arrow-up-left.svg";
import markerGreen from "assets/marker-green.svg";
import postIt from "assets/footer-mobile.svg";
import Links from "components/Links";
import "./Footer.css";
type FooterProps = {};
@@ -34,14 +36,14 @@ const Footer: React.FC<FooterProps> = () => {
a little quirky, too.
</p>
<p>
We're thankful for the tools we've benefited from and
this is our contribution towards a collaborative community.
We're thankful for the tools we've benefited from and this is our
contribution towards a collaborative community.
</p>
<p>
Phosphor is free and open-source, licensed under{" "}
<a
className="main-link"
href="https://raw.githubusercontent.com/phosphor-icons/phosphor-web/master/LICENSE"
href="https://raw.githubusercontent.com/phosphor-icons/phosphor-home/master/LICENSE"
>
MIT
</a>
@@ -82,7 +84,7 @@ const Footer: React.FC<FooterProps> = () => {
Helena Zhang
</a>{" "}
and built by{" "}
<a className="main-link" href="https://github.com/rektdeckard">
<a className="main-link" href="https://tobiasfried.com">
Toby Fried
</a>{" "}
<span

View File

@@ -0,0 +1,2 @@
import Footer from "./Footer";
export default Footer;

View File

@@ -60,7 +60,7 @@ header {
top: -158px;
}
#billiard-ball {
.billiard-ball {
position: absolute;
left: 132px;
top: -98px;
@@ -72,13 +72,13 @@ header {
top: 152px;
}
#warning {
.warning {
position: absolute;
left: 394px;
top: -304px;
}
#tablet {
.tablet {
position: absolute;
left: 672px;
top: -900px;
@@ -94,18 +94,18 @@ header {
height: 612px;
}
#cutting-mat {
.cutting-mat {
position: absolute;
left: 96px;
}
#receipt {
.receipt {
position: absolute;
left: -36px;
top: 190px;
}
#calculator {
.calculator {
position: absolute;
left: 632px;
top: 170px;
@@ -131,7 +131,7 @@ header {
top: -158px;
}
#billiard-ball {
.billiard-ball {
position: absolute;
left: 900px;
top: 400px;
@@ -148,30 +148,30 @@ header {
top: 694px;
}
#warning {
.warning {
position: absolute;
left: 1170px;
top: 400px;
}
#tablet {
.tablet {
position: absolute;
left: 578px;
top: -900px;
}
#cutting-mat {
.cutting-mat {
position: absolute;
left: 120px;
}
#receipt {
.receipt {
position: absolute;
left: -16px;
top: 190px;
}
#calculator {
.calculator {
position: absolute;
left: 924px;
top: 114px;

View File

@@ -1,29 +1,31 @@
import React from "react";
import { ArrowCircleUpRight, ArrowCircleDown } from "phosphor-react";
import markerPurple from "../../assets/marker-purple.svg";
import paperclips from "../../assets/paperclips-header-mobile.svg";
import paperclipsThree from "../../assets/paperclips-header.svg";
import tablet from "../../assets/tablet.svg";
import tabletSpec from "../../assets/tablet-spec.svg";
import billiardBall from "../../assets/billiard-ball.svg";
import billiardBallSpec from "../../assets/billiard-ball-spec.svg";
import warning from "../../assets/warning.svg";
import warningSpec from "../../assets/warning-spec.svg";
import cuttingMat from "../../assets/cutting-mat.svg";
import cuttingMatSpec from "../../assets/cutting-mat-spec.svg";
import receipt from "../../assets/receipt.svg";
import receiptSpec from "../../assets/receipt-spec.svg";
import calculator from "../../assets/calculator.svg";
import calculatorSpec from "../../assets/calculator-spec.svg";
import Links from "../Links/Links";
import markerPurple from "assets/marker-purple.svg";
import paperclips from "assets/paperclips-header-mobile.svg";
import paperclipsThree from "assets/paperclips-header.svg";
import tablet from "assets/tablet.svg";
import tabletSpec from "assets/tablet-spec.svg";
import billiardBall from "assets/billiard-ball.svg";
import billiardBallSpec from "assets/billiard-ball-spec.svg";
import warning from "assets/warning.svg";
import warningSpec from "assets/warning-spec.svg";
import cuttingMat from "assets/cutting-mat.svg";
import cuttingMatSpec from "assets/cutting-mat-spec.svg";
import receipt from "assets/receipt.svg";
import receiptSpec from "assets/receipt-spec.svg";
import calculator from "assets/calculator.svg";
import calculatorSpec from "assets/calculator-spec.svg";
import Links from "components/Links";
import "./Header.css";
type HeaderProps = {};
const handleGetStarted = () =>
window.open(
"https://github.com/phosphor-icons/phosphor-web#phosphor-icons",
"https://github.com/phosphor-icons/phosphor-home#phosphor-icons",
"_blank",
"noopener noreferrer"
);
@@ -41,22 +43,22 @@ const Header: React.FC<HeaderProps> = () => {
<img src={markerPurple} id="marker-purple" alt="" />
<img src={paperclips} id="paperclips" alt="" />
<img src={paperclipsThree} id="paperclips-three" alt="" />
<img id="tablet" src={tabletSpec} alt="" />
<img id="tablet" className="inspectable xray" src={tablet} alt="" />
<img id="billiard-ball" src={billiardBallSpec} alt="" />
<img className="tablet" src={tabletSpec} alt="" />
<img className="tablet inspectable xray" src={tablet} alt="" />
<img className="billiard-ball" src={billiardBallSpec} alt="" />
<img
id="billiard-ball"
className="inspectable xray"
className="billiard-ball inspectable xray"
src={billiardBall}
alt=""
/>
<img id="warning" src={warningSpec} alt="" />
<img id="warning" className="inspectable xray" src={warning} alt="" />
<img className="warning" src={warningSpec} alt="" />
<img className="warning inspectable xray" src={warning} alt="" />
</div>
<div className="intro">
<h2>
Phosphor is a flexible icon family for interfaces, diagrams, presentations  
Phosphor is a flexible icon family for interfaces, diagrams,
presentations  
<wbr />
whatever, really.
</h2>
@@ -73,19 +75,17 @@ const Header: React.FC<HeaderProps> = () => {
<Links />
</div>
<div className="illustrations-bottom">
<img id="cutting-mat" src={cuttingMatSpec} alt="" />
<img className="cutting-mat" src={cuttingMatSpec} alt="" />
<img
id="cutting-mat"
className="inspectable xray"
className="cutting-mat inspectable xray"
src={cuttingMat}
alt=""
/>
<img id="receipt" src={receiptSpec} alt="" />
<img id="receipt" className="inspectable xray" src={receipt} alt="" />
<img id="calculator" src={calculatorSpec} alt="" />
<img className="receipt" src={receiptSpec} alt="" />
<img className="receipt inspectable xray" src={receipt} alt="" />
<img className="calculator" src={calculatorSpec} alt="" />
<img
id="calculator"
className="inspectable xray"
className="calculator inspectable xray"
src={calculator}
alt=""
/>

View File

@@ -0,0 +1,2 @@
import Header from "./Header";
export default Header;

View File

@@ -3,39 +3,40 @@ import { useRecoilValue, useSetRecoilState } from "recoil";
import { motion } from "framer-motion";
import { Svg2Png } from "svg2png-converter";
import { saveAs } from "file-saver";
import { Copy, X, CheckCircle, Download } from "phosphor-react";
import ReactGA from "react-ga";
import { Copy, X, CheckCircle, Download } from "phosphor-react";
import {
iconWeightAtom,
iconSizeAtom,
iconColorAtom,
iconPreviewOpenAtom,
} from "../../state/atoms";
import useTransientState from "../../hooks/useTransientState";
} from "state/atoms";
import { IconEntry } from "lib";
import useTransientState from "hooks/useTransientState";
import TagCloud from "./TagCloud";
import { IconEntry } from "../../lib";
const panelVariants = {
open: {
opacity: 1,
height: "100%",
marginTop: 4,
marginBottom: 4,
// transition: { stiffness: 600, damping: 32, duration: 0.2 },
marginTop: "4px",
marginBottom: "4px",
transition: { type: "tween", duration: 0.1 },
},
collapsed: {
opacity: 0,
height: 0,
marginTop: 0,
marginBottom: 0,
// transition: { stiffness: 600, damping: 32, duration: 0.2 },
height: "0px",
marginTop: "0px",
marginBottom: "0px",
transition: { type: "tween", duration: 0.1 },
},
};
const contentVariants = {
open: { opacity: 1, transition: { duration: 0.2 } },
collapsed: { opacity: 0, transition: { duration: 0.1 } },
open: { opacity: 1, transition: { duration: 0.2, delay: 0.1 } },
collapsed: { opacity: 0, transition: { duration: 0 } },
};
const buttonColor = "#35313D";
@@ -82,7 +83,10 @@ const DetailsPanel: React.FC<InfoPanelProps> = (props) => {
react: `<${Icon.displayName} size={${size}} ${
color !== "#000000" ? `color="${color}" ` : ""
}${weight === "regular" ? "" : `weight="${weight}" `}/>`,
vue: `<Ph${Icon.displayName} :size="${size}" ${
vue: `<ph${Icon.displayName!!.replace(
/([a-z0-9]|(?=[A-Z]))([A-Z])/g,
"$1-$2"
).toLowerCase()} :size="${size}" ${
color !== "#000000" ? `color="${color}" ` : ""
}${weight === "regular" ? "" : `weight="${weight}" `}/>`,
};
@@ -122,7 +126,7 @@ const DetailsPanel: React.FC<InfoPanelProps> = (props) => {
Svg2Png.save(
ref.current,
`${name}${weight === "regular" ? "" : `-${weight}`}.png`,
{ scaleX: 1.334, scaleY: 1.334 }
{ scaleX: 2.667, scaleY: 2.667 }
);
};
@@ -230,7 +234,7 @@ const DetailsPanel: React.FC<InfoPanelProps> = (props) => {
) : (
<Copy size={32} color="currentColor" weight="fill" />
)}
{copied === "svg" ? "Copied!" : "Copy to design software"}
{copied === "svg" ? "Copied!" : "Copy SVG"}
</button>
</div>
</motion.div>
@@ -239,6 +243,7 @@ const DetailsPanel: React.FC<InfoPanelProps> = (props) => {
animate="open"
exit="collapsed"
variants={contentVariants}
title="Close"
>
<X
className="close-icon"

View File

@@ -1,6 +1,7 @@
.grid-container {
padding: 32px 16px;
min-height: 80vh;
content-visibility: auto;
}
.grid {
@@ -21,9 +22,9 @@
justify-content: center;
margin: 4px;
border-radius: 16px;
user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
cursor: pointer;
/* transition: background-color 100ms ease; */
}
@@ -45,6 +46,24 @@
text-align: center;
}
@media screen and (max-width: 536px) {
.grid-container {
padding: 32px 8px;
}
.grid-item {
width: 108px;
height: unset;
padding: 4px 0;
justify-content: flex-start;
border: 2px solid transparent;
}
.grid-item p {
padding: 0 4px;
}
}
.info-box {
position: relative;
display: flex;
@@ -63,6 +82,10 @@
.icon-usage {
padding-left: 10% !important;
}
.snippet pre {
padding: 12px 8px 12px 20px;
}
}
.icon-preview {
@@ -94,9 +117,9 @@
align-items: center;
text-overflow: ellipsis;
color: black;
user-select: all;
-moz-user-select: all;
-webkit-user-select: all;
user-select: all;
}
.snippet pre:focus {
@@ -105,9 +128,9 @@
@keyframes select {
to {
user-select: text;
-moz-user-select: text;
-webkit-user-select: text;
user-select: text;
}
}

View File

@@ -3,18 +3,27 @@ import { useRecoilValue } from "recoil";
import { motion, useAnimation } from "framer-motion";
import { IconContext } from "phosphor-react";
import { iconWeightAtom, iconSizeAtom, iconColorAtom } from "../../state/atoms";
import { iconWeightAtom, iconSizeAtom, iconColorAtom } from "state/atoms";
import {
filteredQueryResultsSelector,
isDarkThemeSelector,
} from "../../state/selectors";
import useGridSpans from "../../hooks/useGridSpans";
} from "state/selectors";
import useGridSpans from "hooks/useGridSpans";
import IconGridItem from "./IconGridItem";
import TagCloud from "./TagCloud";
import Notice from "../Notice/Notice";
import Notice from "components/Notice";
import "./IconGrid.css";
const defaultSearchTags = ["communication", "editor", "emoji", "maps", "weather"];
const defaultSearchTags = [
"*new*",
"communication",
"editor",
"emoji",
"maps",
"weather",
];
type IconGridProps = {};

View File

@@ -7,9 +7,9 @@ import React, {
import { useRecoilState } from "recoil";
import { motion, AnimatePresence } from "framer-motion";
import { iconPreviewOpenAtom } from "../../state/atoms";
import { IconEntry } from "lib";
import { iconPreviewOpenAtom } from "state/atoms";
import DetailsPanel from "./DetailsPanel";
import { IconEntry } from "../../lib";
interface IconGridItemProps {
index: number;
@@ -86,9 +86,9 @@ const IconGridItem: React.FC<IconGridItemProps> = (props) => {
<Icon />
<p>{name}</p>
</motion.div>
<AnimatePresence initial={false}>
{isOpen && <DetailsPanel {...props} />}
</AnimatePresence>
<AnimatePresence initial={false}>
{isOpen && <DetailsPanel {...props} />}
</AnimatePresence>
</>
);
};

View File

@@ -1,7 +1,8 @@
import React, { useCallback } from "react";
import { useSetRecoilState } from "recoil";
import { searchQueryAtom } from "../../state/atoms";
import { searchQueryAtom } from "state/atoms";
import "./TagCloud.css";
interface TagCloudProps {

View File

@@ -0,0 +1,2 @@
import IconGrid from "./IconGrid";
export default IconGrid;

View File

@@ -20,13 +20,14 @@
margin-right: 12px;
}
a.nav-link {
.nav-link {
text-decoration: none;
position: relative;
color: black;
cursor: pointer;
}
a.nav-link:after {
.nav-link:after {
content: "";
position: absolute;
bottom: -2px;
@@ -36,6 +37,6 @@ a.nav-link:after {
transition: 0.2s;
}
a.nav-link:hover:after {
.nav-link:hover:after {
width: 100%;
}
}

View File

@@ -1,14 +1,22 @@
import React from "react";
import { OutboundLink } from "react-ga";
import { useSetRecoilState } from "recoil";
import { ArrowElbowDownRight } from "phosphor-react";
import { iconCount } from "../../lib/icons";
import { iconCount } from "lib/icons";
import { modalSelector } from "state/selectors";
import DonationModal from "components/Modal/DonationModal";
import "./Links.css";
interface LinksProps {}
const Links: React.FC<LinksProps> = () => {
const openModal = useSetRecoilState(modalSelector);
const openDonationModal = () => openModal({ type: DonationModal });
const delayedOpenDonationModal = () => setTimeout(openDonationModal, 2000);
return (
<div className="links">
<div>
@@ -19,56 +27,45 @@ const Links: React.FC<LinksProps> = () => {
eventLabel="Download all"
download
type="application/zip"
onClick={delayedOpenDonationModal}
>
Download all ({iconCount})
</OutboundLink>
</div>
<div>
<ArrowElbowDownRight size={24} />
<OutboundLink
className="nav-link"
to="https://www.figma.com/file/xMCDSp5g0g7Fw8aMyAdVVr/Phosphor-Icon-Library-0.6.0"
eventLabel="Figma library"
>
Figma library
</OutboundLink>
<span>
<OutboundLink
className="nav-link"
to="https://www.figma.com/community/file/903830135544202908/Phosphor-Icons"
eventLabel="Figma library"
>
Figma library
</OutboundLink>
{" / "}
<OutboundLink
className="nav-link"
to="https://www.figma.com/community/plugin/898620911119764089/Phosphor-Icons"
eventLabel="Figma plugin"
>
plugin
</OutboundLink>
</span>
</div>
{/* <div>
<ArrowElbowDownRight size={24} />
<OutboundLink
className="nav-link"
to="https://www.figma.com/community/plugin/892854133443228626/Phosphor-Icons"
eventLabel="Figma plugin"
>
Add Figma plugin
</OutboundLink>
</div> */}
<div>
<ArrowElbowDownRight size={24} />
<a
className="nav-link"
href="https://github.com/phosphor-icons/phosphor-web/issues"
href="https://github.com/phosphor-icons/phosphor-home/issues"
>
Request an icon
</a>
</div>
{/* <div>
<ArrowElbowDownRight size={24} />
<span>
<a className="nav-link" href="https://paypal.me/minoraxis">
Donate on PayPal
</a>
{" / "}
<a className="nav-link" href="https://patreon.com/phosphoricons">
Patreon
</a>
</span>
</div> */}
<div>
<ArrowElbowDownRight size={24} />
<a className="nav-link" href="https://paypal.me/minoraxis">
Donate on PayPal
</a>
<span className="nav-link" onClick={openDonationModal}>
Donate
</span>
</div>
<div>
<ArrowElbowDownRight size={24} />
@@ -80,9 +77,9 @@ const Links: React.FC<LinksProps> = () => {
<ArrowElbowDownRight size={24} />
<a
className="nav-link"
href="https://github.com/phosphor-icons/phosphor-web"
href="https://github.com/phosphor-icons/phosphor-home"
>
Github
GitHub
</a>
</div>
</div>

View File

@@ -0,0 +1,2 @@
import Links from "./Links";
export default Links;

View File

@@ -0,0 +1,91 @@
import React, { useState } from "react";
import { ModalInstance } from "../Modal";
import DonationStepMethod from "./DonationStepMethod";
import DonationStepDropin from "./DonationStepDropin";
import DonationStepThanks from "./DonationStepThanks";
const routes = [DonationStepMethod, DonationStepDropin, DonationStepThanks];
export enum DonationType {
FIVE_DOLLARS = 5,
TEN_DOLLARS = 10,
TWENTY_DOLLARS = 20,
FIFTY_DOLLARS = 50,
ONE_HUNDRED_DOLLARS = 100,
CUSTOM = -1,
}
interface RouteProps {
donationType: DonationType | undefined;
setDonationType: React.Dispatch<
React.SetStateAction<DonationType | undefined>
>;
donationAmount: number;
setDonationAmount: React.Dispatch<React.SetStateAction<number>>;
}
export interface StepProps {
previousStep: () => void;
nextStep: () => void;
close: () => void;
routeProps: RouteProps;
}
interface StepperProps {
routes: Array<React.FC<StepProps>>;
routeProps: RouteProps;
close: () => void;
}
const Stepper: React.FC<StepperProps> = ({ routes, routeProps, close }) => {
const [currentStep, setCurrentStep] = useState<number>(0);
const previousStep = () => {
if (currentStep <= 0) return;
setTimeout(() => setCurrentStep((c) => c - 1), 500);
};
const nextStep = () => {
if (currentStep >= routes.length - 1) return;
setTimeout(() => setCurrentStep((c) => c + 1), 500);
};
const Component = routes[currentStep];
return (
<>
<Component
previousStep={previousStep}
nextStep={nextStep}
close={close}
routeProps={routeProps}
/>
</>
);
};
const DonationModal = ({ close }: ModalInstance): JSX.Element => {
const [donationType, setDonationType] = useState<DonationType | undefined>();
const [donationAmount, setDonationAmount] = useState<number>(0);
return (
<>
<div className="modal-titlebar">
<h2>Donate</h2>
</div>
<Stepper
routes={routes}
routeProps={{
donationType,
setDonationType,
donationAmount,
setDonationAmount,
}}
close={close}
/>
</>
);
};
export default DonationModal;

View File

@@ -0,0 +1,128 @@
import React, { useRef, useState, useEffect } from "react";
import dropin, { Dropin } from "braintree-web-drop-in";
import axios from "axios";
import { CurrencyCircleDollar } from "phosphor-react";
import { StepProps } from "./DonationModal";
const PaymentServer = axios.create({
baseURL: "https://us-central1-phosphor-14c61.cloudfunctions.net/paymentsApi",
});
const BT_PAYMENT_FIELDS = {
number: {
placeholder: "4111 1111 1111 1111",
},
cvv: {
placeholder: "123",
},
expirationDate: {
placeholder: "10/22",
},
cardholderName: {
placeholder: "Person McFace",
},
};
const PaymentModal: React.FC<StepProps> = ({
nextStep,
previousStep,
routeProps,
}) => {
const instance = useRef<Dropin>();
const [isValid, setIsValid] = useState<boolean>(false);
const [isLoading, setLoading] = useState<boolean>(false);
const { donationAmount } = routeProps;
const submit = async () => {
if (!instance.current) return;
setLoading(true);
try {
const payload = await instance.current.requestPaymentMethod();
console.log({ ...payload, donationAmount });
const response = await PaymentServer.post("/", {
...payload,
donationAmount,
});
console.log({ response });
if (!!response.data?.success) {
nextStep();
} else {
setIsValid(false);
}
} catch (_e) {
} finally {
setLoading(false);
}
};
useEffect(() => {
const initializePayments = async () => {
try {
instance.current = await dropin.create({
authorization: "sandbox_246jdjxq_8h7hm5rvngkykjds",
container: "#braintree-dropin",
card: {
cardholderName: {
required: true,
},
overrides: {
fields: BT_PAYMENT_FIELDS,
},
},
paypal: {
flow: "checkout",
amount: donationAmount.toFixed(2).toString(),
currency: "USD",
commit: false,
},
paypalCredit: {
flow: "checkout",
amount: donationAmount.toFixed(2).toString(),
currency: "USD",
commit: false,
},
venmo: { allowNewBrowserTab: false },
});
instance.current.on("paymentMethodRequestable", () => setIsValid(true));
instance.current.on("noPaymentMethodRequestable", () =>
setIsValid(false)
);
} catch (err) {
console.error(err);
}
};
initializePayments();
}, [donationAmount]);
return (
<>
<div id="braintree-dropin"></div>
<div className="donation-details">
<CurrencyCircleDollar size={64} weight="duotone" />
<span>
Preparing your ${routeProps.donationAmount.toFixed(2)} donation...
</span>
</div>
<div className="step-button-container">
<button className="main-button" onClick={previousStep}>
Back
</button>
<button
className="main-button"
onClick={submit}
disabled={isLoading || !isValid}
>
{isLoading ? "Processing..." : "Donate"}
</button>
</div>
</>
);
};
export default PaymentModal;

View File

@@ -0,0 +1,123 @@
import React from "react";
import { StepProps, DonationType } from "./DonationModal";
const DonationStepMethod: React.FC<StepProps> = ({
previousStep,
nextStep,
close,
routeProps,
}) => {
const { donationType, donationAmount, setDonationType, setDonationAmount } =
routeProps;
const onDonationChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setDonationType(+e.target.value as DonationType);
if (!(+e.target.value === DonationType.CUSTOM))
setDonationAmount(+e.target.value);
};
void previousStep;
return (
<>
<h3>
Thanks for using Phosphor! Would you like to make a donation to help
support our work?
</h3>
<div className="radio-group">
<div className="radio-button">
<input
type="radio"
id="donate-5"
name="donation-type"
value={DonationType.FIVE_DOLLARS}
checked={donationType === DonationType.FIVE_DOLLARS}
onChange={onDonationChange}
/>
<label htmlFor="donate-5">$5</label>
</div>
<div className="radio-button">
<input
type="radio"
id="donate-10"
name="donation-type"
value={DonationType.TEN_DOLLARS}
checked={donationType === DonationType.TEN_DOLLARS}
onChange={onDonationChange}
/>
<label htmlFor="donate-10">$10</label>
</div>
<div className="radio-button">
<input
type="radio"
id="donate-20"
name="donation-type"
value={DonationType.TWENTY_DOLLARS}
checked={donationType === DonationType.TWENTY_DOLLARS}
onChange={onDonationChange}
/>
<label htmlFor="donate-20">$20</label>
</div>
<div className="radio-button">
<input
type="radio"
id="donate-50"
name="donation-type"
value={DonationType.FIFTY_DOLLARS}
checked={donationType === DonationType.FIFTY_DOLLARS}
onChange={onDonationChange}
/>
<label htmlFor="donate-50">$50</label>
</div>
<div className="radio-button">
<input
type="radio"
id="donate-100"
name="donation-type"
value={DonationType.ONE_HUNDRED_DOLLARS}
checked={donationType === DonationType.ONE_HUNDRED_DOLLARS}
onChange={onDonationChange}
/>
<label htmlFor="donate-100">$100</label>
</div>
<div className="radio-button">
<input
type="radio"
id="donate-custom"
name="donation-type"
value={DonationType.CUSTOM}
checked={donationType === DonationType.CUSTOM}
onChange={onDonationChange}
/>
<label htmlFor="donate-custom">
Other: $
<input
type="number"
min={2}
max={1000000}
id="donate-custom"
value={donationAmount}
disabled={donationType !== DonationType.CUSTOM}
onChange={(e) => setDonationAmount(+e.target.value)}
/>
</label>
</div>
</div>
<div className="step-button-container">
<button className="main-button" onClick={close}>
No thanks
</button>
<button
className="main-button"
onClick={nextStep}
disabled={!(donationType && donationAmount)}
>
Next
</button>
</div>
</>
);
};
export default DonationStepMethod;

View File

@@ -0,0 +1,7 @@
import React from "react";
const DonationStepThanks: React.FC<{}> = () => {
return null;
};
export default DonationStepThanks;

View File

@@ -0,0 +1,2 @@
import DonationModal from "./DonationModal";
export default DonationModal;

View File

@@ -0,0 +1,85 @@
.modal-container {
position: fixed;
display: grid;
place-items: center;
inset: 0;
background-color: rgba(0, 0, 0, 0.4);
z-index: 10;
}
.modal-content {
position: relative;
display: flex;
flex-direction: column;
width: 400px;
min-height: 600px;
background-color: white;
border-radius: 8px;
border: 2px solid black;
padding: 24px;
}
@media screen and (max-width: 480px) {
.modal-content {
position: fixed;
inset: 0;
width: unset;
min-height: unset;
border: none;
border-radius: 0;
}
}
.step-button-container {
flex: 1;
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: center;
}
.donation-details {
display: grid;
place-items: center;
padding: 32px;
}
button.modal-close-button {
position: absolute;
top: 24px;
right: 24px;
background: transparent;
padding: 0;
cursor: pointer;
box-sizing: content-box;
z-index: 1;
}
.modal-titlebar {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.modal-titlebar > * {
margin: 0;
}
.payment-methods {
display: grid;
gap: 16px;
grid-template-rows: repeat(2, 1fr);
grid-template-columns: repeat(2, 1fr);
}
.payment-methods button {
margin: 0;
padding: 0;
justify-content: center;
height: 96px;
}
.payment-methods button > svg {
margin: 0;
}

View File

@@ -0,0 +1,38 @@
import React from "react";
import { useRecoilState, useRecoilValue } from "recoil";
import { useLockBodyScroll } from "react-use";
import { useHotkeys } from "react-hotkeys-hook";
import { X } from "phosphor-react";
import { modalAtom, modalOpenAtom } from "state/atoms";
import "./Modal.css";
export interface ModalInstance {
close: () => void;
children?: JSX.Element;
}
const Modal = (): JSX.Element | null => {
const Instance = useRecoilValue(modalAtom);
const [isModalOpen, setModalOpen] = useRecoilState(modalOpenAtom);
useHotkeys("esc", () => isModalOpen && setModalOpen(false), [isModalOpen]);
useLockBodyScroll(isModalOpen);
const close = () => setModalOpen(false);
if (!Instance || !isModalOpen) return null;
return (
<div className="modal-container">
<div className="modal-content">
<button className="modal-close-button" onClick={close}>
<X size={32} />
</button>
<Instance close={close} />
</div>
</div>
);
};
export default Modal;

View File

@@ -0,0 +1,3 @@
import Modal from "./Modal";
export default Modal;

View File

@@ -1,17 +1,21 @@
import React from "react";
import { motion } from "framer-motion";
import { useRecoilValue } from "recoil";
import { isDarkThemeSelector } from "../../state/selectors";
import { searchQueryAtom } from "../../state/atoms";
import { HourglassMedium, Question, SmileyXEyes } from "phosphor-react";
import { isDarkThemeSelector } from "state/selectors";
import { searchQueryAtom } from "state/atoms";
interface NoticeProps {
message?: string;
type?: "wait" | "help" | "warn" | "none";
}
const Notice: React.FC<NoticeProps> = ({ message, type = "warn", children }) => {
const Notice: React.FC<NoticeProps> = ({
message,
type = "warn",
children,
}) => {
const isDark = useRecoilValue(isDarkThemeSelector);
const query = useRecoilValue(searchQueryAtom);

View File

@@ -0,0 +1,2 @@
import Notice from "./Notice";
export default Notice;

View File

@@ -15,11 +15,15 @@
background-color: white !important;
}
.search-bar:focus-within .keys {
display: none;
}
.search-bar input {
height: 100%;
flex: 1;
border: none;
margin-left: 12px;
margin: 0 12px;
padding: 0;
font-size: 16px;
color: white;
@@ -48,6 +52,17 @@
cursor: wait;
}
.keys {
display: inline-flex;
align-items: center;
justify-content: flex-end;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
min-width: 42px;
font-size: 12px;
}
@media screen and (max-width: 558px) {
#search-icon {
display: none;
@@ -58,3 +73,9 @@
width: 60%;
}
}
@media screen and (min-width: 858px) and (max-width: 1100px) {
.search-bar {
flex-basis: 320px;
}
}

View File

@@ -1,17 +1,35 @@
import React, { useState, useEffect } from "react";
import React, { useState, useEffect, useRef, MutableRefObject } from "react";
import { useRecoilState } from "recoil";
import { useDebounce } from "react-use";
import { MagnifyingGlass, X, HourglassHigh } from "phosphor-react";
import { useHotkeys } from "react-hotkeys-hook";
import { Command, MagnifyingGlass, X, HourglassHigh } from "phosphor-react";
import ReactGA from "react-ga";
import { searchQueryAtom } from "../../state/atoms";
import { searchQueryAtom } from "state/atoms";
import "./SearchInput.css";
const apple = /iPhone|iPod|iPad|Macintosh|MacIntel|MacPPC/i;
const isApple = apple.test(window.navigator.platform);
const mobile = /Android|iPhone|iPod|iPad|Opera Mini|IEMobile/i;
const isMobile = mobile.test(window.navigator.userAgent);
type SearchInputProps = {};
const SearchInput: React.FC<SearchInputProps> = () => {
const [value, setValue] = useState<string>("");
const [query, setQuery] = useRecoilState(searchQueryAtom);
const inputRef =
useRef<HTMLInputElement>() as MutableRefObject<HTMLInputElement>;
useHotkeys("ctrl+k,cmd+k", (e) => {
e.preventDefault();
if (!e.repeat) {
inputRef.current?.focus();
inputRef.current.select();
}
});
/* eslint-disable react-hooks/exhaustive-deps */
useEffect(() => {
@@ -28,13 +46,15 @@ const SearchInput: React.FC<SearchInputProps> = () => {
() => {
if (value !== query) {
setQuery(value);
!!value && ReactGA.event({ category: "Search", action: "Query", label: value });
!!value &&
ReactGA.event({ category: "Search", action: "Query", label: value });
}
!!value && void document
.getElementById("beacon")
?.scrollIntoView({ block: "start", behavior: "smooth" });
!!value &&
void document
.getElementById("beacon")
?.scrollIntoView({ block: "start", behavior: "smooth" });
},
250,
500,
[value]
);
@@ -49,6 +69,7 @@ const SearchInput: React.FC<SearchInputProps> = () => {
<div className="search-bar">
<MagnifyingGlass id="search-icon" size={24} />
<input
ref={inputRef}
id="search-input"
title="Search for icon names, categories, or keywords"
aria-label="Search for an icon"
@@ -62,6 +83,7 @@ const SearchInput: React.FC<SearchInputProps> = () => {
key === "Enter" && currentTarget.blur()
}
/>
{!value && !isMobile && <Keys>{isApple ? <Command /> : "Ctrl + "}K</Keys>}
{value ? (
isReady() ? (
<X className="clear-icon" size={18} onClick={handleCancelSearch} />
@@ -73,4 +95,8 @@ const SearchInput: React.FC<SearchInputProps> = () => {
);
};
const Keys: React.FC<{}> = ({ children }) => (
<div className="keys">{children}</div>
);
export default SearchInput;

View File

@@ -0,0 +1,2 @@
import SearchInput from "./SearchInput";
export default SearchInput;

View File

@@ -1,7 +1,8 @@
import React, { useCallback } from "react";
import { useRecoilState } from "recoil";
import { iconSizeAtom } from "../../state/atoms";
import { iconSizeAtom } from "state/atoms";
import "./SizeInput.css";
type SizeInputProps = {};

View File

@@ -0,0 +1,2 @@
import SizeInput from "./SizeInput";
export default SizeInput;

View File

@@ -1,10 +1,11 @@
import React from "react";
import { useSetRecoilState } from "recoil";
import React, { useMemo } from "react";
import { useRecoilState } from "recoil";
import Select from "react-dropdown-select";
import { PencilLine } from "phosphor-react";
import { iconWeightAtom } from "../../state/atoms";
import { IconStyle } from "../../lib";
import { iconWeightAtom } from "state/atoms";
import { IconStyle } from "lib";
import "./StyleInput.css";
type WeightOption = { key: string; value: IconStyle; icon: JSX.Element };
@@ -45,7 +46,12 @@ const options: WeightOption[] = [
type StyleInputProps = {};
const StyleInput: React.FC<StyleInputProps> = () => {
const setStyle = useSetRecoilState(iconWeightAtom);
const [style, setStyle] = useRecoilState(iconWeightAtom);
const currentStyle = useMemo(
() => [options.find((option) => option.value === style)!!],
[style]
);
const handleStyleChange = (values: WeightOption[]) =>
setStyle(values[0].value as IconStyle);
@@ -53,7 +59,7 @@ const StyleInput: React.FC<StyleInputProps> = () => {
return (
<Select
options={options}
values={[options[2]]}
values={currentStyle}
searchable={false}
labelField="key"
onChange={handleStyleChange}

View File

@@ -0,0 +1,2 @@
import StyleInput from "./StyleInput";
export default StyleInput;

View File

@@ -1,4 +1,5 @@
menu.toolbar {
nav.toolbar {
position: -webkit-sticky;
position: sticky;
top: -1px;
padding: 0;

View File

@@ -1,23 +1,24 @@
import React from "react";
import StyleInput from "components/StyleInput";
import SearchInput from "components/SearchInput";
import SizeInput from "components/SizeInput";
import ColorInput from "components/ColorInput";
import "./Toolbar.css";
import StyleInput from "../StyleInput/StyleInput";
import SearchInput from "../SearchInput/SearchInput";
import SizeInput from "../SizeInput/SizeInput";
import ColorInput from "../ColorInput/ColorInput";
type ToolbarProps = {};
const Toolbar: React.FC<ToolbarProps> = () => {
return (
<menu className="toolbar" id="toolbar">
<nav className="toolbar" id="toolbar">
<div className="toolbar-contents">
<StyleInput />
<SearchInput />
<SizeInput />
<ColorInput />
</div>
</menu>
</nav>
);
};

View File

@@ -0,0 +1,2 @@
import Toolbar from "./Toolbar";
export default Toolbar;

8
src/hooks/index.ts Normal file
View File

@@ -0,0 +1,8 @@
export { default as useDebounce } from "./useDebounce";
export { default as useGridSpans } from "./useGridSpans";
export { default as useIconParameters } from "./useIconParameters";
export { default as useThrottle } from "./useThrottle";
export { default as useThrottled } from "./useThrottled";
export { default as useTimeoutFn } from "./useTimeoutFn";
export { default as useTransientState } from "./useTransientState";
export { default as useUnmount } from "./useUnmount";

16
src/hooks/useDebounce.ts Normal file
View File

@@ -0,0 +1,16 @@
import { DependencyList, useEffect } from "react";
import useTimeoutFn from "./useTimeoutFn";
export type UseDebounceReturn = [() => boolean | null, () => void];
export default function useDebounce(
fn: Function,
ms: number = 0,
deps: DependencyList = []
): UseDebounceReturn {
const [isReady, cancel, reset] = useTimeoutFn(fn, ms);
useEffect(reset, deps);
return [isReady, cancel];
}

View File

@@ -1,13 +1,18 @@
import { useWindowSize } from "react-use";
const MOBILE_BREAKPOINT = 536;
const GRID_PADDING = 32; // .grid-container { padding }
const TOOLBAR_WIDTH = 17; // IS THIS BROWSER-SPECIFIC?
const MAX_GRID_WIDTH = 1120; // .grid { max-width }
const ITEM_WIDTH = 168; // .grid-item { width; height; margin }
const ITEM_WIDTH_MOBILE = 108; // .grid-item { width; height; margin }
export default (): number => {
const { width } = useWindowSize();
const itemWidth = width <= MOBILE_BREAKPOINT ? ITEM_WIDTH_MOBILE : ITEM_WIDTH;
return Math.floor(
Math.min(width - GRID_PADDING - TOOLBAR_WIDTH, MAX_GRID_WIDTH) / ITEM_WIDTH
Math.min(width - GRID_PADDING - TOOLBAR_WIDTH, MAX_GRID_WIDTH) / itemWidth
);
};

View File

@@ -0,0 +1,37 @@
import { useEffect } from "react";
import { useSearchParam } from "react-use";
import { useSetRecoilState } from "recoil";
import TinyColor from "tinycolor2";
import { iconColorAtom, iconWeightAtom, iconSizeAtom } from "../state/atoms";
import { IconStyle } from "../lib";
export default () => {
const weight = useSearchParam("weight")?.replace(/["']/g, "");
const size = useSearchParam("size")?.replace(/["']/g, "");
const color = useSearchParam("color")?.replace(/["']/g, "");
const setColor = useSetRecoilState(iconColorAtom);
const setWeight = useSetRecoilState(iconWeightAtom);
const setSize = useSetRecoilState(iconSizeAtom);
useEffect(() => {
if (weight) {
if (weight.toUpperCase() in IconStyle) setWeight(weight as IconStyle);
}
}, [weight, setWeight]);
useEffect(() => {
if (size) {
const normalizedSize = parseInt(size);
if (typeof normalizedSize === "number" && isFinite(normalizedSize))
setSize(Math.min(Math.max(normalizedSize, 16), 96));
}
}, [size, setSize]);
useEffect(() => {
if (color) {
const normalizedColor = TinyColor(color);
if (normalizedColor.isValid()) setColor(normalizedColor.toHexString());
}
}, [color, setColor]);
};

37
src/hooks/useThrottle.ts Normal file
View File

@@ -0,0 +1,37 @@
import { useEffect, useRef, useState } from "react";
import useUnmount from "./useUnmount";
const useThrottle = <T>(value: T, ms: number = 200) => {
const [state, setState] = useState<T>(value);
const timeout = useRef<ReturnType<typeof setTimeout>>();
const nextValue = useRef(null) as any;
const hasNextValue = useRef(0) as any;
useEffect(() => {
if (!timeout.current) {
setState(value);
const timeoutCallback = () => {
if (hasNextValue.current) {
hasNextValue.current = false;
setState(nextValue.current);
timeout.current = setTimeout(timeoutCallback, ms);
} else {
timeout.current = undefined;
}
};
timeout.current = setTimeout(timeoutCallback, ms);
} else {
nextValue.current = value;
hasNextValue.current = true;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [value]);
useUnmount(() => {
timeout.current && clearTimeout(timeout.current);
});
return state;
};
export default useThrottle;

44
src/hooks/useTimeoutFn.ts Normal file
View File

@@ -0,0 +1,44 @@
import { useCallback, useEffect, useRef } from "react";
export type UseTimeoutFnReturn = [() => boolean | null, () => void, () => void];
export default function useTimeoutFn(
fn: Function,
ms: number = 0
): UseTimeoutFnReturn {
const ready = useRef<boolean | null>(false);
const timeout = useRef<ReturnType<typeof setTimeout>>();
const callback = useRef(fn);
const isReady = useCallback(() => ready.current, []);
const set = useCallback(() => {
ready.current = false;
timeout.current && clearTimeout(timeout.current);
timeout.current = setTimeout(() => {
ready.current = true;
callback.current();
}, ms);
}, [ms]);
const clear = useCallback(() => {
ready.current = null;
timeout.current && clearTimeout(timeout.current);
}, []);
// update ref when function changes
useEffect(() => {
callback.current = fn;
}, [fn]);
// set on mount, clear on unmount
useEffect(() => {
set();
return clear;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ms]);
return [isReady, clear, set];
}

12
src/hooks/useUnmount.ts Normal file
View File

@@ -0,0 +1,12 @@
import { useRef, useEffect } from "react";
const useUnmount = (fn: () => any): void => {
const fnRef = useRef(fn);
// update the ref each render so if it change the newest callback will be invoked
fnRef.current = fn;
useEffect(() => () => fnRef.current(), []);
};
export default useUnmount;

View File

@@ -2,7 +2,7 @@ import React from "react";
import ReactDOM from "react-dom";
import { RecoilRoot } from "recoil";
import * as serviceWorker from "./serviceWorker";
import App from "./components/App/App";
import App from "./components/App";
import ReactGA from "react-ga";
ReactGA.initialize("UA-179205759-1", { titleCase: false });
@@ -22,8 +22,8 @@ ReactDOM.render(
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
// prettier-ignore
console.log(`
%c sphorphosphor %co%cspho
%c s%cphorphosphor %co%csphorpho%cs
%c o %cp%chorphosphor %co%csphorphosph%co

File diff suppressed because it is too large Load Diff

View File

@@ -15,13 +15,13 @@ export enum IconCategory {
COMMERCE = "commerce",
COMMUNICATION = "communications",
DESIGN = "design",
DEVELOPMENT = "development",
DEVELOPMENT = "technology & development",
OFFICE = "office",
EDITOR = "editor",
FINANCE = "finances",
GAMES = "games",
HEALTH = "health & wellness",
MAP = "maps & navigation",
MAP = "maps & travel",
MEDIA = "media",
NATURE = "nature",
OBJECTS = "objects",

View File

@@ -1,4 +1,5 @@
import { atom } from "recoil";
import { ModalInstance } from "../components/Modal/Modal";
import { IconStyle } from "../lib";
export const searchQueryAtom = atom<string>({
@@ -25,3 +26,13 @@ export const iconPreviewOpenAtom = atom<string | false>({
key: "iconPreviewOpenAtom",
default: false,
});
export const modalAtom = atom<((props: ModalInstance) => JSX.Element) | null>({
key: "modalAtom",
default: null,
});
export const modalOpenAtom = atom<boolean>({
key: "modalOpenAtom",
default: false,
});

View File

@@ -1,10 +1,16 @@
import { selector, selectorFamily } from "recoil";
import { DefaultValue, selector, selectorFamily } from "recoil";
import TinyColor from "tinycolor2";
import Fuse from "fuse.js";
import { searchQueryAtom, iconColorAtom } from "./atoms";
import {
searchQueryAtom,
iconColorAtom,
modalAtom,
modalOpenAtom,
} from "./atoms";
import { IconEntry, IconCategory } from "../lib";
import { icons } from "../lib/icons";
import { ModalInstance } from "../components/Modal/Modal";
const fuse = new Fuse(icons, {
keys: [{ name: "name", weight: 4 }, "tags", "categories"],
@@ -52,17 +58,40 @@ export const singleCategoryQueryResultsSelector = selectorFamily<
IconCategory
>({
key: "singleCategoryQueryResultsSelector",
get: (category: IconCategory) => ({ get }) => {
const filteredResults = get(filteredQueryResultsSelector);
return new Promise((resolve) =>
resolve(
filteredResults.filter((icon) => icon.categories.includes(category))
)
);
},
get:
(category: IconCategory) =>
({ get }) => {
const filteredResults = get(filteredQueryResultsSelector);
return new Promise((resolve) =>
resolve(
filteredResults.filter((icon) => icon.categories.includes(category))
)
);
},
});
export const isDarkThemeSelector = selector<boolean>({
key: "isDarkThemeSelector",
get: ({ get }) => TinyColor(get(iconColorAtom)).isLight(),
});
export const modalSelector = selector<{
type: (props: ModalInstance) => JSX.Element;
} | null>({
key: "openModalSelector",
set: ({ set }, instance) => {
if (instance instanceof DefaultValue || instance === null) {
set(modalAtom, null);
set(modalOpenAtom, false);
return;
}
set(modalAtom, () => instance.type!!);
set(modalOpenAtom, true);
},
get: ({ get }) => {
const currentModal = get(modalAtom);
if (!currentModal) return null;
return { type: currentModal };
},
});

View File

@@ -1,36 +1,27 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"es6",
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"baseUrl": "./src/",
"declaration": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react",
"sourceMap": true,
"declaration": true,
"lib": ["es6", "dom", "dom.iterable", "esnext"],
"module": "esnext",
"moduleResolution": "node",
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"experimentalDecorators": true,
"noFallthroughCasesInSwitch": true,
"noEmit": true
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"target": "es5"
},
"include": [
"src"
],
"exclude": [
"node_modules",
"build"
]
"include": ["src"],
"exclude": ["node_modules", "build"]
}