[WIP] Rework design (#34)
* WIP: Redesign the default layout * Merge old & new default layouts * Fix login logic; add proper user controls dropdown * Fix latest version listing (#31) (#32) Co-authored-by: Aeledfyr <45501007+Aeledfyr@users.noreply.github.com> * First pass of design cleanup * Improve ad integration and fix light theme * Begin splitting up variables, change some styling to new mockup * Continue redesign progress * Work on some more pages * Add missing dark theme variables for text * Continue working on modularizing * Continue progress, redo pagination * Fix auth buttons in navbar layout * Continue progress * Continue progress more * Redo ModResult * Scope ModPage :irritater: * Continue Dashboard * Continue progress on Dashboard and cleanup * Add missing variables for dark theme * Small tweaks, cleanup, and continue mod page progress * Fix user not being able to see hidden mods that they own * Start reworking mod creation * Continue revamp of mod creation page * Yank v-html out * Hotfix markdown rendering and some spacing issues * Move legal; continue with mod creation; create reusable footer * Create README.md * Update README.md * Update README.md * Add in basic usage instructions * Fix some stuff * Continue with mod creation; fix some CSS errors * Start user page * Start transition to vue-select; fix a few bugs * Continue mod creation page * Finish mod pages * Add very raw version editing * Mod editing + creation * Fixed versions that were in processing causing a 404 (#39) Co-authored-by: Mikhail Oleynikov <falseresync@gmail.com> Co-authored-by: Aeledfyr <45501007+Aeledfyr@users.noreply.github.com> Co-authored-by: Jai A <jai.a@tuta.io> Co-authored-by: MulverineX <mulverin3@gmail.com> Co-authored-by: diabolical17 <calumproh28@gmail.com> Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true
|
||||
"singleQuote": true,
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
|
||||
4
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"prettier.endOfLine": "lf",
|
||||
"editor.formatOnSave": true
|
||||
}
|
||||
22
README.md
Normal file
@@ -0,0 +1,22 @@
|
||||

|
||||
|
||||
## Modrinth's center for its frontend service
|
||||
|
||||
## Build Setup
|
||||
|
||||
```bash
|
||||
# install dependencies
|
||||
$ npm install
|
||||
|
||||
# serve with hot reload at localhost:3000
|
||||
$ npm run dev
|
||||
|
||||
# build for production and launch server
|
||||
$ npm run build
|
||||
$ npm run start
|
||||
|
||||
# generate static project
|
||||
$ npm run generate
|
||||
```
|
||||
|
||||
For detailed explanation on how things work, check out [Nuxt.js docs](https://nuxtjs.org).
|
||||
1
assets/images/categories/external.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
|
||||
|
After Width: | Height: | Size: 388 B |
7
assets/images/categories/flame.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
|
||||
<path d="M7.3,20.8c-0.7-0.8-5.2-6-0.6-10.5c3.8-3.8,4.4-6.9,3.1-8.5c0,0,9.7,4,4,13.2c-1,1.6-3.4,3.4-2.1,7.2L7.3,20.8L7.3,20.8z
|
||||
M13.2,22c-0.2-0.8-1.1-2.5,1.7-5.8c1.5-1.8,2.1-4.4,2.2-5.4c0,0,5,2.9,0,9.9C17.2,20.7,13.2,22,13.2,22z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 584 B |
3
assets/images/categories/flameanvil.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="113" height="128" viewBox="0 0 113 128" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24.6637 59.3337L32.1412 51.8562L44.2184 66.0338L29.8772 79.9532C28.7085 81.0876 28.3443 82.8173 28.9563 84.3266C29.5683 85.836 31.0344 86.8235 32.6631 86.8235H92.5028L67.5247 106.806C66.2594 107.818 65.7298 109.494 66.1835 111.049L69.9608 124H31.0805L36.7657 111.596C37.3659 110.286 37.2156 108.755 36.3721 107.587L20.215 85.2161C20.3794 84.9958 20.5226 84.7565 20.6408 84.5005C21.2947 83.0843 21.0658 81.4171 20.0542 80.2297L12.3066 71.1346L20.0395 63.9541C20.0812 63.9153 20.122 63.8758 20.1617 63.8356L24.6614 59.336C24.6622 59.3352 24.6629 59.3344 24.6637 59.3337ZM101.193 76.5647H89.4745C90.2162 73.609 92.1388 69.5598 96.679 64.1834C101.3 58.726 104.009 51.7383 105.519 46.2493C106.213 47.2422 106.872 48.4045 107.402 49.743C109.386 54.7518 109.993 63.3535 101.193 76.5647ZM77.9962 64.0567C75.9317 67.4679 74.1929 71.566 73.842 76.5647H62.454C60.2035 73.7571 56.5771 68.6022 54.7738 62.4556C52.6945 55.3677 53.0109 47.0396 61.1035 39.0164L61.104 39.0159C69.5087 30.6807 74.6146 22.7347 76.8078 15.6999C77.5821 13.2161 78.0043 10.7893 78.0555 8.48397C80.6738 10.3958 83.4898 12.8635 85.9054 15.9006C89.1604 19.9929 91.6386 25.049 92.0315 31.1916C92.424 37.3281 90.7617 44.957 85.0299 54.247C84.3475 55.3429 83.4533 56.4992 82.3222 57.962C82.2062 58.1119 82.0877 58.2651 81.9667 58.4218C80.7208 60.0353 79.2887 61.9211 77.9962 64.0567Z" stroke="currentColor" stroke-width="8" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
8
assets/images/categories/modrinth.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="none"
|
||||
>
|
||||
<path class="st0" d="m20.2 17.6c-0.5-0.2-0.9 0-1.2 0.3-1.2 1.4-2.8 2.5-4.8 3-3.1 0.8-6.2 0-8.4-1.9l3.6-3.2 2.1 1.9 4-1.8 2.1-3.3-0.8-1.6-2.3 1-1 1.3-1.5 0.7-1.2-1-0.8-1.5 1-1.3 1.5-0.7 1.6-2-1.3-1.2-3.8 1.3-2.7 3.5 1.3 2.5-3.7 3.2-0.5-0.8c-0.1-0.2-0.2-0.5-0.3-0.8 0-0.1-0.1-0.2-0.1-0.2-0.1-0.3-0.5-0.6-0.9-0.6-0.5 0-1 0.4-1 1 0.1 0.2 0.1 0.4 0.2 0.5 2 5.3 7.8 8.3 13.4 6.8 2.4-0.6 4.3-1.9 5.8-3.7 0.5-0.4 0.3-1.2-0.3-1.4zm2.6-8.5c-1.7-5.9-7.8-9.4-13.8-7.9-3.8 1-6.6 3.8-7.8 7.1-0.2 0.7 0.3 1.3 0.9 1.3 0.4 0 0.8-0.3 0.9-0.7 1-2.8 3.3-5 6.4-5.9 4.7-1.2 9.5 1.3 11.1 5.6l0.5 1.8c0.1 0.7 0.1 1.4 0.1 2.1v0.1c0 0.4 0.3 0.8 0.7 0.9 0.6 0.2 1.3-0.2 1.3-0.9 0.1-1 0-2.3-0.3-3.5z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 789 B |
10
assets/images/sidebar/admin.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<line x1="14.31" y1="8" x2="20.05" y2="17.94"></line>
|
||||
<line x1="9.69" y1="8" x2="21.17" y2="8"></line>
|
||||
<line x1="7.38" y1="12" x2="13.12" y2="2.06"></line>
|
||||
<line x1="9.69" y1="16" x2="3.95" y2="6.06"></line>
|
||||
<line x1="14.31" y1="16" x2="2.83" y2="16"></line>
|
||||
<line x1="16.62" y1="12" x2="10.88" y2="21.94"></line>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 552 B |
6
assets/images/sidebar/analytics.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="18" y1="20" x2="18" y2="10"></line>
|
||||
<line x1="12" y1="20" x2="12" y2="4"></line>
|
||||
<line x1="6" y1="20" x2="6" y2="14"></line>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 316 B |
3
assets/images/sidebar/mod.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 218 B |
8
assets/images/sidebar/modpack.svg
Normal file
@@ -0,0 +1,8 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
|
||||
<line x1="16.5" y1="9.4" x2="7.5" y2="4.21" />
|
||||
<path
|
||||
d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
|
||||
<polyline points="3.27 6.96 12 12.01 20.73 6.96" />
|
||||
<line x1="12" y1="22.08" x2="12" y2="12" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 471 B |
7
assets/images/sidebar/projects.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<polyline points="22 12 16 12 14 15 10 15 8 12 2 12"></polyline>
|
||||
<path
|
||||
d="M5.45 5.11L2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z">
|
||||
</path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 380 B |
16
assets/images/text-logo-white.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 777 141.73">
|
||||
<g>
|
||||
<path d="M159.07,89.29A70.94,70.94,0,1,0,20,63.52H32A58.78,58.78,0,0,1,145.23,49.93l-11.66,3.12a46.54,46.54,0,0,0-29-26.52l-2.15,12.13a34.31,34.31,0,0,1,2.77,63.26l3.19,11.9a46.52,46.52,0,0,0,28.33-49l11.62-3.1A57.94,57.94,0,0,1,147.27,85Z" transform="translate(-19.79)" fill="#5da545" fill-rule="evenodd"/>
|
||||
<path d="M108.92,139.3A70.93,70.93,0,0,1,19.79,76h12a59.48,59.48,0,0,0,1.78,9.91,58.73,58.73,0,0,0,3.63,9.91l10.68-6.41a46.58,46.58,0,0,1,44.72-65L90.43,36.54A34.38,34.38,0,0,0,57.36,79.75C57.67,80.88,58,82,58.43,83l13.66-8.19L68,63.93l12.9-13.25,16.31-3.51L101.9,53l-7.52,7.61-6.55,2.06-4.69,4.82,2.3,6.38s4.64,4.94,4.65,4.94l6.57-1.74,4.67-5.13,10.2-3.24,3,6.84L104.05,88.43,86.41,94l-7.92-8.81L64.7,93.48a34.44,34.44,0,0,0,28.72,11.59L96.61,117A46.6,46.6,0,0,1,54.13,99.83l-10.64,6.38a58.81,58.81,0,0,0,99.6-9.77l11.8,4.29A70.77,70.77,0,0,1,108.92,139.3Z" transform="translate(-19.79)" fill="#5da545"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M303,52.44q7.51,7.45,7.52,22.37v39H294.54v-37q0-8.92-4-13.45t-11.35-4.52q-8,0-12.87,5.29t-4.85,15.1v34.55H245.59v-37q0-8.92-4-13.45t-11.35-4.52q-8.16,0-12.94,5.22t-4.78,15.17v34.55H196.64V45.75h15.17v8.66a24.78,24.78,0,0,1,9.56-7A32.51,32.51,0,0,1,234.11,45a30.83,30.83,0,0,1,13.58,2.87,22,22,0,0,1,9.37,8.48A28.31,28.31,0,0,1,267.89,48a35.16,35.16,0,0,1,14.66-3Q295.43,45,303,52.44Z" transform="translate(-19.79)" fill="#fff"/>
|
||||
<path d="M343.49,110.25a32.53,32.53,0,0,1-12.94-12.43,35,35,0,0,1-4.66-18,34.68,34.68,0,0,1,4.66-18,32.66,32.66,0,0,1,12.94-12.37,41.33,41.33,0,0,1,37.35,0,32.7,32.7,0,0,1,12.93,12.37,34.68,34.68,0,0,1,4.66,18,35,35,0,0,1-4.66,18,32.57,32.57,0,0,1-12.93,12.43,41.33,41.33,0,0,1-37.35,0Zm33.14-15q5.73-5.86,5.74-15.43t-5.74-15.42a19.46,19.46,0,0,0-14.53-5.87,19.25,19.25,0,0,0-14.47,5.87Q342,70.22,342,79.78t5.67,15.43a19.25,19.25,0,0,0,14.47,5.86A19.46,19.46,0,0,0,376.63,95.21Z" transform="translate(-19.79)" fill="#fff"/>
|
||||
<path d="M480.39,19.23v94.59H465.1V105a24.75,24.75,0,0,1-9.76,7.27,33,33,0,0,1-12.81,2.42,35.84,35.84,0,0,1-17.65-4.33,31.06,31.06,0,0,1-12.3-12.31,36.71,36.71,0,0,1-4.47-18.29,36.4,36.4,0,0,1,4.47-18.23,31.27,31.27,0,0,1,12.3-12.24A35.94,35.94,0,0,1,442.53,45a32.36,32.36,0,0,1,12.37,2.3,24.89,24.89,0,0,1,9.56,6.88V19.23ZM454.77,98.46A18.92,18.92,0,0,0,462,91a22.87,22.87,0,0,0,2.67-11.22A22.87,22.87,0,0,0,462,68.56a18.89,18.89,0,0,0-7.27-7.45,21.65,21.65,0,0,0-20.65,0,18.89,18.89,0,0,0-7.27,7.45,22.87,22.87,0,0,0-2.67,11.22A22.87,22.87,0,0,0,426.85,91a18.92,18.92,0,0,0,7.27,7.46,21.73,21.73,0,0,0,20.65,0Z" transform="translate(-19.79)" fill="#fff"/>
|
||||
<path d="M540.69,45V60.15a20.64,20.64,0,0,0-3.7-.38q-9.3,0-14.53,5.42T517.23,80.8v33H501.3V45.75h15.17v9.94Q523.35,45,540.69,45Z" transform="translate(-19.79)" fill="#fff"/>
|
||||
<path d="M555,31.79A8.94,8.94,0,0,1,552,25,8.94,8.94,0,0,1,555,18.15a10.2,10.2,0,0,1,7.26-2.74A10.55,10.55,0,0,1,569.5,18a8.43,8.43,0,0,1,2.93,6.56,9.58,9.58,0,0,1-2.87,7.08,9.92,9.92,0,0,1-7.33,2.87A10.2,10.2,0,0,1,555,31.79Zm-.77,14h15.94v68.07H554.2Z" transform="translate(-19.79)" fill="#fff"/>
|
||||
<path d="M650.32,52.5q7.77,7.53,7.77,22.31v39H642.16v-37q0-8.92-4.21-13.45t-12-4.52q-8.81,0-13.9,5.29T607,79.4v34.42H591V45.75h15.17v8.79a25,25,0,0,1,9.94-7.14A35.91,35.91,0,0,1,629.67,45Q642.54,45,650.32,52.5Z" transform="translate(-19.79)" fill="#fff"/>
|
||||
<path d="M716.6,110.12a18.65,18.65,0,0,1-6.82,3.44,30.46,30.46,0,0,1-8.47,1.15q-11.22,0-17.34-5.86t-6.12-17.09V30.7h15.94V46.26H712V59H693.79V91.38c0,3.32.82,5.85,2.48,7.59a9.14,9.14,0,0,0,7,2.61,14,14,0,0,0,8.92-2.8Z" transform="translate(-19.79)" fill="#fff"/>
|
||||
<path d="M789,52.5q7.77,7.53,7.78,22.31v39H780.85v-37q0-8.92-4.21-13.45t-12-4.52q-8.79,0-13.89,5.29t-5.1,15.23v34.42H729.73V19.23h15.94V53.65a25.82,25.82,0,0,1,9.75-6.44A36,36,0,0,1,768.36,45Q781.23,45,789,52.5Z" transform="translate(-19.79)" fill="#fff"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
5632
assets/images/text-logo.ai
Normal file
16
assets/images/text-logo.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 777 141.73">
|
||||
<g>
|
||||
<path d="M159.07,89.29A70.94,70.94,0,1,0,20,63.52H32A58.78,58.78,0,0,1,145.23,49.93l-11.66,3.12a46.54,46.54,0,0,0-29-26.52l-2.15,12.13a34.31,34.31,0,0,1,2.77,63.26l3.19,11.9a46.52,46.52,0,0,0,28.33-49l11.62-3.1A57.94,57.94,0,0,1,147.27,85Z" transform="translate(-19.79)" fill="#5da545" fill-rule="evenodd"/>
|
||||
<path d="M108.92,139.3A70.93,70.93,0,0,1,19.79,76h12a59.48,59.48,0,0,0,1.78,9.91,58.73,58.73,0,0,0,3.63,9.91l10.68-6.41a46.58,46.58,0,0,1,44.72-65L90.43,36.54A34.38,34.38,0,0,0,57.36,79.75C57.67,80.88,58,82,58.43,83l13.66-8.19L68,63.93l12.9-13.25,16.31-3.51L101.9,53l-7.52,7.61-6.55,2.06-4.69,4.82,2.3,6.38s4.64,4.94,4.65,4.94l6.57-1.74,4.67-5.13,10.2-3.24,3,6.84L104.05,88.43,86.41,94l-7.92-8.81L64.7,93.48a34.44,34.44,0,0,0,28.72,11.59L96.61,117A46.6,46.6,0,0,1,54.13,99.83l-10.64,6.38a58.81,58.81,0,0,0,99.6-9.77l11.8,4.29A70.77,70.77,0,0,1,108.92,139.3Z" transform="translate(-19.79)" fill="#5da545"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M303,52.44q7.51,7.45,7.52,22.37v39H294.54v-37q0-8.92-4-13.45t-11.35-4.52q-8,0-12.87,5.29t-4.85,15.1v34.55H245.59v-37q0-8.92-4-13.45t-11.35-4.52q-8.16,0-12.94,5.22t-4.78,15.17v34.55H196.64V45.75h15.17v8.66a24.78,24.78,0,0,1,9.56-7A32.51,32.51,0,0,1,234.11,45a30.83,30.83,0,0,1,13.58,2.87,22,22,0,0,1,9.37,8.48A28.31,28.31,0,0,1,267.89,48a35.16,35.16,0,0,1,14.66-3Q295.43,45,303,52.44Z" transform="translate(-19.79)" fill="#19202c"/>
|
||||
<path d="M343.49,110.25a32.53,32.53,0,0,1-12.94-12.43,35,35,0,0,1-4.66-18,34.68,34.68,0,0,1,4.66-18,32.66,32.66,0,0,1,12.94-12.37,41.33,41.33,0,0,1,37.35,0,32.7,32.7,0,0,1,12.93,12.37,34.68,34.68,0,0,1,4.66,18,35,35,0,0,1-4.66,18,32.57,32.57,0,0,1-12.93,12.43,41.33,41.33,0,0,1-37.35,0Zm33.14-15q5.73-5.86,5.74-15.43t-5.74-15.42a19.46,19.46,0,0,0-14.53-5.87,19.25,19.25,0,0,0-14.47,5.87Q342,70.22,342,79.78t5.67,15.43a19.25,19.25,0,0,0,14.47,5.86A19.46,19.46,0,0,0,376.63,95.21Z" transform="translate(-19.79)" fill="#19202c"/>
|
||||
<path d="M480.39,19.23v94.59H465.1V105a24.75,24.75,0,0,1-9.76,7.27,33,33,0,0,1-12.81,2.42,35.84,35.84,0,0,1-17.65-4.33,31.06,31.06,0,0,1-12.3-12.31,36.71,36.71,0,0,1-4.47-18.29,36.4,36.4,0,0,1,4.47-18.23,31.27,31.27,0,0,1,12.3-12.24A35.94,35.94,0,0,1,442.53,45a32.36,32.36,0,0,1,12.37,2.3,24.89,24.89,0,0,1,9.56,6.88V19.23ZM454.77,98.46A18.92,18.92,0,0,0,462,91a22.87,22.87,0,0,0,2.67-11.22A22.87,22.87,0,0,0,462,68.56a18.89,18.89,0,0,0-7.27-7.45,21.65,21.65,0,0,0-20.65,0,18.89,18.89,0,0,0-7.27,7.45,22.87,22.87,0,0,0-2.67,11.22A22.87,22.87,0,0,0,426.85,91a18.92,18.92,0,0,0,7.27,7.46,21.73,21.73,0,0,0,20.65,0Z" transform="translate(-19.79)" fill="#19202c"/>
|
||||
<path d="M540.69,45V60.15a20.64,20.64,0,0,0-3.7-.38q-9.3,0-14.53,5.42T517.23,80.8v33H501.3V45.75h15.17v9.94Q523.35,45,540.69,45Z" transform="translate(-19.79)" fill="#19202c"/>
|
||||
<path d="M555,31.79A8.94,8.94,0,0,1,552,25,8.94,8.94,0,0,1,555,18.15a10.2,10.2,0,0,1,7.26-2.74A10.55,10.55,0,0,1,569.5,18a8.43,8.43,0,0,1,2.93,6.56,9.58,9.58,0,0,1-2.87,7.08,9.92,9.92,0,0,1-7.33,2.87A10.2,10.2,0,0,1,555,31.79Zm-.77,14h15.94v68.07H554.2Z" transform="translate(-19.79)" fill="#19202c"/>
|
||||
<path d="M650.32,52.5q7.77,7.53,7.77,22.31v39H642.16v-37q0-8.92-4.21-13.45t-12-4.52q-8.81,0-13.9,5.29T607,79.4v34.42H591V45.75h15.17v8.79a25,25,0,0,1,9.94-7.14A35.91,35.91,0,0,1,629.67,45Q642.54,45,650.32,52.5Z" transform="translate(-19.79)" fill="#19202c"/>
|
||||
<path d="M716.6,110.12a18.65,18.65,0,0,1-6.82,3.44,30.46,30.46,0,0,1-8.47,1.15q-11.22,0-17.34-5.86t-6.12-17.09V30.7h15.94V46.26H712V59H693.79V91.38c0,3.32.82,5.85,2.48,7.59a9.14,9.14,0,0,0,7,2.61,14,14,0,0,0,8.92-2.8Z" transform="translate(-19.79)" fill="#19202c"/>
|
||||
<path d="M789,52.5q7.77,7.53,7.78,22.31v39H780.85v-37q0-8.92-4.21-13.45t-12-4.52q-8.79,0-13.89,5.29t-5.1,15.23v34.42H729.73V19.23h15.94V53.65a25.82,25.82,0,0,1,9.75-6.44A36,36,0,0,1,768.36,45Q781.23,45,789,52.5Z" transform="translate(-19.79)" fill="#19202c"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -1,15 +1,3 @@
|
||||
<svg viewBox="0 0 273 291" fill-rule="evenodd" stroke-linejoin="round">
|
||||
<g transform="matrix(1,0,0,1,-3303.68,-2082.6)">
|
||||
<g transform="matrix(0.564163,0,0,1.70346,1629.87,0)">
|
||||
<g transform="matrix(29.6754,0,-5.39484e-14,10.5245,2970.52,1222.47)">
|
||||
<g transform="matrix(1.4323,0,0,1.4323,-3.56656,-3.89073)">
|
||||
<path d="M10.854,7.146C10.948,7.24 11.001,7.367 11.001,7.5C11.001,7.633 10.948,7.76 10.854,7.854L7.854,10.854C7.76,10.948 7.633,11.001 7.5,11.001C7.367,11.001 7.24,10.948 7.146,10.854L5.646,9.354C5.552,9.26 5.499,9.133 5.499,9C5.499,8.725 5.725,8.499 6,8.499C6.133,8.499 6.26,8.552 6.354,8.646L7.5,9.793L10.146,7.146C10.24,7.052 10.367,6.999 10.5,6.999C10.633,6.999 10.76,7.052 10.854,7.146Z"/>
|
||||
</g>
|
||||
<path d="M1.427,4L1.427,13.715C1.427,14.264 1.879,14.715 2.427,14.715L13.573,14.715C14.121,14.715 14.573,14.264 14.573,13.715L14.573,4L1.427,4ZM1.878,1C0.781,1 -0.122,1.903 -0.122,3L-0.122,14.191C-0.122,15.288 0.781,16.191 1.878,16.191L14.183,16.191C15.28,16.191 16.183,15.097 16.183,14L16.183,3C16.183,1.903 15.28,1 14.183,1L1.878,1Z"/>
|
||||
<g transform="matrix(1.32086,0,-1.73365e-32,1.32086,-3.43823,0.00935866)">
|
||||
<path d="M4.819,0C5.094,-0 5.319,0.226 5.319,0.5L5.319,1C5.319,1.274 5.094,1.5 4.819,1.5C4.545,1.5 4.319,1.274 4.319,1L4.319,0.5C4.319,0.226 4.545,0 4.819,0ZM12.5,0C12.774,-0 13,0.226 13,0.5L13,1C13,1.274 12.774,1.5 12.5,1.5C12.226,1.5 12,1.274 12,1L12,0.5C12,0.226 12.226,0 12.5,0Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 7V3M16 7V3M7 11H17M5 21H19C20.1046 21 21 20.1046 21 19V7C21 5.89543 20.1046 5 19 5H5C3.89543 5 3 5.89543 3 7V19C3 20.1046 3.89543 21 5 21Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 343 B |
@@ -1,5 +1,3 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||||
<polyline points="7 10 12 15 17 10"></polyline>
|
||||
<line x1="12" y1="15" x2="12" y2="3"></line>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 16L4 17C4 18.6569 5.34315 20 7 20L17 20C18.6569 20 20 18.6569 20 17L20 16M16 12L12 16M12 16L8 12M12 16L12 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 312 B |
3
assets/images/utils/dropdown.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 9L12 16L5 9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 217 B |
@@ -1,15 +1,3 @@
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
|
||||
></path>
|
||||
<path
|
||||
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
|
||||
></path>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11 5H6C4.89543 5 4 5.89543 4 7V18C4 19.1046 4.89543 20 6 20H17C18.1046 20 19 19.1046 19 18V13M17.5858 3.58579C18.3668 2.80474 19.6332 2.80474 20.4142 3.58579C21.1953 4.36683 21.1953 5.63316 20.4142 6.41421L11.8284 15H9L9 12.1716L17.5858 3.58579Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 448 B |
@@ -1 +1,6 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
|
||||
<polyline points="15 3 21 3 21 9"></polyline>
|
||||
<line x1="10" y1="14" x2="21" y2="3"></line>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 293 B After Width: | Height: | Size: 312 B |
1
assets/images/utils/gap.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="2" viewBox="0 0 14 2"><path d="M18,12H6" transform="translate(-5 -11)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
|
||||
|
After Width: | Height: | Size: 235 B |
4
assets/images/utils/github.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg enable-background="new 0 0 24 24" version="1.1" viewBox="0 0 24 24" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="currentColor" class="st0" d="m12 1c-6.3 0-11.3 5-11.3 11.3 0 5 3.2 9.2 7.7 10.7 0.6 0.1 0.8-0.2 0.8-0.5v-1.9c-3.2 0.6-3.8-1.6-3.8-1.6-0.5-1.3-1.3-1.7-1.3-1.7-1-0.7 0.1-0.7 0.1-0.7 1.1 0.1 1.7 1.2 1.7 1.2 1 1.7 2.7 1.2 3.3 0.9 0.1-0.7 0.4-1.2 0.7-1.5-2.5-0.2-5.1-1.2-5.1-5.5 0-1.2 0.4-2.2 1.2-3-0.1-0.3-0.5-1.4 0.1-3 0 0 1-0.3 3.1 1.2 0.9-0.3 1.8-0.5 2.8-0.5s1.9 0.1 2.8 0.4c2.2-1.5 3.1-1.2 3.1-1.2 0.6 1.6 0.2 2.7 0.1 3 0.7 0.8 1.2 1.8 1.2 3 0 4.4-2.6 5.3-5.2 5.6 0.4 0.3 0.8 1 0.8 2.1v3.1c0 0.3 0.2 0.7 0.8 0.5 4.5-1.5 7.7-5.7 7.7-10.7 0-6.2-5-11.2-11.3-11.2z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 752 B |
6
assets/images/utils/hamburger.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor"
|
||||
stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu">
|
||||
<line x1="3" y1="12" x2="21" y2="12" />
|
||||
<line x1="3" y1="6" x2="21" y2="6" />
|
||||
<line x1="3" y1="18" x2="21" y2="18" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 351 B |
1
assets/images/utils/left-arrow.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14.414" height="12.162" viewBox="0 0 14.414 12.162"><path d="M7.667,14.333,3,9.667m0,0L7.667,5M3,9.667H15" transform="translate(-1.586 -3.586)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
|
||||
|
After Width: | Height: | Size: 296 B |
6
assets/images/utils/log-out.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
||||
<polyline points="16 17 21 12 16 7"></polyline>
|
||||
<line x1="21" y1="12" x2="9" y2="12"></line>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 297 B |
4
assets/images/utils/moon.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 239 B |
1
assets/images/utils/right-arrow.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14.414" height="12.162" viewBox="0 0 14.414 12.162"><path d="M7.667,14.333,3,9.667m0,0L7.667,5M3,9.667H15" transform="translate(16 15.748) rotate(180)" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"/></svg>
|
||||
|
After Width: | Height: | Size: 304 B |
3
assets/images/utils/search.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M21 21L15 15M17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 323 B |
12
assets/images/utils/sun.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="5"></circle>
|
||||
<line x1="12" y1="1" x2="12" y2="3"></line>
|
||||
<line x1="12" y1="21" x2="12" y2="23"></line>
|
||||
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line>
|
||||
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line>
|
||||
<line x1="1" y1="12" x2="3" y2="12"></line>
|
||||
<line x1="21" y1="12" x2="23" y2="12"></line>
|
||||
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line>
|
||||
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 649 B |
3
assets/images/utils/tag.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7 7H7.01M7 3H12C12.5119 2.99999 13.0237 3.19525 13.4142 3.58579L20.4143 10.5858C21.1953 11.3668 21.1953 12.6332 20.4143 13.4142L13.4142 20.4142C12.6332 21.1953 11.3668 21.1953 10.5858 20.4142L3.58579 13.4142C3.19526 13.0237 3 12.5118 3 12V7C3 4.79086 4.79086 3 7 3Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 468 B |
5
assets/images/utils/user.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="12" cy="7" r="4"></circle>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 241 B |
7
assets/images/utils/users.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round">
|
||||
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
|
||||
<circle cx="9" cy="7" r="4"></circle>
|
||||
<path d="M23 21v-2a4 4 0 0 0-3-3.87"></path>
|
||||
<path d="M16 3.13a4 4 0 0 1 0 7.75"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 337 B |
3
assets/images/utils/x.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 337 B |
@@ -7,54 +7,47 @@
|
||||
|
||||
input {
|
||||
padding-left: 2.5rem;
|
||||
|
||||
&:hover {
|
||||
&+svg {
|
||||
color: var(--color-grey-6);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
&+svg {
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
color: var(--color-grey-5);
|
||||
color: var(--color-icon);
|
||||
margin-right: -2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.badge {
|
||||
max-height: 1rem;
|
||||
border-radius: 1rem;
|
||||
font-size: 0.8rem;
|
||||
font-size: var(--font-size-xs);
|
||||
font-weight: bold;
|
||||
letter-spacing: 0.02rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
|
||||
&.gray {
|
||||
background-color: #c8c1c1;
|
||||
color: #646161;
|
||||
background-color: var(--color-badge-gray-bg);
|
||||
color: var(--color-badge-gray-text);
|
||||
}
|
||||
|
||||
&.red {
|
||||
background-color: #fed7d7;
|
||||
color: #9b2c2c;
|
||||
background-color: var(--color-badge-red-bg);
|
||||
color: var(--color-badge-red-text);
|
||||
}
|
||||
|
||||
&.green {
|
||||
background-color: #c6f6d5;
|
||||
color: #276749;
|
||||
background-color: var(--color-badge-green-bg);
|
||||
color: var(--color-badge-green-text);
|
||||
}
|
||||
|
||||
&.yellow {
|
||||
background-color: #f6e8c6;
|
||||
color: #675027;
|
||||
background-color: var(--color-badge-yellow-bg);
|
||||
color: var(--color-badge-yellow-text);
|
||||
}
|
||||
}
|
||||
|
||||
.text-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.required:after {
|
||||
content: ' *';
|
||||
color: red;
|
||||
@@ -70,14 +63,14 @@
|
||||
|
||||
h1, h2 {
|
||||
padding: 10px 0 5px;
|
||||
border-bottom: 1px solid var(--color-grey-3);
|
||||
border-bottom: 1px solid var(--color-header-underline);
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 15px 0;
|
||||
padding: 0 1em;
|
||||
color: var(--color-grey-5);
|
||||
border-left: .25em solid var(--color-grey-3);
|
||||
color: var(--color-text);
|
||||
border-left: .25em solid var(--color-block-quote);
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -90,8 +83,8 @@
|
||||
|
||||
pre {
|
||||
padding: 15px 10px;
|
||||
border-radius: var(--size-rounded-sm);
|
||||
background-color: var(--color-grey-1);
|
||||
border-radius: var(--size-rounded-control);
|
||||
background-color: var(--color-code-bg);
|
||||
|
||||
code {
|
||||
font-size: 80%;
|
||||
@@ -101,10 +94,11 @@
|
||||
}
|
||||
|
||||
code {
|
||||
padding: .2em .4em;
|
||||
font-size: 60%;
|
||||
border-radius: var(--size-rounded-sm);
|
||||
background-color: var(--color-grey-1)
|
||||
padding: 0.2em 0.4em;
|
||||
font-size: 80%;
|
||||
border-radius: var(--size-rounded-control);
|
||||
background-color: var(--color-code-bg);
|
||||
color: var(--color-code-text);
|
||||
}
|
||||
|
||||
hr {
|
||||
@@ -118,9 +112,12 @@
|
||||
z-index: 10000;
|
||||
|
||||
.tooltip-inner {
|
||||
background: var(--color-grey-2);
|
||||
color: var(--color-text);
|
||||
background: var(--color-tooltip-bg);
|
||||
color: var(--color-tooltip-text);
|
||||
padding: 5px 10px 4px;
|
||||
border-radius: var(--size-rounded-tooltip);
|
||||
box-shadow: var(--shadow-tooltip);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
@@ -129,7 +126,7 @@
|
||||
border-style: solid;
|
||||
position: absolute;
|
||||
margin: 5px;
|
||||
border-color: var(--color-grey-2);
|
||||
border-color: var(--color-tooltip-bg);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@@ -205,3 +202,174 @@
|
||||
transition: opacity .15s;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
padding: 0.5rem 1rem;
|
||||
.filler {
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.tabs a.tab {
|
||||
user-select: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0.25rem;
|
||||
padding-bottom: 0.2rem;
|
||||
margin: auto 0.5rem;
|
||||
border-bottom: 3px solid transparent;
|
||||
|
||||
svg {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
border-bottom: 3px solid var(--color-brand-disabled);
|
||||
color: var(--color-text-medium);
|
||||
}
|
||||
|
||||
&.nuxt-link-exact-active {
|
||||
border-bottom: 3px solid var(--color-brand);
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
.card {
|
||||
padding: var(--spacing-card-md);
|
||||
margin-bottom: var(--spacing-card-md);
|
||||
@extend %card;
|
||||
|
||||
&.page-nav {
|
||||
.tab {
|
||||
padding: var(--spacing-card-sm);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: var(--size-rounded-control);
|
||||
margin-bottom: 0.5rem;
|
||||
@extend %transparent-clickable;
|
||||
|
||||
&.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
svg {
|
||||
color: var(--color-icon);
|
||||
margin-right: 5px;
|
||||
height: 1.25rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&.nuxt-link-exact-active {
|
||||
svg {
|
||||
color: var(--color-brand-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-l {
|
||||
@extend .sidebar;
|
||||
margin-right: var(--spacing-card-lg);
|
||||
}
|
||||
|
||||
.sidebar-r {
|
||||
@extend .sidebar;
|
||||
margin-left: var(--spacing-card-lg);
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: auto 0;
|
||||
padding: 6px 20px;
|
||||
border-radius: var(--size-rounded-control);
|
||||
color: var(--color-button-text);
|
||||
background-color: var(--color-button-bg);
|
||||
font-weight: var(--font-weight-medium);
|
||||
&:focus,
|
||||
&:hover {
|
||||
background-color: var(--color-button-bg-hover);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--color-button-bg-active);
|
||||
}
|
||||
}
|
||||
|
||||
.transparent-button {
|
||||
@extend %transparent-clickable;
|
||||
margin: auto 0;
|
||||
padding: 6px 20px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.brand-button {
|
||||
@extend .button;
|
||||
color: var(--color-brand-inverted);
|
||||
background-color: var(--color-brand);
|
||||
&:focus,
|
||||
&:hover {
|
||||
background-color: var(--color-brand-hover);
|
||||
color: var(--color-brand-inverted);
|
||||
}
|
||||
&:active {
|
||||
background-color: var(--color-brand-active);
|
||||
color: var(--color-brand-inverted);
|
||||
}
|
||||
}
|
||||
|
||||
.multiselect--above .multiselect__content-wrapper {
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
.multiselect {
|
||||
color: var(--color-text) !important;
|
||||
input {
|
||||
background: transparent;
|
||||
}
|
||||
.multiselect__tags {
|
||||
background: var(--color-dropdown-bg);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
&:active,
|
||||
&:hover {
|
||||
background: var(--color-button-bg-hover);
|
||||
}
|
||||
.multiselect__single {
|
||||
background: transparent;
|
||||
}
|
||||
.multiselect__tag {
|
||||
color: var(--color-text-dark);
|
||||
background: transparent;
|
||||
border: 2px solid var(--color-brand);
|
||||
}
|
||||
.multiselect__tag-icon {
|
||||
background: transparent;
|
||||
&:after {
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
}
|
||||
}
|
||||
.multiselect__content-wrapper {
|
||||
background: var(--color-dropdown-bg);
|
||||
border: none;
|
||||
.multiselect__element {
|
||||
.multiselect__option--highlight {
|
||||
background: var(--color-button-bg-active);
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
.multiselect__option--selected {
|
||||
background: var(--color-brand);
|
||||
font-weight: bold;
|
||||
color: var(--color-brand-inverted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +1,204 @@
|
||||
.light-mode {
|
||||
--color-text: #1a202c;
|
||||
--color-bg: #ffffff;
|
||||
--color-icon: #718096;
|
||||
--color-text:#4A5568;
|
||||
--color-text-medium:#2a303d;
|
||||
--color-text-dark:#1A202C;
|
||||
--color-heading: #2c313d;
|
||||
--color-heading-light: #777e8d;
|
||||
--color-bg: #edf2f7;
|
||||
--color-raised-bg: #ffffff;
|
||||
--color-divider: #eaecef;
|
||||
--color-divider-dark: #c8cdd3;
|
||||
|
||||
--color-text-inverted: var(--color-bg);
|
||||
--color-bg-inverted: var(--color-text);
|
||||
|
||||
--color-brand: #4d9227;
|
||||
--color-brand: #5da545;
|
||||
--color-brand-hover: #53923e;
|
||||
--color-brand-active: #4b8138;
|
||||
--color-brand-light: #6bac57;
|
||||
--color-brand-inverted: #ffffff;
|
||||
--color-brand-2: #5fa33b;
|
||||
--color-brand-3: #c5ddb7;
|
||||
--color-brand-disabled: #e2e8f0;
|
||||
|
||||
--color-grey-0: #f7fafc;
|
||||
--color-grey-1: #edf2f7;
|
||||
--color-grey-2: #e2e8f0;
|
||||
--color-grey-3: #cbd5e0;
|
||||
--color-grey-4: #a0aec0;
|
||||
--color-grey-5: #718096;
|
||||
--color-grey-6: #4a5568;
|
||||
--color-grey-7: #2d3748;
|
||||
--color-button-bg: var(--color-bg);
|
||||
--color-button-text: var(--color-text-dark);
|
||||
--color-button-bg-hover: #e0e7ee;
|
||||
--color-button-text-hover: #1b1e24;
|
||||
--color-button-bg-active: #d0d7df;
|
||||
--color-button-text-active: var(--color-button-text-hover);
|
||||
--color-button-bg-disabled: #eceef0;
|
||||
--color-button-text-disabled: #9da3ac;
|
||||
--color-transparent-button-bg-hover: var(--color-button-bg);
|
||||
--color-transparent-button-text-hover: var(--color-text-dark);
|
||||
--color-transparent-button-bg-active: var(--color-button-bg-hover);
|
||||
--color-transparent-button-text-active: var(--color-text-dark);
|
||||
|
||||
--color-dropdown-bg: var(--color-button-bg);
|
||||
--color-dropdown-text: var(--color-button-text);
|
||||
|
||||
--color-category-bg: var(--color-bg);
|
||||
--color-category-text: var(--color-text-dark);
|
||||
|
||||
--color-tooltip-bg: var(--color-text);
|
||||
--color-tooltip-text: var(--color-bg);
|
||||
|
||||
--color-code-bg: var(--color-bg);
|
||||
--color-code-text: var(--color-text-dark);
|
||||
|
||||
--color-ad: #d6e6f9;
|
||||
|
||||
--shadow-dropdown: 3px 3px 14px hsla(0, 0%, 0%, 0.15);
|
||||
--shadow-dropdown-strong: 3px 3px 10px hsla(0, 0%, 0%, 0.3);
|
||||
--shadow-tooltip: 0.2rem 0.2rem 10px rgba(0, 0, 0, 0.15);
|
||||
|
||||
--color-link: #2089ff;
|
||||
|
||||
--color-badge-gray-text: #646161;
|
||||
--color-badge-gray-bg: #c8c1c1;
|
||||
--color-badge-red-text: #9b2c2c;
|
||||
--color-badge-red-bg: #fed7d7;
|
||||
--color-badge-green-text: #276749;
|
||||
--color-badge-green-bg: #c6f6d5;
|
||||
--color-badge-yellow-text: #675027;
|
||||
--color-badge-yellow-bg: #f6e8c6;
|
||||
|
||||
--color-block-quote: var(--color-tooltip-bg);
|
||||
--color-header-underline: var(--color-tooltip-text);
|
||||
--color-hr: var(--color-text);
|
||||
}
|
||||
|
||||
.dark-mode {
|
||||
--color-text: #ccccc2;
|
||||
--color-bg: #191917;
|
||||
--color-icon: #acacac;
|
||||
--color-text: #cecece;
|
||||
--color-text-medium:#e4e4e4;
|
||||
--color-text-dark:#ffffff;
|
||||
--color-heading: #ffffff;
|
||||
--color-heading-light: #8a8a8a;
|
||||
--color-bg: #171719;
|
||||
--color-raised-bg: #222224;
|
||||
--color-divider: #49494d;
|
||||
--color-divider-dark: #646468;
|
||||
|
||||
--color-text-inverted: var(--color-bg);
|
||||
--color-bg-inverted: var(--color-text);
|
||||
|
||||
--color-brand: #4d9227;
|
||||
--color-brand: #5da545;
|
||||
--color-brand-hover: #6bac57;
|
||||
--color-brand-active: #7fc46a;
|
||||
--color-brand-light: #6bac57;
|
||||
--color-brand-inverted: #ffffff;
|
||||
--color-brand-2: #438121;
|
||||
--color-brand-3: #344d26;
|
||||
--color-brand-disabled: #414146;
|
||||
|
||||
--color-grey-7: #f7faf0;
|
||||
--color-grey-6: #f7f2eb;
|
||||
--color-grey-5: #ede9e4;
|
||||
--color-grey-4: #b3b3b3;
|
||||
--color-grey-3: #797b76;
|
||||
--color-grey-2: #3b3937;
|
||||
--color-grey-1: #3a3b38;
|
||||
--color-grey-0: #1d1e1b;
|
||||
--color-button-bg: #343438;
|
||||
--color-button-text: var(--color-text);
|
||||
--color-button-bg-hover: #3a3a3f;
|
||||
--color-button-text-hover: #ffffff;
|
||||
--color-button-bg-active: #49494e;
|
||||
--color-button-text-active: var(--color-button-text-hover);
|
||||
--color-button-text-disabled: #444444;
|
||||
--color-transparent-button-bg-hover: var(--color-button-bg);
|
||||
--color-transparent-button-text-hover: var(--color-text-dark);
|
||||
--color-transparent-button-bg-active: var(--color-button-bg-hover);
|
||||
--color-transparent-button-text-active: var(--color-text-dark);
|
||||
|
||||
--color-dropdown-bg: var(--color-button-bg);
|
||||
--color-dropdown-text: var(--color-button-text);
|
||||
|
||||
--color-category-bg: var(--color-button-bg);
|
||||
--color-category-text: var(--color-text-dark);
|
||||
|
||||
--color-tooltip-bg: var(--color-text);
|
||||
--color-tooltip-text: var(--color-bg);
|
||||
|
||||
--color-code-bg: var(--color-button-bg);
|
||||
--color-code-text: var(--color-text-dark);
|
||||
|
||||
--color-ad: #2c323a;
|
||||
|
||||
--shadow-dropdown: 3px 3px 14px hsla(0, 0%, 0%, 0.15);
|
||||
--shadow-dropdown-strong: 3px 3px 20px hsla(0, 0%, 0%, 0.15);
|
||||
--shadow-tooltip: 0.2rem 0.2rem 10px rgba(0, 0, 0, 0.15);
|
||||
|
||||
--color-link: #4793d9;
|
||||
|
||||
--color-badge-gray-bg: #646161;
|
||||
--color-badge-gray-text: #c8c1c1;
|
||||
--color-badge-red-bg: #9b2c2c;
|
||||
--color-badge-red-text: #fed7d7;
|
||||
--color-badge-green-bg: #276749;
|
||||
--color-badge-green-text: #c6f6d5;
|
||||
--color-badge-yellow-bg: #675027;
|
||||
--color-badge-yellow-text: #f6e8c6;
|
||||
|
||||
--color-block-quote:var(--color-code-bg);
|
||||
--color-header-underline: var(--color-tooltip-text);
|
||||
--color-hr: var(--color-text);
|
||||
}
|
||||
|
||||
body {
|
||||
// Defaults
|
||||
background-color: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
font-family: Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen,
|
||||
Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
--font-standard: Inter, -apple-system, BlinkMacSystemFont, Segoe UI, Oxygen, Ubuntu, Roboto, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
|
||||
font-family: var(--font-standard);
|
||||
font-size: 16px;
|
||||
font-weight: var(--font-weight-medium);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
/**
|
||||
* Sizes
|
||||
*/
|
||||
--size-rounded-sm: 0.25rem;
|
||||
--size-rounded-md: 0.5rem;
|
||||
--size-rounded-lg: 1rem;
|
||||
overflow-y: overlay;
|
||||
|
||||
/**
|
||||
* Defaults
|
||||
*/
|
||||
font-size: 18px;
|
||||
// Rounding sizes
|
||||
--size-rounded-xs: 0.5rem;
|
||||
--size-rounded-sm: 0.75rem;
|
||||
--size-rounded-md: 1rem;
|
||||
--size-rounded-lg: 1.25rem;
|
||||
|
||||
--size-rounded-max: 999999999px;
|
||||
--size-rounded-card: 0.5rem;
|
||||
--size-rounded-icon: 0.5rem;
|
||||
--size-rounded-control: 0.25rem;
|
||||
--size-rounded-tooltip: 0.25rem;
|
||||
|
||||
--size-navbar-height: 4rem;
|
||||
|
||||
--spacing-card-lg: 1.5rem;
|
||||
--spacing-card-md: 0.75rem;
|
||||
--spacing-card-sm: 0.5rem;
|
||||
|
||||
// Font Sizes
|
||||
--font-size-xxs: 0.625rem; //10px
|
||||
--font-size-xs: 0.75rem; //12px
|
||||
--font-size-sm: 0.875rem; //14px
|
||||
--font-size-nm: 1rem; //16px
|
||||
--font-size-md: 1.125rem; //18px
|
||||
--font-size-lg: 1.25rem; //20px
|
||||
--font-size-xl: 1.5rem; //24px
|
||||
--font-size-2xl: 2rem; //32px
|
||||
--font-size-3xl: 3rem; //48px
|
||||
|
||||
// Font Weights
|
||||
--font-weight-regular: 400;
|
||||
--font-weight-medium: 500;
|
||||
--font-weight-bold: 700;
|
||||
--font-weight-extrabold: 800;
|
||||
|
||||
--font-weight-text: var(--font-weight-medium);
|
||||
--font-weight-heading: var(--font-weight-extrabold);
|
||||
--font-weight-title: var(--font-weight-extrabold);
|
||||
|
||||
// Temporary
|
||||
--color-grey-7: #ff0000;
|
||||
--color-grey-6: #ff0000;
|
||||
--color-grey-5: #ff0000;
|
||||
--color-grey-4: #ff0000;
|
||||
--color-grey-3: #ff0000;
|
||||
--color-grey-2: #ff0000;
|
||||
--color-grey-1: #ff0000;
|
||||
--color-grey-0: #ff0000;
|
||||
}
|
||||
|
||||
svg {
|
||||
@@ -72,38 +213,91 @@ a {
|
||||
|
||||
h2 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1.25rem;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0;
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
|
||||
input {
|
||||
background: var(--color-bg);
|
||||
border: 2px solid var(--color-grey-3);
|
||||
border-radius: var(--size-rounded-sm);
|
||||
color: var(--color-grey-9);
|
||||
font-size: 1rem;
|
||||
button {
|
||||
cursor: pointer;
|
||||
@extend .button;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
background: var(--color-button-bg);
|
||||
border-radius: var(--size-rounded-control);
|
||||
color: var(--color-text);
|
||||
padding: 0.5rem 1rem;
|
||||
width: 100%;
|
||||
border: 2px solid transparent;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
border-color: var(--color-grey-4);
|
||||
background: var(--color-button-bg-hover);
|
||||
color: var(--color-text);
|
||||
outline: none;
|
||||
|
||||
&::placeholder {
|
||||
color: var(--color-grey-7);
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: var(--color-raised-bg);
|
||||
border-color: var(--color-divider-dark);
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: var(--color-grey-6);
|
||||
color: var(--color-color-text);
|
||||
}
|
||||
}
|
||||
|
||||
.ea-content {
|
||||
background: var(--color-ad) !important;
|
||||
border-radius: var(--size-rounded-card) !important;
|
||||
margin-left: 0 !important;
|
||||
margin-right: 0 !important;
|
||||
margin-bottom: 0 !important;
|
||||
margin-top: 0 !important;
|
||||
box-shadow: var(--shadow-faint) !important;
|
||||
}
|
||||
|
||||
.ea-callout {
|
||||
margin-top: 0.25rem !important;
|
||||
margin-bottom: 0.25rem !important;
|
||||
margin-left: 0 !important;
|
||||
margin-right: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0.5rem 0;
|
||||
outline: none;
|
||||
color: var(--color-button-text);
|
||||
background-color: var(--color-button-bg);
|
||||
border: none;
|
||||
border-radius: var(--size-rounded-control);
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
background-color: var(--color-button-bg-hover);
|
||||
color: var(--color-button-text-hover);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--color-button-bg-active);
|
||||
color: var(--color-button-text-active);
|
||||
}
|
||||
}
|
||||
|
||||
// @import "vue-select/src/scss/vue-select.scss";
|
||||
|
||||
|
||||
@import "~assets/styles/highlightjs.scss";
|
||||
@import "~assets/styles/layout.scss";
|
||||
@import "~assets/styles/utils.scss";
|
||||
|
||||
87
assets/styles/injected.scss
Normal file
@@ -0,0 +1,87 @@
|
||||
%card {
|
||||
background: var(--color-raised-bg);
|
||||
border-radius: var(--size-rounded-card);
|
||||
}
|
||||
|
||||
%card-spaced-b {
|
||||
@extend %card;
|
||||
margin-bottom: var(--spacing-card-md);
|
||||
}
|
||||
|
||||
%row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
%column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
%transparent-clickable {
|
||||
border-radius: var(--size-rounded-control);
|
||||
color: var(--color-text);
|
||||
background-color: transparent;
|
||||
&:focus,
|
||||
&:hover,
|
||||
&.selected,
|
||||
&.nuxt-link-exact-active {
|
||||
color: var(--color-transparent-button-text-hover);
|
||||
background-color: var(--color-transparent-button-bg-hover);
|
||||
}
|
||||
&:active {
|
||||
color: var(--color-transparent-button-text-active);
|
||||
background-color: var(--color-transparent-button-bg-active);
|
||||
}
|
||||
}
|
||||
|
||||
%label {
|
||||
color: var(--color-text);
|
||||
font-weight: var(--font-weight-extrabold);
|
||||
letter-spacing: 0.02rem;
|
||||
margin: 0;
|
||||
margin-bottom: 0.25em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
%small-label {
|
||||
@extend %label;
|
||||
color: var(--color-text);
|
||||
font-size: var(--font-size-xs);
|
||||
letter-spacing: 0.02rem;
|
||||
}
|
||||
|
||||
%large-label {
|
||||
@extend %label;
|
||||
color: var(--color-text);
|
||||
font-size: var(--font-size-sm);
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
%stat {
|
||||
margin-top: 0.5rem;
|
||||
margin-right: 1rem;
|
||||
@extend %row;
|
||||
|
||||
@media screen and (min-width: 900px) {
|
||||
margin-top: 0;
|
||||
}
|
||||
svg {
|
||||
margin: auto 0.5rem auto 0;
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
color: var(--color-icon);
|
||||
}
|
||||
.info {
|
||||
margin: auto 0;
|
||||
white-space: nowrap;
|
||||
h4 {
|
||||
@extend %small-label;
|
||||
}
|
||||
.value {
|
||||
font-size: var(--font-size-sm);
|
||||
margin: 0;
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
.rows {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-direction: column;
|
||||
|
||||
@for $i from 1 through 4 {
|
||||
.row-grow-#{$i} {
|
||||
@@ -18,7 +18,20 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.w-100 {
|
||||
width: 100%;
|
||||
}
|
||||
.page-container {
|
||||
margin: var(--spacing-card-lg);
|
||||
.page-contents {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.content {
|
||||
width: 100%;
|
||||
}
|
||||
@media screen and (min-width: 900px) {
|
||||
}
|
||||
@media screen and (min-width: 1024px) {
|
||||
max-width: 1280px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
.rounded-md {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.w-100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
132
components/Categories.vue
Normal file
@@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<div class="categories">
|
||||
<p v-if="categories.includes('fabric')">
|
||||
<FabricLoader />
|
||||
Fabric
|
||||
</p>
|
||||
<p v-if="categories.includes('forge')">
|
||||
<ForgeLoader />
|
||||
Forge
|
||||
</p>
|
||||
<p v-if="categories.includes('technology')">
|
||||
<TechCategory />
|
||||
Technology
|
||||
</p>
|
||||
<p v-if="categories.includes('adventure')">
|
||||
<AdventureCategory />
|
||||
Adventure
|
||||
</p>
|
||||
<p v-if="categories.includes('magic')">
|
||||
<MagicCategory />
|
||||
Magic
|
||||
</p>
|
||||
<p v-if="categories.includes('utility')">
|
||||
<UtilityCategory />
|
||||
Utility
|
||||
</p>
|
||||
<p v-if="categories.includes('decoration')">
|
||||
<DecorationCategory />
|
||||
Decoration
|
||||
</p>
|
||||
<p v-if="categories.includes('library')">
|
||||
<LibraryCategory />
|
||||
Library
|
||||
</p>
|
||||
<p v-if="categories.includes('cursed')">
|
||||
<CursedCategory />
|
||||
Cursed
|
||||
</p>
|
||||
<p v-if="categories.includes('worldgen')">
|
||||
<WorldGenCategory />
|
||||
Worldgen
|
||||
</p>
|
||||
<p v-if="categories.includes('storage')">
|
||||
<StorageCategory />
|
||||
Storage
|
||||
</p>
|
||||
<p v-if="categories.includes('food')">
|
||||
<FoodCategory />
|
||||
Food
|
||||
</p>
|
||||
<p v-if="categories.includes('equipment')">
|
||||
<EquipmentCategory />
|
||||
Equipment
|
||||
</p>
|
||||
<p v-if="categories.includes('misc')">
|
||||
<MiscCategory />
|
||||
Misc
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import TechCategory from '~/assets/images/categories/tech.svg?inline'
|
||||
import AdventureCategory from '~/assets/images/categories/adventure.svg?inline'
|
||||
import CursedCategory from '~/assets/images/categories/cursed.svg?inline'
|
||||
import DecorationCategory from '~/assets/images/categories/decoration.svg?inline'
|
||||
import EquipmentCategory from '~/assets/images/categories/equipment.svg?inline'
|
||||
import FoodCategory from '~/assets/images/categories/food.svg?inline'
|
||||
import LibraryCategory from '~/assets/images/categories/library.svg?inline'
|
||||
import MagicCategory from '~/assets/images/categories/magic.svg?inline'
|
||||
import MiscCategory from '~/assets/images/categories/misc.svg?inline'
|
||||
import StorageCategory from '~/assets/images/categories/storage.svg?inline'
|
||||
import UtilityCategory from '~/assets/images/categories/utility.svg?inline'
|
||||
import WorldGenCategory from '~/assets/images/categories/worldgen.svg?inline'
|
||||
|
||||
import ForgeLoader from '~/assets/images/categories/forge.svg?inline'
|
||||
import FabricLoader from '~/assets/images/categories/fabric.svg?inline'
|
||||
|
||||
export default {
|
||||
name: 'Categories',
|
||||
components: {
|
||||
TechCategory,
|
||||
AdventureCategory,
|
||||
CursedCategory,
|
||||
DecorationCategory,
|
||||
EquipmentCategory,
|
||||
FoodCategory,
|
||||
LibraryCategory,
|
||||
MagicCategory,
|
||||
MiscCategory,
|
||||
StorageCategory,
|
||||
UtilityCategory,
|
||||
WorldGenCategory,
|
||||
ForgeLoader,
|
||||
FabricLoader,
|
||||
},
|
||||
props: {
|
||||
categories: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.categories {
|
||||
@extend %row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
p {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
background-color: var(--color-category-bg);
|
||||
border-radius: var(--size-rounded-max);
|
||||
color: var(--color-category-text);
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
margin-right: 0.5em;
|
||||
padding: 0.4em 0.7em;
|
||||
font-size: var(--font-size-sm);
|
||||
height: 1em;
|
||||
svg {
|
||||
width: 15px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,86 +1,53 @@
|
||||
<template>
|
||||
<div>
|
||||
<slot></slot>
|
||||
<label class="button">
|
||||
<span>
|
||||
{{ prompt }}
|
||||
</span>
|
||||
<input
|
||||
:id="inputId"
|
||||
class="file-input"
|
||||
type="file"
|
||||
:accept="inputAccept"
|
||||
:multiple="inputMultiple"
|
||||
@change="onChange"
|
||||
:multiple="multiple"
|
||||
:accept="accept"
|
||||
@change="(files) => $emit('change', files)"
|
||||
/>
|
||||
<label :for="inputId">{{ text }}</label>
|
||||
</div>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'FileInput',
|
||||
props: {
|
||||
defaultText: {
|
||||
prompt: {
|
||||
type: String,
|
||||
default: '',
|
||||
default: 'Select file',
|
||||
},
|
||||
inputId: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
inputAccept: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
inputMultiple: {
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
text: this.defaultText,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onChange(files) {
|
||||
const length = files.target.files.length
|
||||
|
||||
if (length === 0) {
|
||||
this.text = this.defaultText
|
||||
} else if (length === 1) {
|
||||
this.text = '1 file selected'
|
||||
} else if (length > 1) {
|
||||
this.text = length + ' files selected'
|
||||
}
|
||||
|
||||
this.$emit('change', files)
|
||||
accept: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
[type='file'] {
|
||||
border: 0;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute !important;
|
||||
white-space: nowrap;
|
||||
width: 1px;
|
||||
label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
padding: var(--spacing-card-sm) var(--spacing-card-md);
|
||||
}
|
||||
|
||||
+ label {
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
color: var(--color-grey-5);
|
||||
background-color: var(--color-grey-1);
|
||||
padding: 10px 20px;
|
||||
}
|
||||
span {
|
||||
border: 2px dashed var(--color-divider-dark);
|
||||
border-radius: var(--size-rounded-control);
|
||||
padding: var(--spacing-card-md) var(--spacing-card-lg);
|
||||
}
|
||||
|
||||
&:focus + label,
|
||||
+ label:hover,
|
||||
&:focus + label {
|
||||
background-color: var(--color-grey-2);
|
||||
color: var(--color-text);
|
||||
}
|
||||
input {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
79
components/MFooter.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<footer :class="{ centered }">
|
||||
<span>
|
||||
Modrinth is open source software. You may view the source code at
|
||||
<a target="_blank" href="https://github.com/modrinth">our GitHub page</a>.
|
||||
</span>
|
||||
<ul>
|
||||
<li>
|
||||
<nuxt-link to="/legal/terms">Terms</nuxt-link>
|
||||
</li>
|
||||
<li>
|
||||
<nuxt-link to="/legal/privacy">Privacy</nuxt-link>
|
||||
</li>
|
||||
<li>
|
||||
<nuxt-link to="/about">About</nuxt-link>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li>
|
||||
<a target="_blank" href="https://blog.modrinth.com">Blog</a>
|
||||
</li>
|
||||
<li>
|
||||
<a target="_blank" href="https://discord.gg/gFRbNQ2">Discord</a>
|
||||
</li>
|
||||
<li>
|
||||
<a target="_blank" href="https://twitter.com/modrinth">Twitter</a>
|
||||
</li>
|
||||
</ul>
|
||||
<span> © Guavy LLC </span>
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
centered: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.centered {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding: 2rem 0 5rem 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
li {
|
||||
margin-bottom: var(--spacing-card-sm);
|
||||
&:not(:last-child)::after {
|
||||
content: '•';
|
||||
padding: 0;
|
||||
margin: 0 var(--spacing-card-sm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > *:not(:last-child) {
|
||||
margin-bottom: var(--spacing-card-sm);
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
@@ -1,71 +1,134 @@
|
||||
<template>
|
||||
<div class="columns">
|
||||
<div class="content column-grow-5">
|
||||
<div class="mod-header columns">
|
||||
<img
|
||||
:src="
|
||||
mod.icon_url
|
||||
? mod.icon_url
|
||||
: 'https://cdn.modrinth.com/placeholder.svg'
|
||||
"
|
||||
alt="mod-icon"
|
||||
/>
|
||||
<div class="mod-header-text">
|
||||
<div class="columns title">
|
||||
<h2>{{ mod.title }}</h2>
|
||||
<nuxt-link
|
||||
:to="'/user/' + members.find((x) => x.role === 'Owner').user_id"
|
||||
>
|
||||
<p>by {{ members.find((x) => x.role === 'Owner').name }}</p>
|
||||
</nuxt-link>
|
||||
<div class="page-container">
|
||||
<div class="page-contents">
|
||||
<div class="content">
|
||||
<div class="header">
|
||||
<div class="icon">
|
||||
<img
|
||||
:src="
|
||||
mod.icon_url
|
||||
? mod.icon_url
|
||||
: 'https://cdn.modrinth.com/placeholder.svg'
|
||||
"
|
||||
alt="mod - icon"
|
||||
/>
|
||||
</div>
|
||||
<p>{{ mod.description }}</p>
|
||||
<div class="info">
|
||||
<h2 class="title">{{ mod.title }}</h2>
|
||||
<p class="description">
|
||||
{{ mod.description }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<client-only>
|
||||
<EthicalAd type="text" />
|
||||
</client-only>
|
||||
<div class="mod-navigation">
|
||||
<div class="tabs">
|
||||
<nuxt-link :to="'/mod/' + mod.id" class="tab">
|
||||
Description
|
||||
</nuxt-link>
|
||||
<nuxt-link :to="'/mod/' + mod.id + '/versions'" class="tab">
|
||||
Versions
|
||||
</nuxt-link>
|
||||
<a v-if="mod.wiki_url" :href="mod.wiki_url" class="tab">
|
||||
<ExternalIcon />
|
||||
Wiki
|
||||
</a>
|
||||
<a
|
||||
v-if="mod.issues_url"
|
||||
:href="mod.issues_url"
|
||||
target="_blank"
|
||||
class="tab"
|
||||
>
|
||||
<ExternalIcon />
|
||||
Issues
|
||||
</a>
|
||||
<a
|
||||
v-if="mod.source_url"
|
||||
:href="mod.source_url"
|
||||
target="_blank"
|
||||
class="tab"
|
||||
>
|
||||
<ExternalIcon />
|
||||
Source
|
||||
</a>
|
||||
<nuxt-link
|
||||
v-if="
|
||||
this.$auth.loggedIn &&
|
||||
members.find((x) => x.user_id === this.$auth.user.id)
|
||||
"
|
||||
:to="'/mod/' + mod.id + '/settings'"
|
||||
class="tab"
|
||||
>
|
||||
Settings
|
||||
</nuxt-link>
|
||||
<div class="filler" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mod-content">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
<div class="mod-navigation">
|
||||
<nuxt-link :to="'/mod/' + mod.id">
|
||||
<InfoIcon />
|
||||
Description
|
||||
</nuxt-link>
|
||||
<nuxt-link :to="'/mod/' + mod.id + '/versions'">
|
||||
<VersionIcon />
|
||||
Versions
|
||||
</nuxt-link>
|
||||
<nuxt-link
|
||||
v-if="
|
||||
this.$auth.loggedIn &&
|
||||
members.find((x) => x.user_id === this.$auth.user.id)
|
||||
"
|
||||
:to="'/mod/' + mod.id + '/settings'"
|
||||
>
|
||||
<SettingsIcon />
|
||||
Settings
|
||||
</nuxt-link>
|
||||
<a v-if="mod.wiki_url" :href="mod.wiki_url">
|
||||
<ExternalIcon />
|
||||
Wiki
|
||||
</a>
|
||||
<a v-if="mod.issues_url" :href="mod.issues_url">
|
||||
<ExternalIcon />
|
||||
Issues
|
||||
</a>
|
||||
<a v-if="mod.source_url" :href="mod.source_url">
|
||||
<ExternalIcon />
|
||||
Source Code
|
||||
</a>
|
||||
<div class="filler" />
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
<div>
|
||||
<section class="mod-info">
|
||||
<div class="mod-stats">
|
||||
<h3>Info</h3>
|
||||
<p>{{ mod.downloads }} Downloads</p>
|
||||
<p>Created {{ $dayjs(mod.published).fromNow() }}</p>
|
||||
<p>Updated {{ $dayjs(mod.updated).fromNow() }}</p>
|
||||
<div class="mod-stats section">
|
||||
<div class="stat">
|
||||
<DownloadIcon />
|
||||
<div class="info">
|
||||
<h4>Downloads</h4>
|
||||
<p class="value">{{ formatNumber(mod.downloads) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<CalendarIcon />
|
||||
<div class="info">
|
||||
<h4>Created</h4>
|
||||
<p
|
||||
v-tooltip="
|
||||
$dayjs(mod.published).format(
|
||||
'[Created on] YYYY-MM-DD [at] HH:mm A'
|
||||
)
|
||||
"
|
||||
class="value"
|
||||
>
|
||||
{{ $dayjs(mod.published).fromNow() }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<TagIcon />
|
||||
<div class="info">
|
||||
<h4>Available For</h4>
|
||||
<p class="value">
|
||||
{{
|
||||
versions[versions.length - 1]
|
||||
? versions[versions.length - 1].game_versions[0]
|
||||
? versions[versions.length - 1].game_versions[0]
|
||||
: 'None'
|
||||
: 'None'
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<EditIcon />
|
||||
<div class="info">
|
||||
<h4>Updated</h4>
|
||||
<p
|
||||
v-tooltip="
|
||||
$dayjs(mod.updated).format(
|
||||
'[Updated on] YYYY-MM-DD [at] HH:mm A'
|
||||
)
|
||||
"
|
||||
class="value"
|
||||
>
|
||||
{{ $dayjs(mod.updated).fromNow() }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Categories :categories="mod.categories.concat(mod.loaders)" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="section">
|
||||
<h3>Members</h3>
|
||||
<div
|
||||
v-for="member in members"
|
||||
@@ -77,63 +140,75 @@
|
||||
<nuxt-link :to="'/user/' + member.user_id">
|
||||
<h4>{{ member.name }}</h4>
|
||||
</nuxt-link>
|
||||
<p>{{ member.role }}</p>
|
||||
<h3>{{ member.role }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="versions.length > 0">
|
||||
<div v-if="versions.length > 0" class="section">
|
||||
<h3>Featured Versions</h3>
|
||||
<div
|
||||
v-for="version in versions"
|
||||
:key="version.id"
|
||||
class="featured-version columns"
|
||||
class="featured-version"
|
||||
>
|
||||
<div class="version-info">
|
||||
<div class="columns">
|
||||
<h4 class="limit-text-width">
|
||||
{{ version.name }}
|
||||
</h4>
|
||||
<p
|
||||
<a
|
||||
:href="findPrimary(version).url"
|
||||
class="download"
|
||||
@click.prevent="
|
||||
downloadFile(
|
||||
findPrimary(version).hashes.sha1,
|
||||
findPrimary(version).url
|
||||
)
|
||||
"
|
||||
>
|
||||
<DownloadIcon />
|
||||
</a>
|
||||
<div class="info">
|
||||
<div class="top">
|
||||
<span
|
||||
v-if="version.version_type === 'release'"
|
||||
class="badge green"
|
||||
>
|
||||
Release
|
||||
</p>
|
||||
<p v-if="version.version_type === 'beta'" class="badge yellow">
|
||||
</span>
|
||||
<span
|
||||
v-if="version.version_type === 'beta'"
|
||||
class="badge yellow"
|
||||
>
|
||||
Beta
|
||||
</p>
|
||||
<p v-if="version.version_type === 'alpha'" class="badge red">
|
||||
</span>
|
||||
<span v-if="version.version_type === 'alpha'" class="badge red">
|
||||
Alpha
|
||||
</p>
|
||||
</span>
|
||||
<h4 class="title">
|
||||
<nuxt-link :to="'/mod/' + mod.id + '/version/' + version.id">
|
||||
{{ version.name }}
|
||||
</nuxt-link>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="columns info-2">
|
||||
<p class="version-number limit-text-width">
|
||||
{{ version.version_number }}
|
||||
</p>
|
||||
<div class="bottom">
|
||||
<span class="version-number limit-text-width">
|
||||
{{ version.version_number }} ·
|
||||
</span>
|
||||
<FabricIcon
|
||||
v-if="version.loaders.includes('fabric')"
|
||||
stroke="#AC6C3A"
|
||||
class="loader"
|
||||
/>
|
||||
<ForgeIcon
|
||||
v-if="version.loaders.includes('forge')"
|
||||
stroke="#8B81E6"
|
||||
class="loader"
|
||||
/>
|
||||
<p
|
||||
<span
|
||||
v-if="version.game_versions.length > 0"
|
||||
class="game-version limit-text-width"
|
||||
>
|
||||
{{ version.game_versions[0] }}
|
||||
</p>
|
||||
· {{ version.game_versions[0] }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<nuxt-link :to="'/mod/' + mod.id + '/version/' + version.id">
|
||||
<DownloadIcon />
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<client-only>
|
||||
<EthicalAd type="image" />
|
||||
</client-only>
|
||||
</div>
|
||||
<m-footer class="footer" />
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
@@ -142,11 +217,16 @@
|
||||
<script>
|
||||
import EthicalAd from '@/components/EthicalAd'
|
||||
|
||||
import Categories from '@/components/Categories'
|
||||
import MFooter from '@/components/MFooter'
|
||||
|
||||
import axios from 'axios'
|
||||
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
||||
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
||||
import EditIcon from '~/assets/images/utils/edit.svg?inline'
|
||||
import TagIcon from '~/assets/images/utils/tag.svg?inline'
|
||||
|
||||
import ExternalIcon from '~/assets/images/utils/external.svg?inline'
|
||||
import InfoIcon from '~/assets/images/utils/info.svg?inline'
|
||||
import VersionIcon from '~/assets/images/utils/version.svg?inline'
|
||||
import SettingsIcon from '~/assets/images/utils/settings.svg?inline'
|
||||
|
||||
import ForgeIcon from '~/assets/images/categories/forge.svg?inline'
|
||||
import FabricIcon from '~/assets/images/categories/fabric.svg?inline'
|
||||
@@ -154,14 +234,16 @@ import FabricIcon from '~/assets/images/categories/fabric.svg?inline'
|
||||
export default {
|
||||
name: 'ModPage',
|
||||
components: {
|
||||
MFooter,
|
||||
Categories,
|
||||
EthicalAd,
|
||||
ExternalIcon,
|
||||
InfoIcon,
|
||||
VersionIcon,
|
||||
SettingsIcon,
|
||||
ForgeIcon,
|
||||
FabricIcon,
|
||||
DownloadIcon,
|
||||
CalendarIcon,
|
||||
EditIcon,
|
||||
TagIcon,
|
||||
},
|
||||
props: {
|
||||
mod: {
|
||||
@@ -183,190 +265,168 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatNumber(x) {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
},
|
||||
findPrimary(version) {
|
||||
let file = version.files.find((x) => x.primary)
|
||||
|
||||
if (!file) {
|
||||
file = version.files[0]
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
file = { url: `/mod/${this.mod.id}/version/${version.id}` }
|
||||
}
|
||||
|
||||
return file
|
||||
},
|
||||
async downloadFile(hash, url) {
|
||||
await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version_file/${hash}/download`
|
||||
)
|
||||
|
||||
const elem = document.createElement('a')
|
||||
elem.download = hash
|
||||
elem.href = url
|
||||
elem.click()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.mod-header {
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
border-radius: var(--size-rounded-md);
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
<style lang="scss" scoped>
|
||||
.header {
|
||||
@extend %row;
|
||||
@extend %card-spaced-b;
|
||||
width: 100%;
|
||||
.icon {
|
||||
margin: auto 0;
|
||||
img {
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
margin: var(--spacing-card-md);
|
||||
border-radius: var(--size-rounded-icon);
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.mod-header-text {
|
||||
margin-left: 15px;
|
||||
|
||||
.info {
|
||||
@extend %column;
|
||||
.title {
|
||||
align-items: end;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
align-self: flex-end;
|
||||
margin: 0;
|
||||
padding: 0 0 2px 5px;
|
||||
}
|
||||
margin: var(--spacing-card-md) var(--spacing-card-md) 0 0;
|
||||
color: var(--color-text-dark);
|
||||
font-size: var(--font-size-lg);
|
||||
}
|
||||
.description {
|
||||
margin: var(--spacing-card-sm) var(--spacing-card-md) 0 0;
|
||||
height: 100%;
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mod-navigation {
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
|
||||
a {
|
||||
user-select: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 20px;
|
||||
border-bottom: 2px solid var(--color-grey-2);
|
||||
|
||||
svg {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
border-bottom: 2px solid var(--color-grey-3);
|
||||
}
|
||||
|
||||
&.nuxt-link-exact-active {
|
||||
border-bottom: 2px solid var(--color-brand);
|
||||
}
|
||||
}
|
||||
|
||||
.filler {
|
||||
flex-grow: 1;
|
||||
border-bottom: 2px solid var(--color-grey-2);
|
||||
}
|
||||
@extend %card-spaced-b;
|
||||
padding-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.mod-info {
|
||||
top: 1rem;
|
||||
position: sticky;
|
||||
min-width: 270px;
|
||||
max-width: 270px;
|
||||
margin: 1rem;
|
||||
padding: 0 0.75rem 0 1rem;
|
||||
overflow-y: auto;
|
||||
background-color: var(--color-bg);
|
||||
border: 1px solid var(--color-grey-2);
|
||||
border-radius: var(--size-rounded-sm);
|
||||
width: 30rem;
|
||||
height: auto;
|
||||
margin-left: var(--spacing-card-lg);
|
||||
|
||||
.section {
|
||||
padding: var(--spacing-card-sm);
|
||||
@extend %card-spaced-b;
|
||||
margin-top: var(--spacing-card-lg);
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #718096;
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.02rem;
|
||||
margin: 1.5rem 0 0.5rem 0;
|
||||
text-transform: uppercase;
|
||||
@extend %large-label;
|
||||
}
|
||||
|
||||
.mod-stats {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0;
|
||||
margin-left: 5px;
|
||||
p {
|
||||
color: var(--color-grey-4);
|
||||
margin: 3px;
|
||||
}
|
||||
.stat {
|
||||
width: 8.5rem;
|
||||
margin: 0.75rem;
|
||||
@extend %stat;
|
||||
|
||||
svg {
|
||||
padding: 0.25rem;
|
||||
border-radius: 50%;
|
||||
background-color: var(--color-button-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.team-member {
|
||||
margin-left: 5px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid var(--color-grey-1);
|
||||
border-radius: var(--size-rounded-sm);
|
||||
|
||||
img {
|
||||
border-radius: var(--size-rounded-sm);
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-radius: var(--size-rounded-icon);
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
.member-info {
|
||||
max-width: 150px;
|
||||
overflow: hidden;
|
||||
margin: auto 0 auto 20px;
|
||||
margin: auto 0 auto 0.5rem;
|
||||
h4 {
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
}
|
||||
p {
|
||||
color: var(--color-grey-4);
|
||||
font-weight: lighter;
|
||||
font-size: 12pt;
|
||||
margin: 0;
|
||||
h3 {
|
||||
margin-top: 0.1rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.featured-version {
|
||||
margin-left: 5px;
|
||||
margin-bottom: 10px;
|
||||
border: 1px solid var(--color-grey-1);
|
||||
border-radius: var(--size-rounded-sm);
|
||||
|
||||
.version-info {
|
||||
padding: 5px 10px;
|
||||
h4 {
|
||||
max-width: 120px;
|
||||
font-weight: normal;
|
||||
margin: 0 10px 0 0;
|
||||
}
|
||||
.badge {
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
.info-2 {
|
||||
overflow: hidden;
|
||||
max-width: 180px;
|
||||
align-items: center;
|
||||
|
||||
.version-number {
|
||||
max-width: 80px;
|
||||
}
|
||||
|
||||
.game-version {
|
||||
max-width: 120px;
|
||||
}
|
||||
|
||||
p {
|
||||
color: var(--color-grey-4);
|
||||
font-weight: lighter;
|
||||
margin: 0 10px 0 0;
|
||||
}
|
||||
|
||||
svg {
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
@extend %row;
|
||||
padding-top: var(--spacing-card-sm);
|
||||
padding-bottom: var(--spacing-card-sm);
|
||||
.download {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 2.25rem;
|
||||
width: 2.25rem;
|
||||
border-radius: 2rem;
|
||||
background-color: var(--color-button-bg);
|
||||
margin-right: var(--spacing-card-sm);
|
||||
svg {
|
||||
width: 1.25rem;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
display: table-cell;
|
||||
margin-left: auto;
|
||||
width: 40px;
|
||||
height: 60px;
|
||||
background-color: var(--color-grey-1);
|
||||
color: var(--color-grey-3);
|
||||
|
||||
svg {
|
||||
margin-top: 15px;
|
||||
height: 30px;
|
||||
width: 40px;
|
||||
.info {
|
||||
@extend %column;
|
||||
font-size: var(--font-size-xs);
|
||||
.top {
|
||||
@extend %row;
|
||||
.badge {
|
||||
font-size: var(--font-size-xs);
|
||||
margin-right: var(--spacing-card-sm);
|
||||
}
|
||||
.title {
|
||||
margin: auto 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--color-grey-3);
|
||||
color: var(--color-grey-4);
|
||||
.bottom {
|
||||
margin-top: 0.25rem;
|
||||
@extend %row;
|
||||
.loader {
|
||||
height: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,464 +0,0 @@
|
||||
<template>
|
||||
<div class="result rows">
|
||||
<img
|
||||
class="result-icon"
|
||||
:src="iconUrl ? iconUrl : 'https://cdn.modrinth.com/placeholder.svg'"
|
||||
:alt="name"
|
||||
/>
|
||||
<div class="rows result-name-author">
|
||||
<h2 class="mod-name">
|
||||
<a :href="pageUrl">{{ name }}</a>
|
||||
</h2>
|
||||
<p v-if="author" class="author">
|
||||
by <a :href="authorUrl">{{ author }}</a>
|
||||
</p>
|
||||
</div>
|
||||
<p class="result-summary">
|
||||
{{ description }}
|
||||
</p>
|
||||
<div class="column-grow-1 columns result-infos">
|
||||
<div class="result-image columns">
|
||||
<DownloadIcon stroke="#3cdb36" />
|
||||
<p>{{ formatNumber(downloads) }}</p>
|
||||
</div>
|
||||
<div
|
||||
v-tooltip="
|
||||
$dayjs(createdAt).format('[Created on] YYYY-MM-DD [at] HH:mm A')
|
||||
"
|
||||
class="result-image columns"
|
||||
>
|
||||
<CalendarIcon fill="#099fef" />
|
||||
<p>{{ $dayjs(createdAt).fromNow() }}</p>
|
||||
</div>
|
||||
<div
|
||||
v-if="updatedAt"
|
||||
v-tooltip="
|
||||
$dayjs(updatedAt).format('[Updated on] YYYY-MM-DD [at] HH:mm A')
|
||||
"
|
||||
class="result-image columns"
|
||||
>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#e88d0d"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
|
||||
></path>
|
||||
<path
|
||||
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
|
||||
></path>
|
||||
</svg>
|
||||
<p>{{ $dayjs(updatedAt).fromNow() }}</p>
|
||||
</div>
|
||||
<div class="result-image columns">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="#e8200d"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"
|
||||
></path>
|
||||
<line x1="7" y1="7" x2="7.01" y2="7"></line>
|
||||
</svg>
|
||||
<p>{{ latestVersion }}</p>
|
||||
</div>
|
||||
|
||||
<div class="loaders columns">
|
||||
<FabricLoader v-if="categories.includes('fabric')" stroke="#AC6C3A" />
|
||||
<ForgeLoader v-if="categories.includes('forge')" stroke="#8B81E6" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="categories">
|
||||
<p v-if="categories.includes('technology')">
|
||||
<TechCategory />
|
||||
Technology
|
||||
</p>
|
||||
<p v-if="categories.includes('adventure')">
|
||||
<AdventureCategory />
|
||||
Adventure
|
||||
</p>
|
||||
<p v-if="categories.includes('magic')">
|
||||
<MagicCategory />
|
||||
Magic
|
||||
</p>
|
||||
<p v-if="categories.includes('utility')">
|
||||
<UtilityCategory />
|
||||
Utility
|
||||
</p>
|
||||
<p v-if="categories.includes('decoration')">
|
||||
<DecorationCategory />
|
||||
Decoration
|
||||
</p>
|
||||
<p v-if="categories.includes('library')">
|
||||
<LibraryCategory />
|
||||
Library
|
||||
</p>
|
||||
<p v-if="categories.includes('cursed')">
|
||||
<CursedCategory />
|
||||
Cursed
|
||||
</p>
|
||||
<p v-if="categories.includes('worldgen')">
|
||||
<WorldGenCategory />
|
||||
Worldgen
|
||||
</p>
|
||||
<p v-if="categories.includes('storage')">
|
||||
<StorageCategory />
|
||||
Storage
|
||||
</p>
|
||||
<p v-if="categories.includes('food')">
|
||||
<FoodCategory />
|
||||
Food
|
||||
</p>
|
||||
<p v-if="categories.includes('equipment')">
|
||||
<EquipmentCategory />
|
||||
Equipment
|
||||
</p>
|
||||
<p v-if="categories.includes('misc')">
|
||||
<MiscCategory />
|
||||
Misc
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
||||
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
||||
|
||||
import TechCategory from '~/assets/images/categories/tech.svg?inline'
|
||||
import AdventureCategory from '~/assets/images/categories/adventure.svg?inline'
|
||||
import CursedCategory from '~/assets/images/categories/cursed.svg?inline'
|
||||
import DecorationCategory from '~/assets/images/categories/decoration.svg?inline'
|
||||
import EquipmentCategory from '~/assets/images/categories/equipment.svg?inline'
|
||||
import FoodCategory from '~/assets/images/categories/food.svg?inline'
|
||||
import LibraryCategory from '~/assets/images/categories/library.svg?inline'
|
||||
import MagicCategory from '~/assets/images/categories/magic.svg?inline'
|
||||
import MiscCategory from '~/assets/images/categories/misc.svg?inline'
|
||||
import StorageCategory from '~/assets/images/categories/storage.svg?inline'
|
||||
import UtilityCategory from '~/assets/images/categories/utility.svg?inline'
|
||||
import WorldGenCategory from '~/assets/images/categories/worldgen.svg?inline'
|
||||
|
||||
import ForgeLoader from '~/assets/images/categories/forge.svg?inline'
|
||||
import FabricLoader from '~/assets/images/categories/fabric.svg?inline'
|
||||
|
||||
export default {
|
||||
name: 'ModResult',
|
||||
components: {
|
||||
TechCategory,
|
||||
AdventureCategory,
|
||||
CursedCategory,
|
||||
DecorationCategory,
|
||||
EquipmentCategory,
|
||||
FoodCategory,
|
||||
LibraryCategory,
|
||||
MagicCategory,
|
||||
MiscCategory,
|
||||
StorageCategory,
|
||||
UtilityCategory,
|
||||
WorldGenCategory,
|
||||
ForgeLoader,
|
||||
FabricLoader,
|
||||
CalendarIcon,
|
||||
DownloadIcon,
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: 'modrinth-0',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: 'Mod Name',
|
||||
},
|
||||
author: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: 'A mod description',
|
||||
},
|
||||
pageUrl: {
|
||||
type: String,
|
||||
default: '#',
|
||||
},
|
||||
authorUrl: {
|
||||
type: String,
|
||||
default: '#',
|
||||
},
|
||||
iconUrl: {
|
||||
type: String,
|
||||
default: '#',
|
||||
},
|
||||
downloads: {
|
||||
type: String,
|
||||
default: '0',
|
||||
},
|
||||
createdAt: {
|
||||
type: String,
|
||||
default: '0000-00-00',
|
||||
},
|
||||
updatedAt: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
latestVersion: {
|
||||
type: String,
|
||||
default: 'None',
|
||||
},
|
||||
categories: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatNumber(x) {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.results {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.result {
|
||||
display: grid;
|
||||
grid-template-columns: 80px auto;
|
||||
grid-template-rows: auto auto auto 30px;
|
||||
max-width: 100vw;
|
||||
margin-bottom: 10px;
|
||||
background: var(--color-bg);
|
||||
box-shadow: 0 2px 3px 1px var(--color-grey-2);
|
||||
|
||||
// Columns are larger to accomodate larger screens
|
||||
@media screen and (min-width: 1375px) {
|
||||
grid-template-columns: 120px auto;
|
||||
}
|
||||
}
|
||||
|
||||
.result * {
|
||||
object-fit: contain;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.result-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin: 5px !important;
|
||||
border-radius: 0.5rem;
|
||||
grid-row-start: 1;
|
||||
grid-row-end: 4;
|
||||
grid-column-start: 1;
|
||||
|
||||
@media screen and (min-width: 900px) {
|
||||
margin: 10px 20px 10px 10px !important;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
}
|
||||
|
||||
// Larger screen, larger icon
|
||||
@media screen and (min-width: 1375px) {
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
}
|
||||
|
||||
.result-name-author {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
min-height: 38px;
|
||||
}
|
||||
|
||||
.result-summary {
|
||||
grid-row: 2;
|
||||
grid-column: 2;
|
||||
max-height: 150px;
|
||||
font-size: 11pt;
|
||||
margin: auto 0;
|
||||
}
|
||||
|
||||
.mod-name {
|
||||
align-self: flex-end;
|
||||
font-size: 13pt;
|
||||
}
|
||||
|
||||
.author {
|
||||
margin-bottom: 2px !important;
|
||||
align-self: flex-end;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
.result-infos {
|
||||
display: grid;
|
||||
grid-template-columns: 115px 115px auto;
|
||||
grid-template-rows: 20px 20px;
|
||||
margin-top: 5px;
|
||||
grid-column: 2;
|
||||
align-items: flex-start;
|
||||
align-self: flex-start;
|
||||
|
||||
.columns:nth-child(2) {
|
||||
grid-column: 1;
|
||||
}
|
||||
|
||||
.columns:nth-child(3) {
|
||||
grid-column: 2;
|
||||
grid-row: 1;
|
||||
}
|
||||
|
||||
.result-image {
|
||||
p {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.result-image svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.result-image p {
|
||||
margin-left: 5px;
|
||||
margin-right: 15px;
|
||||
font-size: 15px;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.categories {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
grid-column: 1;
|
||||
margin: 0 0 auto;
|
||||
}
|
||||
|
||||
.categories p {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
background-color: var(--color-grey-1);
|
||||
color: var(--color-text);
|
||||
margin: 0 5px;
|
||||
padding: 2px;
|
||||
font-size: 15px;
|
||||
|
||||
svg {
|
||||
width: 15px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.loaders {
|
||||
align-items: center;
|
||||
grid-column: 1;
|
||||
grid-row: 3;
|
||||
img {
|
||||
width: 15px;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 20px;
|
||||
margin-top: 2px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
// Larger tablet-sized screens
|
||||
@media screen and (min-width: 900px) {
|
||||
.result {
|
||||
grid-template-columns: 90px auto;
|
||||
grid-template-rows: auto auto 35px;
|
||||
}
|
||||
|
||||
.result-infos {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 0;
|
||||
.result-image {
|
||||
p {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loaders {
|
||||
svg {
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.categories {
|
||||
margin: 0 0 10px 0;
|
||||
}
|
||||
|
||||
.result-name-author {
|
||||
display: flex;
|
||||
margin-top: 0;
|
||||
.author {
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.mod-name {
|
||||
font-size: 18pt;
|
||||
}
|
||||
|
||||
.result-summary {
|
||||
max-height: 100px;
|
||||
font-size: 13pt;
|
||||
}
|
||||
}
|
||||
|
||||
// Larger screens
|
||||
@media screen and (min-width: 1375px) {
|
||||
.result {
|
||||
margin: 5px 0;
|
||||
grid-column: 1;
|
||||
grid-template-columns: 110px auto;
|
||||
}
|
||||
|
||||
.categories {
|
||||
margin: 0 5px 10px auto;
|
||||
grid-row: 3;
|
||||
grid-column: 3;
|
||||
}
|
||||
|
||||
.mod-name {
|
||||
font-size: 20pt;
|
||||
}
|
||||
}
|
||||
|
||||
// Desktop
|
||||
@media screen and (min-width: 1500px) {
|
||||
.result-name-author {
|
||||
display: flex;
|
||||
min-height: 38px;
|
||||
grid-column: 2;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,59 +1,57 @@
|
||||
<template>
|
||||
<div v-if="pages.length > 1" class="columns paginates">
|
||||
<svg
|
||||
:class="{
|
||||
'disabled-paginate': currentPage === 1,
|
||||
'active-paginate': currentPage !== 1,
|
||||
}"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
<button
|
||||
:class="{ disabled: currentPage === 1 }"
|
||||
class="paginate has-icon"
|
||||
@click="currentPage !== 1 ? switchPage(currentPage - 1) : null"
|
||||
>
|
||||
<polyline points="15 18 9 12 15 6"></polyline>
|
||||
</svg>
|
||||
<p
|
||||
<LeftArrowIcon />
|
||||
</button>
|
||||
<div
|
||||
v-for="(item, index) in pages"
|
||||
:key="'page-' + item"
|
||||
:class="{
|
||||
'active-page-number': currentPage !== item,
|
||||
'page-number': currentPage !== item,
|
||||
}"
|
||||
@click="currentPage !== item ? switchPage(item) : null"
|
||||
class="page-number-container"
|
||||
>
|
||||
<span v-if="pages[index - 1] + 1 !== item && item !== 1">...</span>
|
||||
<span :class="{ 'disabled-page-number': currentPage === item }">{{
|
||||
item
|
||||
}}</span>
|
||||
</p>
|
||||
<div v-if="pages[index - 1] + 1 !== item && item !== 1" class="has-icon">
|
||||
<GapIcon />
|
||||
</div>
|
||||
<button
|
||||
:class="{ 'page-number current': currentPage === item }"
|
||||
@click="currentPage !== item ? switchPage(item) : null"
|
||||
>
|
||||
{{ item }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<svg
|
||||
:class="{
|
||||
'disabled-paginate': currentPage === pages[pages.length - 1],
|
||||
'active-paginate': currentPage !== pages[pages.length - 1],
|
||||
}"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
<button
|
||||
:class="{ disabled: currentPage === pages[pages.length - 1] }"
|
||||
class="paginate has-icon"
|
||||
@click="
|
||||
currentPage !== pages[pages.length - 1]
|
||||
? switchPage(currentPage + 1)
|
||||
: null
|
||||
"
|
||||
>
|
||||
<polyline points="9 18 15 12 9 6"></polyline>
|
||||
</svg>
|
||||
<RightArrowIcon />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import GapIcon from '~/assets/images/utils/gap.svg?inline'
|
||||
import LeftArrowIcon from '~/assets/images/utils/left-arrow.svg?inline'
|
||||
import RightArrowIcon from '~/assets/images/utils/right-arrow.svg?inline'
|
||||
|
||||
export default {
|
||||
name: 'Pagination',
|
||||
components: {
|
||||
GapIcon,
|
||||
LeftArrowIcon,
|
||||
RightArrowIcon,
|
||||
},
|
||||
props: {
|
||||
currentPage: {
|
||||
type: Number,
|
||||
@@ -74,32 +72,41 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.paginates {
|
||||
<style scoped lang="scss">
|
||||
button {
|
||||
min-width: 2rem;
|
||||
padding: 0 0.5rem;
|
||||
height: 2rem;
|
||||
border-radius: 2rem;
|
||||
background: transparent;
|
||||
&.page-number.current {
|
||||
background: var(--color-button-bg-hover);
|
||||
color: var(--color-button-text-hover);
|
||||
cursor: default;
|
||||
}
|
||||
&.paginate.disabled {
|
||||
background: none;
|
||||
color: var(--color-button-text-disabled);
|
||||
cursor: default;
|
||||
}
|
||||
&:hover {
|
||||
background: var(--color-button-bg-active);
|
||||
color: var(--color-button-text-active);
|
||||
}
|
||||
}
|
||||
|
||||
.has-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 0.5rem;
|
||||
height: 2rem;
|
||||
svg {
|
||||
width: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.paginates p {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.disabled-paginate {
|
||||
cursor: default;
|
||||
color: var(--color-grey-5);
|
||||
}
|
||||
|
||||
.active-page-number,
|
||||
.active-paginate {
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.disabled-page-number {
|
||||
user-select: none;
|
||||
cursor: default;
|
||||
padding: 2px 3px;
|
||||
border-radius: 3px;
|
||||
background-color: var(--color-grey-1);
|
||||
.page-number-container {
|
||||
display: flex;
|
||||
max-height: 2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -27,7 +27,7 @@ export default {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--color-grey-3);
|
||||
background-color: var(--color-button-bg);
|
||||
border: none;
|
||||
opacity: 0.6;
|
||||
overflow-x: hidden;
|
||||
@@ -39,7 +39,7 @@ export default {
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 2;
|
||||
box-shadow: 0 2px 3px 1px var(--color-grey-2);
|
||||
box-shadow: 0 2px 3px 1px var(--color-button-bg);
|
||||
padding: 5px 60px 5px 20px;
|
||||
border-radius: 10px;
|
||||
max-height: 80%;
|
||||
|
||||
275
components/ProjectCard.vue
Normal file
@@ -0,0 +1,275 @@
|
||||
<template>
|
||||
<div class="project-card">
|
||||
<div class="icon">
|
||||
<img
|
||||
:src="iconUrl ? iconUrl : 'https://cdn.modrinth.com/placeholder.svg'"
|
||||
:alt="name"
|
||||
/>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="top">
|
||||
<h2 class="title">
|
||||
<nuxt-link v-if="isModrinth" :to="'/mod/' + id">{{ name }}</nuxt-link>
|
||||
<a v-else :href="pageUrl">{{ name }}</a>
|
||||
</h2>
|
||||
<p v-if="author" class="author">
|
||||
by <a :href="authorUrl">{{ author }}</a>
|
||||
</p>
|
||||
</div>
|
||||
<p class="description">
|
||||
{{ description }}
|
||||
</p>
|
||||
<div :class="{ vertical: editMode }" class="bottom">
|
||||
<div class="stats">
|
||||
<div v-if="status !== null" class="stat">
|
||||
<div class="info">
|
||||
<h4>Status</h4>
|
||||
<span v-if="status === 'approved'" class="badge green">
|
||||
Approved
|
||||
</span>
|
||||
<span v-if="status === 'rejected'" class="badge red">
|
||||
Rejected
|
||||
</span>
|
||||
<span v-if="status === 'draft'" class="badge yellow">Draft</span>
|
||||
<span v-if="status === 'processing'" class="badge yellow">
|
||||
Processing
|
||||
</span>
|
||||
<span v-if="status === 'unlisted'" class="badge gray">
|
||||
Unlisted
|
||||
</span>
|
||||
<span v-if="status === 'unknown'" class="badge gray">
|
||||
Unknown
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<DownloadIcon />
|
||||
<div class="info">
|
||||
<h4>Downloads</h4>
|
||||
<p class="value">{{ formatNumber(downloads) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<CalendarIcon />
|
||||
<div class="info">
|
||||
<h4>Created</h4>
|
||||
<p
|
||||
v-tooltip="
|
||||
$dayjs(createdAt).format(
|
||||
'[Created on] YYYY-MM-DD [at] HH:mm A'
|
||||
)
|
||||
"
|
||||
class="value"
|
||||
>
|
||||
{{ $dayjs(createdAt).fromNow() }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<EditIcon />
|
||||
<div class="info">
|
||||
<h4>Updated</h4>
|
||||
<p
|
||||
v-tooltip="
|
||||
$dayjs(updatedAt).format(
|
||||
'[Updated on] YYYY-MM-DD [at] HH:mm A'
|
||||
)
|
||||
"
|
||||
class="value"
|
||||
>
|
||||
{{ $dayjs(updatedAt).fromNow() }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="latestVersion" class="stat">
|
||||
<TagIcon />
|
||||
<div class="info">
|
||||
<h4>Available For</h4>
|
||||
<p class="value">
|
||||
{{ latestVersion }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Categories :categories="categories" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="editMode" class="buttons">
|
||||
<nuxt-link class="transparent-button column" :to="'/mod/' + id + '/edit'">
|
||||
Edit
|
||||
</nuxt-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Categories from '@/components/Categories'
|
||||
|
||||
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
||||
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
||||
import EditIcon from '~/assets/images/utils/edit.svg?inline'
|
||||
import TagIcon from '~/assets/images/utils/tag.svg?inline'
|
||||
|
||||
export default {
|
||||
name: 'ProjectCard',
|
||||
components: {
|
||||
Categories,
|
||||
CalendarIcon,
|
||||
DownloadIcon,
|
||||
EditIcon,
|
||||
TagIcon,
|
||||
},
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
default: 'modrinth-0',
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: 'Mod Name',
|
||||
},
|
||||
author: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: 'A mod description',
|
||||
},
|
||||
pageUrl: {
|
||||
type: String,
|
||||
default: '#',
|
||||
},
|
||||
authorUrl: {
|
||||
type: String,
|
||||
default: '#',
|
||||
},
|
||||
iconUrl: {
|
||||
type: String,
|
||||
default: '#',
|
||||
},
|
||||
downloads: {
|
||||
type: String,
|
||||
default: '0',
|
||||
},
|
||||
createdAt: {
|
||||
type: String,
|
||||
default: '0000-00-00',
|
||||
},
|
||||
updatedAt: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
latestVersion: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
categories: {
|
||||
type: Array,
|
||||
default() {
|
||||
return []
|
||||
},
|
||||
},
|
||||
editMode: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
status: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
role: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
isModrinth: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatNumber(x) {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.project-card {
|
||||
@extend %row;
|
||||
@extend %card-spaced-b;
|
||||
width: 100%;
|
||||
.icon {
|
||||
margin: auto 0;
|
||||
img {
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
margin: var(--spacing-card-md);
|
||||
border-radius: var(--size-rounded-icon);
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
@extend %column;
|
||||
.top {
|
||||
@extend %row;
|
||||
flex-wrap: wrap;
|
||||
margin-top: var(--spacing-card-md);
|
||||
margin-right: var(--spacing-card-md);
|
||||
.title {
|
||||
margin: 0;
|
||||
color: var(--color-text-dark);
|
||||
font-size: var(--font-size-lg);
|
||||
}
|
||||
.author {
|
||||
margin: auto 0 0 0.5rem;
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
.description {
|
||||
margin: var(--spacing-card-sm) var(--spacing-card-md) 0 0;
|
||||
height: 100%;
|
||||
color: var(--color-text-dark);
|
||||
}
|
||||
.bottom {
|
||||
@extend %column;
|
||||
margin-top: var(--spacing-card-sm);
|
||||
margin-right: var(--spacing-card-md);
|
||||
margin-bottom: var(--spacing-card-md);
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
flex-direction: row;
|
||||
&.vertical {
|
||||
flex-direction: column;
|
||||
.categories {
|
||||
margin-top: var(--spacing-card-sm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.stats {
|
||||
@extend %row;
|
||||
flex-wrap: wrap;
|
||||
|
||||
@media screen and (min-width: 900px) {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.stat {
|
||||
@extend %stat;
|
||||
}
|
||||
}
|
||||
.categories {
|
||||
@media screen and (min-width: 1024px) {
|
||||
flex-direction: row;
|
||||
margin: auto 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.buttons {
|
||||
@extend %column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<p
|
||||
class="filter"
|
||||
:class="{ 'filter-active': activeFilters.includes(facetName) }"
|
||||
:class="{
|
||||
'filter-active': activeFilters.includes(facetName),
|
||||
cursed: displayName == 'FlameAnvil',
|
||||
}"
|
||||
@click="toggle"
|
||||
>
|
||||
<slot></slot>
|
||||
@@ -41,30 +44,28 @@ export default {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
padding: 2px 2px 2px 20px;
|
||||
margin: 0 0 0 5px;
|
||||
border-left: 4px solid var(--color-grey-3);
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
color: var(--color-grey-5);
|
||||
padding: 0.4rem 0.3rem;
|
||||
margin: 3px 0 0 0.5rem;
|
||||
font-size: 1rem;
|
||||
letter-spacing: 0.02rem;
|
||||
@extend %transparent-clickable;
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
padding: 0.2rem 0.3rem;
|
||||
}
|
||||
|
||||
svg {
|
||||
color: var(--color-icon);
|
||||
margin-right: 5px;
|
||||
height: 1rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--color-grey-1);
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
|
||||
.filter-active {
|
||||
background-color: var(--color-grey-1);
|
||||
color: var(--color-text);
|
||||
border-left: 4px solid var(--color-brand);
|
||||
@extend %transparent-clickable.selected;
|
||||
svg {
|
||||
color: var(--color-brand-light);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -10,10 +10,19 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['error'],
|
||||
props: {
|
||||
error: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {
|
||||
message: 'Unknown error',
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
layout: 'home',
|
||||
created() {
|
||||
console.log(this.error)
|
||||
// console.log(this.error)
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
144
layouts/home.vue
@@ -1,144 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<header class="columns">
|
||||
<nuxt-link to="/">
|
||||
<img class="logo" src="~/assets/images/logo.svg" alt="logo" />
|
||||
</nuxt-link>
|
||||
<div class="links">
|
||||
<nuxt-link to="/">Home</nuxt-link>
|
||||
<nuxt-link to="/mods">Mods</nuxt-link>
|
||||
<nuxt-link to="/modpacks">Packs</nuxt-link>
|
||||
<nuxt-link to="/about">About</nuxt-link>
|
||||
<a href="https://discord.gg/gFRbNQ2">Discord</a>
|
||||
</div>
|
||||
</header>
|
||||
<nuxt />
|
||||
<footer>
|
||||
<div class="logo-wrapper columns">
|
||||
<img class="logo" src="~/assets/images/logo.svg" alt="logo" />
|
||||
<p class="name">modrinth</p>
|
||||
</div>
|
||||
<p class="copyright">© Guavy LLC</p>
|
||||
<div class="column">
|
||||
<h4 class="pages">Pages</h4>
|
||||
<nuxt-link to="/">Home</nuxt-link>
|
||||
<nuxt-link to="/mods">Mods</nuxt-link>
|
||||
<nuxt-link to="/modpacks">Packs</nuxt-link>
|
||||
<nuxt-link to="/about">About</nuxt-link>
|
||||
<nuxt-link to="/guides">Guides</nuxt-link>
|
||||
</div>
|
||||
<div class="column">
|
||||
<h4 class="developers">Developers</h4>
|
||||
<nuxt-link to="/documentation">Documentation</nuxt-link>
|
||||
<a href="https://github.com/modrinth">Open Source</a>
|
||||
<a href="https://github.com/modrinth/knossos/issues">Issues</a>
|
||||
</div>
|
||||
<div class="column legal-wrapper">
|
||||
<h4 class="legal">Legal</h4>
|
||||
<nuxt-link to="/tos">TOS</nuxt-link>
|
||||
<nuxt-link to="/privacy">Privacy Policy</nuxt-link>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
header {
|
||||
width: 100%;
|
||||
|
||||
.logo {
|
||||
margin: 25px 50px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
.links {
|
||||
margin: auto 0;
|
||||
|
||||
a {
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
margin: 0 25px;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--color-grey-1);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
&.nuxt-link-exact-active {
|
||||
border-bottom: 3px var(--color-brand) solid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
justify-content: center;
|
||||
margin-top: 250px;
|
||||
margin-bottom: 100px;
|
||||
display: grid;
|
||||
column-gap: 50px;
|
||||
grid-template-columns: 175px 120px 120px 175px;
|
||||
grid-template-rows: 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px 20px;
|
||||
|
||||
.logo-wrapper {
|
||||
grid-column-start: 1;
|
||||
grid-row-start: 1;
|
||||
|
||||
.logo {
|
||||
width: 30px;
|
||||
}
|
||||
.name {
|
||||
place-self: center;
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-family: 'Montserrat Alternates', serif;
|
||||
}
|
||||
}
|
||||
.copyright {
|
||||
grid-column-start: 1;
|
||||
grid-row-start: 10;
|
||||
color: var(--color-grey-6);
|
||||
}
|
||||
h4 {
|
||||
font-weight: 600;
|
||||
margin: 0 0 20px;
|
||||
grid-row-start: 1;
|
||||
}
|
||||
.column {
|
||||
display: grid;
|
||||
row-gap: 5px;
|
||||
grid-template-rows: 40px 20px 20px 20px 20px 20px 20px 20px;
|
||||
a {
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--color-grey-5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 550px) {
|
||||
footer {
|
||||
column-gap: 10px;
|
||||
margin-left: 300px !important;
|
||||
}
|
||||
.legal-wrapper {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
footer {
|
||||
margin-left: 200px;
|
||||
}
|
||||
.copyright,
|
||||
.logo-wrapper {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -20,7 +20,7 @@ export default {
|
||||
hid: 'description',
|
||||
name: 'description',
|
||||
content:
|
||||
'Modrinth is a mod distribution platform. Modrinth is modern, easy to use, and built for modders. Modrinth currently supports Minecraft, including the forge and fabric mod loaders.',
|
||||
'Modrinth is a mod distribution platform. Modrinth is modern, easy to use, and built for modders. Modrinth currently supports Minecraft, including Forge and Fabric mod loaders.',
|
||||
},
|
||||
|
||||
{ hid: 'publisher', name: 'publisher', content: 'Guavy LLC' },
|
||||
@@ -53,12 +53,7 @@ export default {
|
||||
{
|
||||
rel: 'stylesheet',
|
||||
href:
|
||||
'https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap',
|
||||
},
|
||||
{
|
||||
rel: 'stylesheet',
|
||||
href:
|
||||
'https://fonts.googleapis.com/css2?family=Montserrat+Alternates:wght@600&display=swap',
|
||||
'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;800&display=swap',
|
||||
},
|
||||
],
|
||||
script: [
|
||||
@@ -78,7 +73,7 @@ export default {
|
||||
vue: {
|
||||
config: {
|
||||
productionTip: false,
|
||||
devtools: false,
|
||||
devtools: true,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -96,6 +91,7 @@ export default {
|
||||
plugins: [
|
||||
'~/plugins/vue-tooltip.js',
|
||||
'~/plugins/vue-notification.js',
|
||||
'~/plugins/compiled-markdown-directive.js',
|
||||
'~/plugins/vue-syntax.js',
|
||||
],
|
||||
/*
|
||||
@@ -165,6 +161,9 @@ export default {
|
||||
*/
|
||||
build: {
|
||||
transpile: ['vue-tooltip', 'vue-notification'],
|
||||
styleResources: {
|
||||
scss: './assets/styles/injected.scss',
|
||||
}
|
||||
},
|
||||
loading: {
|
||||
color: 'green',
|
||||
|
||||
5
package-lock.json
generated
@@ -12762,6 +12762,11 @@
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.12.tgz",
|
||||
"integrity": "sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg=="
|
||||
},
|
||||
"vue-click-outside": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-click-outside/-/vue-click-outside-1.1.0.tgz",
|
||||
"integrity": "sha512-pNyvAA9mRXJwPHlHJyjMb4IONSc7khS5lxGcMyE2EIKgNMAO279PWM9Hyq0d5J4FkiSRdmFLwnbjDd5UtPizHQ=="
|
||||
},
|
||||
"vue-client-only": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-client-only/-/vue-client-only-2.0.0.tgz",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
"marked": "^1.2.0",
|
||||
"nuxt": "^2.14.7",
|
||||
"v-tooltip": "^2.0.3",
|
||||
"vue-click-outside": "^1.1.0",
|
||||
"vue-highlightjs": "^1.3.3",
|
||||
"vue-multiselect": "^2.1.6",
|
||||
"vue-notification": "^1.3.20",
|
||||
|
||||
@@ -1,28 +1,35 @@
|
||||
<template>
|
||||
<div class="main">
|
||||
<h1>About</h1>
|
||||
<p>
|
||||
Founded in 2020, Modrinth was created to provide modders with an open and
|
||||
intuitive platform to publish their mods on.
|
||||
</p>
|
||||
<div class="container">
|
||||
<h1>About</h1>
|
||||
<p>
|
||||
Founded in 2020, Modrinth was created to provide modders with an open
|
||||
and intuitive platform to publish their mods on.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Our primary goal is to be as open as possible, with all our code being
|
||||
Open Source, while giving back to the modding community as much as
|
||||
possible.
|
||||
</p>
|
||||
<p>
|
||||
Our primary goal is to be as open as possible, with all our code being
|
||||
Open Source, while giving back to the modding community as much as
|
||||
possible.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
While we still are in early alpha, we hope we can soon be a major modding
|
||||
platform for all modders :)
|
||||
</p>
|
||||
<p>
|
||||
While we still are in early alpha, we hope we can soon be a major
|
||||
modding platform for all modders :)
|
||||
</p>
|
||||
</div>
|
||||
<m-footer class="footer" centered />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MFooter from '@/components/MFooter'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MFooter,
|
||||
},
|
||||
auth: false,
|
||||
layout: 'home',
|
||||
head: {
|
||||
title: 'About - Modrinth',
|
||||
meta: [
|
||||
@@ -54,7 +61,12 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main {
|
||||
margin: 0 auto;
|
||||
margin: var(--spacing-card-sm) auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.container {
|
||||
@extend %card;
|
||||
padding: var(--spacing-card-sm) var(--spacing-card-lg);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,80 +1,80 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<h2>My projects</h2>
|
||||
<div class="section-header">
|
||||
<h3>Mods</h3>
|
||||
<nuxt-link class="create-button" to="/mod/create"
|
||||
>Create a new mod</nuxt-link
|
||||
>
|
||||
<div class="page-container">
|
||||
<div class="page-contents">
|
||||
<div class="sidebar-l">
|
||||
<div class="card page-nav">
|
||||
<nuxt-link :to="'/dashboard/projects'" class="tab last">
|
||||
<ModIcon />
|
||||
My mods
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<client-only>
|
||||
<EthicalAd type="image" />
|
||||
</client-only>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="section-header columns">
|
||||
<h3 class="column-grow-1">My mods</h3>
|
||||
<nuxt-link class="brand-button column" to="/mod/create">
|
||||
Create a mod
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<ModCard
|
||||
v-for="mod in mods"
|
||||
:id="mod.id"
|
||||
:key="mod.id"
|
||||
:author="mod.author"
|
||||
:name="mod.title"
|
||||
:description="mod.description"
|
||||
:latest-version="mod.latest_version"
|
||||
:created-at="mod.published"
|
||||
:updated-at="mod.updated"
|
||||
:downloads="mod.downloads.toString()"
|
||||
:icon-url="mod.icon_url"
|
||||
:author-url="mod.author_url"
|
||||
:page-url="mod.page_url"
|
||||
:categories="mod.categories"
|
||||
:edit-mode="true"
|
||||
:status="mod.status"
|
||||
:is-modrinth="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Name</th>
|
||||
<th>Role</th>
|
||||
<th>Status</th>
|
||||
<th>Downloads</th>
|
||||
<th>Last updated</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="mod in mods" :key="mod.id">
|
||||
<td>
|
||||
<img class="rounded-md" :src="mod.icon_url" />
|
||||
</td>
|
||||
<td>
|
||||
<nuxt-link :to="'/mod/' + mod.id">
|
||||
{{ mod.title }}
|
||||
</nuxt-link>
|
||||
</td>
|
||||
<td>Owner</td>
|
||||
<td>
|
||||
<span v-if="mod.status === 'approved'" class="badge green">
|
||||
Approved
|
||||
</span>
|
||||
<span v-if="mod.status === 'rejected'" class="badge red">
|
||||
Rejected
|
||||
</span>
|
||||
<span v-if="mod.status === 'draft'" class="badge yellow">
|
||||
Draft
|
||||
</span>
|
||||
<span v-if="mod.status === 'processing'" class="badge yellow">
|
||||
Processing
|
||||
</span>
|
||||
<span v-if="mod.status === 'unlisted'" class="badge gray">
|
||||
Unlisted
|
||||
</span>
|
||||
<span v-if="mod.status === 'unknown'" class="badge gray">
|
||||
Unknown
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ mod.downloads }}</td>
|
||||
<td>{{ $dayjs(mod.published).format('YYYY-MM-DD') }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<client-only>
|
||||
<EthicalAd />
|
||||
</client-only>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import EthicalAd from '@/components/EthicalAd'
|
||||
import ModCard from '@/components/ProjectCard'
|
||||
|
||||
import ModIcon from '~/assets/images/sidebar/mod.svg?inline'
|
||||
|
||||
export default {
|
||||
components: { EthicalAd },
|
||||
components: {
|
||||
EthicalAd,
|
||||
ModCard,
|
||||
ModIcon,
|
||||
},
|
||||
async fetch() {
|
||||
const config = {
|
||||
headers: {
|
||||
Authorization: this.$auth.getToken('local'),
|
||||
},
|
||||
}
|
||||
|
||||
try {
|
||||
let res = await axios.get(
|
||||
`https://api.modrinth.com/api/v1/user/${this.$auth.user.id}/mods`
|
||||
`https://api.modrinth.com/api/v1/user/${this.$auth.user.id}/mods`,
|
||||
config
|
||||
)
|
||||
|
||||
if (res.data) {
|
||||
res = await axios.get(
|
||||
`https://api.modrinth.com/api/v1/mods?ids=${JSON.stringify(res.data)}`
|
||||
`https://api.modrinth.com/api/v1/mods?ids=${JSON.stringify(
|
||||
res.data
|
||||
)}`,
|
||||
config
|
||||
)
|
||||
this.mods = res.data
|
||||
}
|
||||
@@ -90,29 +90,23 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.section-header {
|
||||
display: flex;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
& > * {
|
||||
margin-right: 1rem;
|
||||
@extend %card;
|
||||
padding: var(--spacing-card-md) var(--spacing-card-lg);
|
||||
margin-bottom: var(--spacing-card-md);
|
||||
h3 {
|
||||
margin: auto 0;
|
||||
color: var(--color-text-dark);
|
||||
font-weight: var(--font-weight-extrabold);
|
||||
}
|
||||
}
|
||||
|
||||
.create-button {
|
||||
margin: auto 0;
|
||||
padding: 4px 20px;
|
||||
border-radius: 5px;
|
||||
color: var(--color-grey-5);
|
||||
background-color: var(--color-grey-1);
|
||||
}
|
||||
|
||||
table {
|
||||
background: var(--color-bg);
|
||||
border-collapse: collapse;
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 2px 3px 1px var(--color-grey-2);
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
margin-bottom: var(--spacing-card-md);
|
||||
background: var(--color-raised-bg);
|
||||
border-radius: var(--size-rounded-card);
|
||||
|
||||
* {
|
||||
text-align: left;
|
||||
@@ -122,7 +116,7 @@ table {
|
||||
tr:first-child {
|
||||
th,
|
||||
td {
|
||||
border-bottom: 1px solid var(--color-grey-2);
|
||||
border-bottom: 1px solid var(--color-divider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +124,7 @@ table {
|
||||
td {
|
||||
&:first-child {
|
||||
text-align: center;
|
||||
width: 5%;
|
||||
width: 7%;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
@@ -140,7 +134,7 @@ table {
|
||||
}
|
||||
|
||||
th {
|
||||
color: #718096;
|
||||
color: var(--color-heading);
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.02rem;
|
||||
margin-bottom: 0.5rem;
|
||||
@@ -150,7 +144,7 @@ table {
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0.25rem 1rem;
|
||||
padding: 0.75rem;
|
||||
|
||||
img {
|
||||
height: 3rem;
|
||||
@@ -185,4 +179,8 @@ table {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mod-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<h2>Documentation</h2>
|
||||
<p>Coming Soon!</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
auth: false,
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main {
|
||||
margin: 0 auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
</style>
|
||||
@@ -2,7 +2,9 @@
|
||||
<div>
|
||||
<div class="main-hero columns">
|
||||
<div class="left">
|
||||
<h1 class="typewriter">{{ currentText }}</h1>
|
||||
<h1 class="typewriter">
|
||||
{{ currentText }}<span aria-hidden="true"></span>
|
||||
</h1>
|
||||
<h1>modding platform</h1>
|
||||
</div>
|
||||
<div class="right columns">
|
||||
@@ -159,13 +161,18 @@ fetch('https://api.modrinth.com/api/v1/mod').then(res => res.json()).then(data =
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
<m-footer class="footer" centered />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MFooter from '@/components/MFooter'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MFooter,
|
||||
},
|
||||
auth: false,
|
||||
layout: 'home',
|
||||
data() {
|
||||
return {
|
||||
currentText: 'Open source',
|
||||
@@ -208,6 +215,7 @@ export default {
|
||||
}
|
||||
|
||||
.main-hero {
|
||||
margin-top: 100px;
|
||||
height: 600px;
|
||||
|
||||
.left {
|
||||
@@ -217,12 +225,15 @@ export default {
|
||||
.typewriter {
|
||||
display: inline-block;
|
||||
color: var(--color-brand);
|
||||
border-right: 0.15em solid var(--color-brand);
|
||||
animation: caret 1s steps(1) infinite;
|
||||
|
||||
@keyframes caret {
|
||||
50% {
|
||||
border-color: transparent;
|
||||
span {
|
||||
border-right: 0.15em solid var(--color-brand);
|
||||
animation: caret 1s steps(1) infinite;
|
||||
|
||||
@keyframes caret {
|
||||
50% {
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,7 +267,7 @@ export default {
|
||||
p {
|
||||
line-height: 25px;
|
||||
letter-spacing: 0.2px;
|
||||
color: var(--color-grey-7);
|
||||
color: var(--color-text);
|
||||
|
||||
span {
|
||||
color: var(--color-brand);
|
||||
@@ -276,7 +287,7 @@ export default {
|
||||
}
|
||||
|
||||
.slanted-hero {
|
||||
background: var(--color-grey-1);
|
||||
background: var(--color-raised-bg);
|
||||
height: 500px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@@ -336,6 +347,10 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 150px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
.hero {
|
||||
margin-top: 0 !important;
|
||||
|
||||
191
pages/legal/privacy.vue
Normal file
@@ -0,0 +1,191 @@
|
||||
<template>
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
<h1>Privacy Policy</h1>
|
||||
|
||||
<p>
|
||||
At Modrinth, accessible from https://modrinth.com, one of our main
|
||||
priorities is the privacy of our visitors. This Privacy Policy document
|
||||
contains types of information that is collected and recorded by Modrinth
|
||||
and how we use it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you have additional questions or require more information about our
|
||||
Privacy Policy, do not hesitate to contact us.
|
||||
</p>
|
||||
|
||||
<h2>Log Files</h2>
|
||||
|
||||
<p>
|
||||
Modrinth follows a standard procedure of using log files. These files
|
||||
log visitors when they visit websites. All hosting companies do this and
|
||||
a part of hosting services' analytics. The information collected by log
|
||||
files include internet protocol (IP) addresses, browser type, Internet
|
||||
Service Provider (ISP), date and time stamp, referring/exit pages, and
|
||||
possibly the number of clicks. These are not linked to any information
|
||||
that is personally identifiable. The purpose of the information is for
|
||||
analyzing trends, administering the site, tracking users' movement on
|
||||
the website, and gathering demographic information.
|
||||
</p>
|
||||
|
||||
<h2>Cookies and Web Beacons</h2>
|
||||
|
||||
<p>
|
||||
Like any other website, Modrinth uses 'cookies'. These cookies are used
|
||||
to store information including visitors' preferences, and the pages on
|
||||
the website that the visitor accessed or visited. The information is
|
||||
used to optimize the users' experience by customizing our web page
|
||||
content based on visitors' browser type and/or other information.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For more general information on cookies, please read
|
||||
<a href="https://www.privacypolicies.com/blog/cookies/"
|
||||
>"What Are Cookies"</a
|
||||
>.
|
||||
</p>
|
||||
|
||||
<h2>Our Advertising Partners</h2>
|
||||
|
||||
<p>
|
||||
Some of advertisers on our site may use cookies and web beacons. Our
|
||||
advertising partners are listed below. Each of our advertising partners
|
||||
has their own Privacy Policy for their policies on user data. For easier
|
||||
access, we hyperlinked to their Privacy Policies below.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>EthicalAds</p>
|
||||
<p>
|
||||
<a href="https://www.ethicalads.io/privacy-policy/"
|
||||
>https://www.ethicalads.io/privacy-policy/</a
|
||||
>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Privacy Policies</h2>
|
||||
|
||||
<P
|
||||
>You may consult this list to find the Privacy Policy for each of the
|
||||
advertising partners of Modrinth.</P
|
||||
>
|
||||
|
||||
<p>
|
||||
Third-party ad servers or ad networks uses technologies like cookies,
|
||||
JavaScript, or Web Beacons that are used in their respective
|
||||
advertisements and links that appear on Modrinth, which are sent
|
||||
directly to users' browser. They automatically receive your IP address
|
||||
when this occurs. These technologies are used to measure the
|
||||
effectiveness of their advertising campaigns and/or to personalize the
|
||||
advertising content that you see on websites that you visit.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that Modrinth has no access to or control over these cookies that
|
||||
are used by third-party advertisers.
|
||||
</p>
|
||||
|
||||
<h2>Third Party Privacy Policies</h2>
|
||||
|
||||
<p>
|
||||
Modrinth's Privacy Policy does not apply to other advertisers or
|
||||
websites. Thus, we are advising you to consult the respective Privacy
|
||||
Policies of these third-party ad servers for more detailed information.
|
||||
It may include their practices and instructions about how to opt-out of
|
||||
certain options.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can choose to disable cookies through your individual browser
|
||||
options. To know more detailed information about cookie management with
|
||||
specific web browsers, it can be found at the browsers' respective
|
||||
websites. What Are Cookies?
|
||||
</p>
|
||||
|
||||
<h2>Children's Information</h2>
|
||||
|
||||
<p>
|
||||
Another part of our priority is adding protection for children while
|
||||
using the internet. We encourage parents and guardians to observe,
|
||||
participate in, and/or monitor and guide their online activity.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Modrinth does not knowingly collect any Personal Identifiable
|
||||
Information from children under the age of 13. If you think that your
|
||||
child provided this kind of information on our website, we strongly
|
||||
encourage you to contact us immediately and we will do our best efforts
|
||||
to promptly remove such information from our records.
|
||||
</p>
|
||||
|
||||
<h2>Online Privacy Policy Only</h2>
|
||||
|
||||
<p>
|
||||
This Privacy Policy applies only to our online activities and is valid
|
||||
for visitors to our website with regards to the information that they
|
||||
shared and/or collect in Modrinth. This policy is not applicable to any
|
||||
information collected offline or via channels other than this website.
|
||||
</p>
|
||||
|
||||
<h2>Consent</h2>
|
||||
|
||||
<p>
|
||||
By using our website, you hereby consent to our Privacy Policy and agree
|
||||
to its Terms and Conditions.
|
||||
</p>
|
||||
</div>
|
||||
<m-footer class="footer" centered />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MFooter from '@/components/MFooter'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MFooter,
|
||||
},
|
||||
auth: false,
|
||||
head: {
|
||||
title: 'Privacy - Modrinth',
|
||||
meta: [
|
||||
{
|
||||
hid: 'description',
|
||||
name: 'description',
|
||||
content:
|
||||
'The privacy policy of Modrinth, an open source modding platform. Modrinth currently supports Minecraft, including the forge and fabric mod loaders.',
|
||||
},
|
||||
{
|
||||
hid: 'apple-mobile-web-app-title',
|
||||
name: 'apple-mobile-web-app-title',
|
||||
content: 'Privacy Policy',
|
||||
},
|
||||
{
|
||||
hid: 'og:title',
|
||||
name: 'og:title',
|
||||
content: 'Privacy Policy',
|
||||
},
|
||||
{
|
||||
hid: 'og:url',
|
||||
name: 'og:url',
|
||||
content: `https://modrinth.com/privacy`,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main {
|
||||
margin: var(--spacing-card-sm) auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.container {
|
||||
@extend %card;
|
||||
padding: var(--spacing-card-sm) var(--spacing-card-lg);
|
||||
}
|
||||
</style>
|
||||
203
pages/legal/terms.vue
Normal file
@@ -0,0 +1,203 @@
|
||||
<template>
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
<h1>Terms and Conditions</h1>
|
||||
|
||||
<h2>1. Terms</h2>
|
||||
|
||||
<p>
|
||||
By accessing this Website, accessible from https://modrinth.com, you are
|
||||
agreeing to be bound by these Website Terms and Conditions of Use and
|
||||
agree that you are responsible for the agreement with any applicable
|
||||
local laws. If you disagree with any of these terms, you are prohibited
|
||||
from accessing this site. The materials contained in this Website are
|
||||
protected by copyright and trade mark law.
|
||||
</p>
|
||||
|
||||
<h2>2. Use License</h2>
|
||||
|
||||
<p>
|
||||
Permission is granted to temporarily download one copy of the materials
|
||||
on Guavy LLC's Website for personal, non-commercial transitory viewing
|
||||
only. This is the grant of a license, not a transfer of title, and under
|
||||
this license you may not:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>modify or copy the materials;</li>
|
||||
<li>
|
||||
use the materials for any commercial purpose or for any public
|
||||
display;
|
||||
</li>
|
||||
<li>
|
||||
attempt to reverse engineer any software contained on Guavy LLC's
|
||||
Website;
|
||||
</li>
|
||||
<li>
|
||||
remove any copyright or other proprietary notations from the
|
||||
materials; or
|
||||
</li>
|
||||
<li>
|
||||
transferring the materials to another person or "mirror" the materials
|
||||
on any other server.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
This will let Guavy LLC to terminate upon violations of any of these
|
||||
restrictions. Upon termination, your viewing right will also be
|
||||
terminated and you should destroy any downloaded materials in your
|
||||
possession whether it is printed or electronic format.
|
||||
</p>
|
||||
|
||||
<h2>3. Disclaimer</h2>
|
||||
|
||||
<p>
|
||||
All the materials on Guavy LLC’s Website are provided "as is". Guavy LLC
|
||||
makes no warranties, may it be expressed or implied, therefore negates
|
||||
all other warranties. Furthermore, Guavy LLC does not make any
|
||||
representations concerning the accuracy or reliability of the use of the
|
||||
materials on its Website or otherwise relating to such materials or any
|
||||
sites linked to this Website.
|
||||
</p>
|
||||
|
||||
<h2>4. Limitations</h2>
|
||||
|
||||
<p>
|
||||
Guavy LLC or its suppliers will not be hold accountable for any damages
|
||||
that will arise with the use or inability to use the materials on Guavy
|
||||
LLC’s Website, even if Guavy LLC or an authorize representative of this
|
||||
Website has been notified, orally or written, of the possibility of such
|
||||
damage. Some jurisdiction does not allow limitations on implied
|
||||
warranties or limitations of liability for incidental damages, these
|
||||
limitations may not apply to you.
|
||||
</p>
|
||||
|
||||
<h2>5. Revisions and Errata</h2>
|
||||
|
||||
<p>
|
||||
The materials appearing on Guavy LLC’s Website may include technical,
|
||||
typographical, or photographic errors. Guavy LLC will not promise that
|
||||
any of the materials in this Website are accurate, complete, or current.
|
||||
Guavy LLC may change the materials contained on its Website at any time
|
||||
without notice. Guavy LLC does not make any commitment to update the
|
||||
materials.
|
||||
</p>
|
||||
|
||||
<h2>6. Links</h2>
|
||||
|
||||
<p>
|
||||
Guavy LLC has not reviewed all of the sites linked to its Website and is
|
||||
not responsible for the contents of any such linked site. The presence
|
||||
of any link does not imply endorsement by Guavy LLC of the site. The use
|
||||
of any linked website is at the user’s own risk.
|
||||
</p>
|
||||
|
||||
<h2>7. Site Terms of Use Modifications</h2>
|
||||
|
||||
<p>
|
||||
Guavy LLC may revise these Terms of Use for its Website at any time
|
||||
without prior notice. By using this Website, you are agreeing to be
|
||||
bound by the current version of these Terms and Conditions of Use.
|
||||
</p>
|
||||
|
||||
<h2>8. Your Privacy</h2>
|
||||
|
||||
<p>
|
||||
Please read our <nuxt-link to="/privacy"> Privacy Policy</nuxt-link>.
|
||||
</p>
|
||||
|
||||
<h2>9. Governing Law</h2>
|
||||
|
||||
<p>
|
||||
Any claim related to Guavy LLC's Website shall be governed by the laws
|
||||
of us without regards to its conflict of law provisions.
|
||||
</p>
|
||||
|
||||
<h2>10. Content</h2>
|
||||
|
||||
<p>
|
||||
When you upload text, software, mods, scripts, graphics, photos, audio,
|
||||
videos, links, interactive features and other materials that may be
|
||||
viewed on, or accessed through Modrinth, we refer to it as “Content”.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
You must own or have the necessary licenses, rights, consents, and
|
||||
permissions to store, share or distribute the Content that is uploaded
|
||||
under your Modrinth account.
|
||||
</li>
|
||||
<li>
|
||||
You are responsible for all activity and Content that is uploaded
|
||||
under your Modrinth account.
|
||||
</li>
|
||||
<li>
|
||||
You must not transmit any viruses, worms, malware, or any other code
|
||||
of a destructive nature through Modrinth.
|
||||
</li>
|
||||
<li>
|
||||
You retain all of your ownership rights to your Content. We do not
|
||||
claim any ownership in or to any of your Content.
|
||||
</li>
|
||||
<li>
|
||||
To enable us to provide the services of Modrinth, you hereby grant us
|
||||
a worldwide, non-exclusive, royalty-free, and unrestricted license to
|
||||
use, reproduce, distribute copies, prepare derivative works of, or
|
||||
display Content in connection with Modrinth in any medium and for any
|
||||
purpose (including commercial purposes), which is irrevocable.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<m-footer class="footer" centered />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MFooter from '@/components/MFooter'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MFooter,
|
||||
},
|
||||
auth: false,
|
||||
head: {
|
||||
title: 'Terms - Modrinth',
|
||||
meta: [
|
||||
{
|
||||
hid: 'description',
|
||||
name: 'description',
|
||||
content:
|
||||
'The Terms of Service of Modrinth, an open source modding platform. Modrinth currently supports Minecraft, including the forge and fabric mod loaders.',
|
||||
},
|
||||
{
|
||||
hid: 'apple-mobile-web-app-title',
|
||||
name: 'apple-mobile-web-app-title',
|
||||
content: 'Terms of Service',
|
||||
},
|
||||
{
|
||||
hid: 'og:title',
|
||||
name: 'og:title',
|
||||
content: 'Terms of Service',
|
||||
},
|
||||
{
|
||||
hid: 'og:url',
|
||||
name: 'og:url',
|
||||
content: `https://modrinth.com/tos`,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main {
|
||||
margin: var(--spacing-card-sm) auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
.container {
|
||||
@extend %card;
|
||||
padding: var(--spacing-card-sm) var(--spacing-card-lg);
|
||||
}
|
||||
</style>
|
||||
571
pages/mod/_id/edit.vue
Normal file
@@ -0,0 +1,571 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<div class="page-contents">
|
||||
<header class="columns">
|
||||
<h2 class="column-grow-1">Edit Mod</h2>
|
||||
<button
|
||||
title="Save"
|
||||
class="brand-button column"
|
||||
:disabled="!this.$nuxt.$loading"
|
||||
@click="saveMod"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</header>
|
||||
<EthicalAd class="advert" />
|
||||
<section class="essentials">
|
||||
<h3>Name</h3>
|
||||
<label>
|
||||
<span>
|
||||
Be creative. TechCraft v7 won't be searchable and won't be clicked
|
||||
on
|
||||
</span>
|
||||
<input v-model="mod.title" type="text" placeholder="Enter the name" />
|
||||
</label>
|
||||
<h3>Summary</h3>
|
||||
<label>
|
||||
<span>
|
||||
Give a quick description to your mod. It will appear in the search
|
||||
</span>
|
||||
<input
|
||||
v-model="mod.description"
|
||||
type="text"
|
||||
placeholder="Enter the summary"
|
||||
/>
|
||||
</label>
|
||||
<h3>Categories</h3>
|
||||
<label>
|
||||
<span>
|
||||
Select up to 3 categories. They will help to find your mod
|
||||
</span>
|
||||
<multiselect
|
||||
id="categories"
|
||||
v-model="mod.categories"
|
||||
:options="availableCategories"
|
||||
:loading="availableCategories.length === 0"
|
||||
:multiple="true"
|
||||
:searchable="false"
|
||||
:show-no-results="false"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:show-labels="false"
|
||||
:max="3"
|
||||
:limit="6"
|
||||
:hide-selected="true"
|
||||
placeholder="Choose categories"
|
||||
/>
|
||||
</label>
|
||||
<h3>Vanity URL (slug)</h3>
|
||||
<label>
|
||||
<span>
|
||||
Set this to something pretty, so URLs to your mod are more readable
|
||||
</span>
|
||||
<input
|
||||
id="name"
|
||||
v-model="mod.slug"
|
||||
type="text"
|
||||
placeholder="Enter the vanity URL's last bit"
|
||||
/>
|
||||
</label>
|
||||
</section>
|
||||
<section class="mod-icon rows">
|
||||
<h3>Icon</h3>
|
||||
<div class="columns row-grow-1">
|
||||
<div class="column-grow-1 rows">
|
||||
<file-input
|
||||
accept="image/png,image/jpeg,image/gif"
|
||||
class="choose-image"
|
||||
prompt="Choose image or drag it here"
|
||||
@change="showPreviewImage"
|
||||
/>
|
||||
<ul class="row-grow-1">
|
||||
<li>Must be a square</li>
|
||||
<li>Minimum size is 100x100</li>
|
||||
<li>Acceptable formats are PNG, JPEG and GIF</li>
|
||||
</ul>
|
||||
<button
|
||||
class="transparent-button"
|
||||
@click="
|
||||
icon = null
|
||||
previewImage = null
|
||||
"
|
||||
>
|
||||
Reset icon
|
||||
</button>
|
||||
</div>
|
||||
<img
|
||||
:src="
|
||||
mod.icon_url
|
||||
? mod.icon_url
|
||||
: 'https://cdn.modrinth.com/placeholder.svg'
|
||||
"
|
||||
alt="preview-image"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
<section class="game-sides">
|
||||
<h3>Supported environments</h3>
|
||||
<div class="columns">
|
||||
<span>
|
||||
Let others know if your mod is for clients, servers or universal.
|
||||
For example, IC2 will be required + required, while OptiFine will be
|
||||
required + no functionality
|
||||
</span>
|
||||
<div class="labeled-control">
|
||||
<h3>Client</h3>
|
||||
<Multiselect
|
||||
v-model="clientSideType"
|
||||
placeholder="Select one"
|
||||
track-by="id"
|
||||
label="label"
|
||||
:options="sideTypes"
|
||||
:searchable="false"
|
||||
:close-on-select="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="false"
|
||||
/>
|
||||
</div>
|
||||
<div class="labeled-control">
|
||||
<h3>Server</h3>
|
||||
<Multiselect
|
||||
v-model="serverSideType"
|
||||
placeholder="Select one"
|
||||
track-by="id"
|
||||
label="label"
|
||||
:options="sideTypes"
|
||||
:searchable="false"
|
||||
:close-on-select="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="false"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="description">
|
||||
<h3>
|
||||
<label
|
||||
for="body"
|
||||
title="You can type the of the long form of your description here."
|
||||
>
|
||||
Description
|
||||
</label>
|
||||
</h3>
|
||||
<span>
|
||||
You can type the of the long form of your description here. This
|
||||
editor supports markdown. You can find the syntax
|
||||
<a
|
||||
href="https://guides.github.com/features/mastering-markdown/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>here</a
|
||||
>.
|
||||
</span>
|
||||
<div class="columns">
|
||||
<div class="textarea-wrapper">
|
||||
<textarea id="body" v-model="body"></textarea>
|
||||
</div>
|
||||
<div v-compiled-markdown="body" class="markdown-body"></div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="extra-links">
|
||||
<div class="title">
|
||||
<h3>External links</h3>
|
||||
</div>
|
||||
<label
|
||||
title="A place for users to report bugs, issues, and concerns about your mod."
|
||||
>
|
||||
<span>Issue tracker</span>
|
||||
<input
|
||||
v-model="mod.issues_url"
|
||||
type="url"
|
||||
placeholder="Enter a valid URL"
|
||||
/>
|
||||
</label>
|
||||
<label title="A page/repository containing the source code">
|
||||
<span>Source code</span>
|
||||
<input
|
||||
v-model="mod.source_url"
|
||||
type="url"
|
||||
placeholder="Enter a valid URL"
|
||||
/>
|
||||
</label>
|
||||
<label
|
||||
title="A page containing information, documentation, and help for the mod."
|
||||
>
|
||||
<span>Wiki page</span>
|
||||
<input
|
||||
v-model="mod.wiki_url"
|
||||
type="url"
|
||||
placeholder="Enter a valid URL"
|
||||
/>
|
||||
</label>
|
||||
<label title="An inivitation link to your Discord server.">
|
||||
<span>Discord invite</span>
|
||||
<input
|
||||
v-model="mod.wiki_url"
|
||||
type="url"
|
||||
placeholder="Enter a valid URL"
|
||||
/>
|
||||
</label>
|
||||
</section>
|
||||
<section class="license">
|
||||
<div class="title">
|
||||
<h3>License</h3>
|
||||
</div>
|
||||
<label>
|
||||
<span>
|
||||
It is really important to choose a proper license for your mod. You
|
||||
may choose one from our list or provide a URL to your own license.
|
||||
URL field will be filled automatically for provided licenses
|
||||
</span>
|
||||
<div class="input-group">
|
||||
<Multiselect
|
||||
v-model="mod.license"
|
||||
placeholder="Select one"
|
||||
track-by="short"
|
||||
label="name"
|
||||
:options="availableLicenses"
|
||||
:searchable="true"
|
||||
:close-on-select="true"
|
||||
:show-labels="false"
|
||||
/>
|
||||
<input
|
||||
v-model="mod.license.url"
|
||||
type="url"
|
||||
placeholder="License URL"
|
||||
/>
|
||||
</div>
|
||||
</label>
|
||||
</section>
|
||||
<!--
|
||||
<section class="donations">
|
||||
<div class="title">
|
||||
<h3>Donation links</h3>
|
||||
<i>— this section is optional</i>
|
||||
</div>
|
||||
</section>
|
||||
-->
|
||||
<m-footer class="footer" centered />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import Multiselect from 'vue-multiselect'
|
||||
|
||||
import MFooter from '@/components/MFooter'
|
||||
import FileInput from '@/components/FileInput'
|
||||
import EthicalAd from '@/components/EthicalAd'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
MFooter,
|
||||
FileInput,
|
||||
EthicalAd,
|
||||
Multiselect,
|
||||
},
|
||||
async asyncData(data) {
|
||||
const [
|
||||
mod,
|
||||
availableCategories,
|
||||
availableLoaders,
|
||||
availableGameVersions,
|
||||
availableLicenses,
|
||||
// availableDonationPlatforms,
|
||||
] = (
|
||||
await Promise.all([
|
||||
axios.get(`https://api.modrinth.com/api/v1/mod/${data.params.id}`),
|
||||
axios.get(`https://api.modrinth.com/api/v1/tag/category`),
|
||||
axios.get(`https://api.modrinth.com/api/v1/tag/loader`),
|
||||
axios.get(`https://api.modrinth.com/api/v1/tag/game_version`),
|
||||
axios.get(`https://api.modrinth.com/api/v1/tag/license`),
|
||||
// axios.get(`https://api.modrinth.com/api/v1/tag/donation_platform`),
|
||||
])
|
||||
).map((it) => it.data)
|
||||
|
||||
mod.license = {
|
||||
short: mod.license.id,
|
||||
name: mod.license.name,
|
||||
}
|
||||
|
||||
const res = await axios.get(mod.body_url)
|
||||
|
||||
return {
|
||||
mod,
|
||||
body: res.data,
|
||||
clientSideType: {
|
||||
label: mod.client_side,
|
||||
id: mod.client_side,
|
||||
},
|
||||
serverSideType: {
|
||||
label: mod.server_side,
|
||||
id: mod.server_side,
|
||||
},
|
||||
availableCategories,
|
||||
availableLoaders,
|
||||
availableGameVersions,
|
||||
availableLicenses,
|
||||
// availableDonationPlatforms,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
previewImage: null,
|
||||
compiledBody: '',
|
||||
|
||||
icon: null,
|
||||
|
||||
sideTypes: [
|
||||
{ label: 'Required', id: 'required' },
|
||||
{ label: 'No functionality', id: 'no-functionality' },
|
||||
{ label: 'Unsupported', id: 'unsupported' },
|
||||
],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
license(newValue, oldValue) {
|
||||
if (newValue == null) {
|
||||
this.license_url = ''
|
||||
return
|
||||
}
|
||||
|
||||
switch (newValue.short) {
|
||||
case 'custom':
|
||||
this.license_url = ''
|
||||
break
|
||||
default:
|
||||
this.license_url = `https://cdn.modrinth.com/licenses/${newValue.short}.txt`
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async saveMod() {
|
||||
this.$nuxt.$loading.start()
|
||||
|
||||
try {
|
||||
await axios.patch(
|
||||
`https://api.modrinth.com/api/v1/mod/${this.mod.id}`,
|
||||
{
|
||||
title: this.mod.title,
|
||||
description: this.mod.description,
|
||||
body: this.body,
|
||||
categories: this.mod.categories,
|
||||
issues_url: this.mod.issues_url,
|
||||
source_url: this.mod.source_url,
|
||||
wiki_url: this.mod.wiki_url,
|
||||
license_url: this.mod.license_url,
|
||||
discord_url: this.mod.discord_url,
|
||||
license_id: this.mod.license.short,
|
||||
client_side: this.clientSideType.id,
|
||||
server_side: this.serverSideType.id,
|
||||
slug: this.mod.mod_slug,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: this.$auth.getToken('local'),
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
await this.$router.replace(`/mod/${this.mod.id}`)
|
||||
} catch (err) {
|
||||
this.$notify({
|
||||
group: 'main',
|
||||
title: 'An Error Occurred',
|
||||
text: err.response.data.description,
|
||||
type: 'error',
|
||||
})
|
||||
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' })
|
||||
}
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
},
|
||||
|
||||
showPreviewImage(e) {
|
||||
const reader = new FileReader()
|
||||
this.icon = e.target.files[0]
|
||||
reader.readAsDataURL(this.icon)
|
||||
|
||||
reader.onload = (event) => {
|
||||
this.previewImage = event.target.result
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.title {
|
||||
* {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
|
||||
span {
|
||||
flex: 2;
|
||||
padding-right: var(--spacing-card-lg);
|
||||
}
|
||||
|
||||
input,
|
||||
.multiselect,
|
||||
.input-group {
|
||||
flex: 3;
|
||||
height: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
.input-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
* {
|
||||
margin-bottom: var(--spacing-card-sm);
|
||||
}
|
||||
}
|
||||
|
||||
.textarea-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
||||
textarea {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
resize: none;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.page-contents {
|
||||
display: grid;
|
||||
grid-template:
|
||||
'header header header' auto
|
||||
'advert advert advert' auto
|
||||
'essentials essentials mod-icon' auto
|
||||
'game-sides game-sides game-sides' auto
|
||||
'description description description' auto
|
||||
'versions versions versions' auto
|
||||
'extra-links license license' auto
|
||||
'donations donations .' auto
|
||||
'footer footer footer' auto
|
||||
/ 4fr 1fr 4fr;
|
||||
column-gap: var(--spacing-card-md);
|
||||
row-gap: var(--spacing-card-md);
|
||||
}
|
||||
|
||||
header {
|
||||
@extend %card;
|
||||
|
||||
grid-area: header;
|
||||
padding: var(--spacing-card-md) var(--spacing-card-lg);
|
||||
|
||||
h2 {
|
||||
margin: auto 0;
|
||||
color: var(--color-text-dark);
|
||||
font-weight: var(--font-weight-extrabold);
|
||||
}
|
||||
|
||||
button {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.advert {
|
||||
grid-area: advert;
|
||||
}
|
||||
|
||||
section {
|
||||
@extend %card;
|
||||
|
||||
padding: var(--spacing-card-md) var(--spacing-card-lg);
|
||||
}
|
||||
|
||||
section.essentials {
|
||||
grid-area: essentials;
|
||||
}
|
||||
|
||||
section.mod-icon {
|
||||
grid-area: mod-icon;
|
||||
|
||||
img {
|
||||
align-self: flex-start;
|
||||
max-width: 50%;
|
||||
margin-left: var(--spacing-card-lg);
|
||||
}
|
||||
}
|
||||
|
||||
section.game-sides {
|
||||
grid-area: game-sides;
|
||||
|
||||
.columns {
|
||||
flex-wrap: wrap;
|
||||
|
||||
span {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.labeled-control {
|
||||
flex: 2;
|
||||
margin-left: var(--spacing-card-lg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section.description {
|
||||
grid-area: description;
|
||||
|
||||
& > .columns {
|
||||
align-items: stretch;
|
||||
min-height: 10rem;
|
||||
max-height: 40rem;
|
||||
|
||||
& > * {
|
||||
flex: 1;
|
||||
max-width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
overflow-y: auto;
|
||||
padding: 0 var(--spacing-card-sm);
|
||||
}
|
||||
}
|
||||
|
||||
section.extra-links {
|
||||
grid-area: extra-links;
|
||||
|
||||
label {
|
||||
align-items: center;
|
||||
margin-top: var(--spacing-card-sm);
|
||||
|
||||
span {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section.license {
|
||||
grid-area: license;
|
||||
|
||||
label {
|
||||
margin-top: var(--spacing-card-sm);
|
||||
}
|
||||
}
|
||||
|
||||
section.donations {
|
||||
grid-area: donations;
|
||||
}
|
||||
|
||||
.footer {
|
||||
grid-area: footer;
|
||||
}
|
||||
|
||||
.choose-image {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -1,14 +1,11 @@
|
||||
<template>
|
||||
<ModPage :mod="mod" :versions="versions" :members="members">
|
||||
<div class="markdown-body" v-html="body"></div>
|
||||
<div v-compiled-markdown="body" class="markdown-body"></div>
|
||||
</ModPage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
import xss from 'xss'
|
||||
import marked from 'marked'
|
||||
import ModPage from '@/components/ModPage'
|
||||
|
||||
export default {
|
||||
@@ -31,17 +28,20 @@ export default {
|
||||
members[i].avatar_url = res.data.avatar_url
|
||||
}
|
||||
|
||||
res = await axios.get(mod.body_url)
|
||||
const body = xss(marked(res.data))
|
||||
const body = (await axios.get(mod.body_url)).data
|
||||
|
||||
const versions = []
|
||||
|
||||
for (const version of mod.versions) {
|
||||
res = await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version/${version}`
|
||||
)
|
||||
|
||||
versions.push(res.data)
|
||||
try {
|
||||
res = await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version/${version}`
|
||||
)
|
||||
versions.push(res.data)
|
||||
} catch {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Some versions may be missing...')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -102,9 +102,9 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.markdown-body {
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 3px 1px var(--color-grey-2);
|
||||
background: var(--color-bg);
|
||||
border-radius: 0 0 var(--size-rounded-sm) var(--size-rounded-sm);
|
||||
padding: 1rem;
|
||||
margin-bottom: var(--spacing-card-md);
|
||||
background: var(--color-raised-bg);
|
||||
border-radius: var(--size-rounded-card);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -31,11 +31,15 @@ export default {
|
||||
const versions = []
|
||||
|
||||
for (const version of mod.versions) {
|
||||
res = await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version/${version}`
|
||||
)
|
||||
|
||||
versions.push(res.data)
|
||||
try {
|
||||
res = await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version/${version}`
|
||||
)
|
||||
versions.push(res.data)
|
||||
} catch {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Some versions may be missing...')
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,109 +1,115 @@
|
||||
<template>
|
||||
<ModPage :mod="mod" :versions="versions" :members="members">
|
||||
<div class="version">
|
||||
<div class="header">
|
||||
<h3>{{ version.name }}</h3>
|
||||
<div
|
||||
v-if="
|
||||
this.$auth.loggedIn &&
|
||||
members.find((x) => x.user_id === this.$auth.user.id)
|
||||
<div class="version-header">
|
||||
<h4>{{ version.name }}</h4>
|
||||
<span v-if="version.version_type === 'release'" class="badge green">
|
||||
Release
|
||||
</span>
|
||||
<span v-if="version.version_type === 'beta'" class="badge yellow">
|
||||
Beta
|
||||
</span>
|
||||
<span v-if="version.version_type === 'alpha'" class="badge red">
|
||||
Alpha
|
||||
</span>
|
||||
<span>
|
||||
{{ version.version_number }}
|
||||
</span>
|
||||
<Categories :categories="version.loaders" />
|
||||
<a
|
||||
:href="primaryFile.url"
|
||||
class="download-button"
|
||||
@click.prevent="
|
||||
downloadFile(primaryFile.hashes.sha1, primaryFile.url)
|
||||
"
|
||||
class="user-actions"
|
||||
>
|
||||
<button class="trash red">
|
||||
<TrashIcon />
|
||||
</button>
|
||||
<button class="upload" @click="showPopup = !showPopup">
|
||||
<UploadIcon />
|
||||
</button>
|
||||
<DownloadIcon />
|
||||
Download
|
||||
</a>
|
||||
</div>
|
||||
<div class="stats">
|
||||
<div class="stat">
|
||||
<DownloadIcon />
|
||||
<div class="info">
|
||||
<h4>Downloads</h4>
|
||||
<p class="value">{{ version.downloads }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<CalendarIcon />
|
||||
<div class="info">
|
||||
<h4>Created</h4>
|
||||
<p
|
||||
v-tooltip="
|
||||
$dayjs(version.published).format(
|
||||
'[Created on] YYYY-MM-DD [at] HH:mm A'
|
||||
)
|
||||
"
|
||||
class="value"
|
||||
>
|
||||
{{ $dayjs(version.published).fromNow() }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<TagIcon />
|
||||
<div class="info">
|
||||
<h4>Available For</h4>
|
||||
<p class="value">
|
||||
{{ version.game_versions.join(', ') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="markdown-body" v-html="changelog"></div>
|
||||
<hr />
|
||||
<div class="columns metadata">
|
||||
<div class="author">
|
||||
<img :src="version.author.avatar_url" />
|
||||
<p>{{ version.author.name }}</p>
|
||||
</div>
|
||||
<p>{{ version.downloads }} Downloads</p>
|
||||
<div>
|
||||
<FabricIcon
|
||||
v-if="version.loaders.includes('fabric')"
|
||||
stroke="#AC6C3A"
|
||||
/>
|
||||
<ForgeIcon
|
||||
v-if="version.loaders.includes('forge')"
|
||||
stroke="#8B81E6"
|
||||
/>
|
||||
</div>
|
||||
<div class="game-versions">
|
||||
<p v-for="gameVersion in version.game_versions" :key="gameVersion">
|
||||
{{ gameVersion }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div v-compiled-markdown="changelog" class="markdown-body"></div>
|
||||
<div class="files">
|
||||
<div v-for="file in version.files" :key="file.hashes.sha1">
|
||||
<p>{{ file.filename }}</p>
|
||||
<a :href="file.url" download>
|
||||
<div class="text-wrapper">
|
||||
<p>{{ file.filename }}</p>
|
||||
<div
|
||||
v-if="
|
||||
$auth.loggedIn &&
|
||||
members.find((x) => x.user_id === $auth.user.id)
|
||||
"
|
||||
class="actions"
|
||||
>
|
||||
<button @click="deleteFile(file.hashes.sha1)">Delete File</button>
|
||||
<button @click="makePrimary(file.hashes.sha1)">
|
||||
Make Primary
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
:href="file.url"
|
||||
@click.prevent="downloadFile(file.hash, file.url)"
|
||||
>
|
||||
<DownloadIcon />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<FileInput class="file-input" @change="addFiles" />
|
||||
</div>
|
||||
<Popup :show-popup="showPopup">
|
||||
<h3 class="popup-title">Upload Files</h3>
|
||||
<FileInput
|
||||
input-id="version-files"
|
||||
input-accept="application/*"
|
||||
default-text="Upload Files"
|
||||
:input-multiple="true"
|
||||
@change="addFiles"
|
||||
>
|
||||
<label class="required" title="The files associated with the version">
|
||||
Version Files
|
||||
</label>
|
||||
</FileInput>
|
||||
<div class="popup-buttons">
|
||||
<button
|
||||
class="trash-button"
|
||||
@click="
|
||||
showPopup = false
|
||||
filesToUpload = []
|
||||
"
|
||||
>
|
||||
<TrashIcon />
|
||||
</button>
|
||||
<button class="default-button" @click="uploadFiles">Upload</button>
|
||||
</div>
|
||||
</Popup>
|
||||
</ModPage>
|
||||
</template>
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
|
||||
import ModPage from '@/components/ModPage'
|
||||
import xss from 'xss'
|
||||
import marked from 'marked'
|
||||
|
||||
import Popup from '@/components/Popup'
|
||||
import Categories from '@/components/Categories'
|
||||
import FileInput from '@/components/FileInput'
|
||||
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
||||
import UploadIcon from '~/assets/images/utils/upload.svg?inline'
|
||||
import TrashIcon from '~/assets/images/utils/trash.svg?inline'
|
||||
|
||||
import ForgeIcon from '~/assets/images/categories/forge.svg?inline'
|
||||
import FabricIcon from '~/assets/images/categories/fabric.svg?inline'
|
||||
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
||||
import TagIcon from '~/assets/images/utils/tag.svg?inline'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Popup,
|
||||
FileInput,
|
||||
Categories,
|
||||
ModPage,
|
||||
ForgeIcon,
|
||||
FabricIcon,
|
||||
DownloadIcon,
|
||||
UploadIcon,
|
||||
TrashIcon,
|
||||
CalendarIcon,
|
||||
TagIcon,
|
||||
},
|
||||
auth: false,
|
||||
async asyncData(data) {
|
||||
@@ -125,11 +131,15 @@ export default {
|
||||
|
||||
const versions = []
|
||||
for (const version of mod.versions) {
|
||||
res = await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version/${version}`
|
||||
)
|
||||
|
||||
versions.push(res.data)
|
||||
try {
|
||||
res = await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version/${version}`
|
||||
)
|
||||
versions.push(res.data)
|
||||
} catch {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Some versions may be missing...')
|
||||
}
|
||||
}
|
||||
|
||||
const version = versions.find((x) => x.id === data.params.version)
|
||||
@@ -138,8 +148,13 @@ export default {
|
||||
|
||||
let changelog = ''
|
||||
if (version.changelog_url) {
|
||||
res = await axios.get(version.changelog_url)
|
||||
changelog = xss(marked(res.data))
|
||||
changelog = (await axios.get(version.changelog_url)).data
|
||||
}
|
||||
|
||||
let primaryFile = version.files.find((file) => file.primary)
|
||||
|
||||
if (!primaryFile) {
|
||||
primaryFile = version.files[0]
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -148,16 +163,55 @@ export default {
|
||||
members,
|
||||
version,
|
||||
changelog,
|
||||
primaryFile,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showPopup: false,
|
||||
filesToUpload: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addFiles(e) {
|
||||
async downloadFile(hash, url) {
|
||||
await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version_file/${hash}/download`
|
||||
)
|
||||
|
||||
const elem = document.createElement('a')
|
||||
elem.download = hash
|
||||
elem.href = url
|
||||
elem.click()
|
||||
},
|
||||
async deleteFile(hash) {
|
||||
const config = {
|
||||
headers: {
|
||||
Authorization: this.$auth.getToken('local'),
|
||||
},
|
||||
}
|
||||
|
||||
await axios.delete(
|
||||
`https://api.modrinth.com/api/v1/version_file/${hash}`,
|
||||
config
|
||||
)
|
||||
},
|
||||
async makePrimary(hash) {
|
||||
const config = {
|
||||
headers: {
|
||||
Authorization: this.$auth.getToken('local'),
|
||||
},
|
||||
}
|
||||
|
||||
await axios.patch(
|
||||
`https://api.modrinth.com/api/v1/version/${this.version.id}`,
|
||||
{
|
||||
primary_file: {
|
||||
sha1: hash,
|
||||
},
|
||||
},
|
||||
config
|
||||
)
|
||||
},
|
||||
async addFiles(e) {
|
||||
this.filesToUpload = e.target.files
|
||||
|
||||
for (let i = 0; i < e.target.files.length; i++) {
|
||||
@@ -165,8 +219,7 @@ export default {
|
||||
'-' + i
|
||||
)
|
||||
}
|
||||
},
|
||||
async uploadFiles() {
|
||||
|
||||
this.$nuxt.$loading.start()
|
||||
|
||||
const formData = new FormData()
|
||||
@@ -254,70 +307,38 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.version {
|
||||
background: var(--color-bg);
|
||||
border-radius: 0 0 0.5rem 0.5rem;
|
||||
box-shadow: 0 2px 3px 1px var(--color-grey-2);
|
||||
padding: 1em;
|
||||
margin-bottom: var(--spacing-card-md);
|
||||
background: var(--color-raised-bg);
|
||||
border-radius: var(--size-rounded-card);
|
||||
padding: 1rem;
|
||||
|
||||
.header {
|
||||
h3 {
|
||||
display: inline-block;
|
||||
}
|
||||
.user-actions {
|
||||
float: right;
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
padding: 5px;
|
||||
border: none;
|
||||
border-radius: var(--size-rounded-sm);
|
||||
}
|
||||
|
||||
.trash {
|
||||
color: #9b2c2c;
|
||||
background-color: var(--color-bg);
|
||||
}
|
||||
|
||||
.upload {
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-grey-1);
|
||||
* {
|
||||
margin: auto 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 20px 0;
|
||||
color: var(--color-grey-1);
|
||||
}
|
||||
|
||||
.metadata {
|
||||
.version-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.author {
|
||||
h4,
|
||||
span {
|
||||
margin: auto 0.5rem auto 0;
|
||||
}
|
||||
|
||||
.download-button {
|
||||
margin-left: auto;
|
||||
padding: 0.5rem;
|
||||
color: var(--color-button-text);
|
||||
background-color: var(--color-button-bg);
|
||||
justify-self: flex-end;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
img {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
border-radius: var(--size-rounded-sm);
|
||||
|
||||
.game-versions {
|
||||
max-width: 200px;
|
||||
p {
|
||||
margin: 0 0 0 10px;
|
||||
padding: 4px;
|
||||
font-size: 15px;
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-grey-1);
|
||||
display: inline-block;
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--color-button-bg-hover);
|
||||
}
|
||||
|
||||
svg {
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,71 +347,77 @@ export default {
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
margin-right: 10px;
|
||||
border: 1px solid var(--color-grey-1);
|
||||
border-radius: var(--size-rounded-sm);
|
||||
margin-right: 0.5rem;
|
||||
background: var(--color-bg);
|
||||
border-radius: var(--size-rounded-control);
|
||||
|
||||
p {
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
.text-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0.5rem;
|
||||
|
||||
.actions {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
max-height: 3rem;
|
||||
font-size: var(--font-size-sm);
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
display: table-cell;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
width: 40px;
|
||||
height: 60px;
|
||||
background-color: var(--color-grey-1);
|
||||
color: var(--color-grey-3);
|
||||
width: 2.5rem;
|
||||
height: auto;
|
||||
background-color: var(--color-button-bg);
|
||||
color: var(--color-button-text);
|
||||
border-radius: 0 var(--size-rounded-control) var(--size-rounded-control)
|
||||
0;
|
||||
|
||||
svg {
|
||||
margin-top: 15px;
|
||||
vertical-align: center;
|
||||
height: 30px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: var(--color-grey-3);
|
||||
color: var(--color-grey-4);
|
||||
background-color: var(--color-button-bg-hover);
|
||||
color: var(--color-button-text-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.popup-buttons {
|
||||
margin-top: 40px;
|
||||
.stats {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
margin: 0.5rem 0;
|
||||
.stat {
|
||||
margin-right: 0.75rem;
|
||||
@extend %stat;
|
||||
|
||||
.default-button {
|
||||
border-radius: var(--size-rounded-sm);
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
padding: 10px;
|
||||
background-color: var(--color-grey-1);
|
||||
color: var(--color-grey-5);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--color-grey-4);
|
||||
svg {
|
||||
padding: 0.25rem;
|
||||
border-radius: 50%;
|
||||
background-color: var(--color-button-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.trash-button {
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
padding: 5px;
|
||||
border: none;
|
||||
border-radius: var(--size-rounded-sm);
|
||||
color: #9b2c2c;
|
||||
background-color: var(--color-bg);
|
||||
}
|
||||
.file-input {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,20 +5,29 @@
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Name</th>
|
||||
<th>Number</th>
|
||||
<th>Loaders</th>
|
||||
<th>Game Versions</th>
|
||||
<th>Version</th>
|
||||
<th>Mod Loader</th>
|
||||
<th>Minecraft Version</th>
|
||||
<th>Status</th>
|
||||
<th>Downloads</th>
|
||||
<th>Published</th>
|
||||
<th>Date Published</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="version in versions" :key="version.id">
|
||||
<td>
|
||||
<nuxt-link :to="'/mod/' + mod.id + '/version/' + version.id">
|
||||
<a
|
||||
:href="findPrimary(version).url"
|
||||
class="download"
|
||||
@click.prevent="
|
||||
downloadFile(
|
||||
findPrimary(version).hashes.sha1,
|
||||
findPrimary(version).url
|
||||
)
|
||||
"
|
||||
>
|
||||
<DownloadIcon />
|
||||
</nuxt-link>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<nuxt-link :to="'/mod/' + mod.id + '/version/' + version.id">
|
||||
@@ -27,14 +36,8 @@
|
||||
</td>
|
||||
<td>{{ version.version_number }}</td>
|
||||
<td>
|
||||
<FabricIcon
|
||||
v-if="version.loaders.includes('fabric')"
|
||||
stroke="#AC6C3A"
|
||||
/>
|
||||
<ForgeIcon
|
||||
v-if="version.loaders.includes('forge')"
|
||||
stroke="#8B81E6"
|
||||
/>
|
||||
<FabricIcon v-if="version.loaders.includes('fabric')" />
|
||||
<ForgeIcon v-if="version.loaders.includes('forge')" />
|
||||
</td>
|
||||
<td>{{ version.game_versions.join(', ') }}</td>
|
||||
<td>
|
||||
@@ -62,10 +65,6 @@
|
||||
class="create-version-popup-body"
|
||||
>
|
||||
<h3>New Version</h3>
|
||||
<div v-if="currentError" class="error">
|
||||
<h4>Error</h4>
|
||||
<p>{{ currentError }}</p>
|
||||
</div>
|
||||
<label
|
||||
for="version-title"
|
||||
class="required"
|
||||
@@ -110,7 +109,7 @@
|
||||
<label
|
||||
title="The version number of this version. Preferably following semantic versioning"
|
||||
>
|
||||
Loaders
|
||||
Mod Loaders
|
||||
</label>
|
||||
<multiselect
|
||||
v-model="createdVersion.loaders"
|
||||
@@ -128,7 +127,7 @@
|
||||
placeholder="Choose loaders..."
|
||||
/>
|
||||
<label title="The versions of minecraft that this mod version supports">
|
||||
Game Versions
|
||||
Minecraft Versions
|
||||
</label>
|
||||
<multiselect
|
||||
v-model="createdVersion.game_versions"
|
||||
@@ -155,7 +154,7 @@
|
||||
/>
|
||||
<FileInput
|
||||
input-id="version-files"
|
||||
input-accept="application/java-archive,application/zip"
|
||||
accept="application/java-archive,application/zip"
|
||||
default-text="Upload Files"
|
||||
:input-multiple="true"
|
||||
@change="updateVersionFiles"
|
||||
@@ -237,11 +236,15 @@ export default {
|
||||
|
||||
const versions = []
|
||||
for (const version of mod.versions) {
|
||||
res = await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version/${version}`
|
||||
)
|
||||
|
||||
versions.push(res.data)
|
||||
try {
|
||||
res = await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version/${version}`
|
||||
)
|
||||
versions.push(res.data)
|
||||
} catch {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Some versions may be missing...')
|
||||
}
|
||||
}
|
||||
|
||||
res = await axios.get(`https://api.modrinth.com/api/v1/tag/loader`)
|
||||
@@ -320,6 +323,29 @@ export default {
|
||||
|
||||
this.$nuxt.$loading.finish()
|
||||
},
|
||||
findPrimary(version) {
|
||||
let file = version.files.find((x) => x.primary)
|
||||
|
||||
if (!file) {
|
||||
file = version.files[0]
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
file = { url: `/mod/${this.mod.id}/version/${version.id}` }
|
||||
}
|
||||
|
||||
return file
|
||||
},
|
||||
async downloadFile(hash, url) {
|
||||
await axios.get(
|
||||
`https://api.modrinth.com/api/v1/version_file/${hash}/download`
|
||||
)
|
||||
|
||||
const elem = document.createElement('a')
|
||||
elem.download = hash
|
||||
elem.href = url
|
||||
elem.click()
|
||||
},
|
||||
},
|
||||
head() {
|
||||
return {
|
||||
@@ -368,10 +394,10 @@ export default {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
table {
|
||||
background: var(--color-bg);
|
||||
border-collapse: collapse;
|
||||
border-radius: 0 0 0.5rem 0.5rem;
|
||||
box-shadow: 0 2px 3px 1px var(--color-grey-2);
|
||||
margin-bottom: var(--spacing-card-md);
|
||||
background: var(--color-raised-bg);
|
||||
border-radius: var(--size-rounded-card);
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
|
||||
@@ -383,7 +409,7 @@ table {
|
||||
tr:first-child {
|
||||
th,
|
||||
td {
|
||||
border-bottom: 1px solid var(--color-grey-2);
|
||||
border-bottom: 1px solid var(--color-divider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -391,14 +417,14 @@ table {
|
||||
td {
|
||||
&:first-child {
|
||||
text-align: center;
|
||||
width: 5%;
|
||||
width: 7%;
|
||||
|
||||
svg {
|
||||
color: var(--color-grey-3);
|
||||
color: var(--color-text);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--color-grey-5);
|
||||
color: var(--color-text-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -406,23 +432,23 @@ table {
|
||||
&:nth-child(2),
|
||||
&:nth-child(5) {
|
||||
padding-left: 0;
|
||||
width: 15%;
|
||||
width: 12%;
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
color: #718096;
|
||||
color: var(--color-heading);
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.02rem;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 1.5rem;
|
||||
padding: 1rem 1rem;
|
||||
padding: 0.75rem 1rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
td {
|
||||
overflow: hidden;
|
||||
padding: 0.25rem 1rem;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
img {
|
||||
height: 3rem;
|
||||
@@ -448,7 +474,7 @@ input {
|
||||
outline: none;
|
||||
border: none;
|
||||
margin: 10px 0 30px;
|
||||
background-color: var(--color-grey-1);
|
||||
background-color: var(--color-button-bg);
|
||||
color: var(--color-text);
|
||||
font-family: monospace;
|
||||
}
|
||||
@@ -482,21 +508,15 @@ input {
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
padding: 10px;
|
||||
background-color: var(--color-grey-1);
|
||||
color: var(--color-grey-5);
|
||||
background-color: var(--color-button-bg);
|
||||
color: var(--color-button-text);
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: var(--color-grey-4);
|
||||
background-color: var(--color-button-bg-hover);
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
margin: 20px 0;
|
||||
border-left: #e04e3e 7px solid;
|
||||
padding: 5px 20px 20px 20px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
th,
|
||||
td {
|
||||
|
||||
1159
pages/mod/create.vue
755
pages/mods.vue
@@ -1,276 +1,294 @@
|
||||
<template>
|
||||
<div class="columns">
|
||||
<div class="content column-grow-5">
|
||||
<h2>Mods</h2>
|
||||
<section class="search-bar">
|
||||
<div class="iconified-input column-grow-2">
|
||||
<label class="hidden" for="search">Search Mods</label>
|
||||
<input
|
||||
id="search"
|
||||
v-model="query"
|
||||
type="search"
|
||||
name="search"
|
||||
placeholder="Search mods"
|
||||
@input="onSearchChange(1)"
|
||||
<div class="page-container">
|
||||
<div class="page-contents">
|
||||
<div class="content">
|
||||
<section class="search-nav">
|
||||
<div class="iconified-input column-grow-2">
|
||||
<label class="hidden" for="search">Search Mods</label>
|
||||
<input
|
||||
id="search"
|
||||
v-model="query"
|
||||
type="search"
|
||||
name="search"
|
||||
placeholder="Search..."
|
||||
autocomplete="off"
|
||||
@input="onSearchChange(1)"
|
||||
/>
|
||||
<SearchIcon />
|
||||
</div>
|
||||
<div class="sort-paginate">
|
||||
<div class="labeled-control">
|
||||
<h3>Sort By</h3>
|
||||
<Multiselect
|
||||
v-model="sortType"
|
||||
class="sort-types"
|
||||
placeholder="Select one"
|
||||
track-by="display"
|
||||
label="display"
|
||||
:options="sortTypes"
|
||||
:searchable="false"
|
||||
:close-on-select="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="false"
|
||||
@input="onSearchChange(1)"
|
||||
>
|
||||
<template slot="singleLabel" slot-scope="{ option }">{{
|
||||
option.display
|
||||
}}</template>
|
||||
</Multiselect>
|
||||
</div>
|
||||
<div class="labeled-control per-page">
|
||||
<h3>Per Page</h3>
|
||||
<Multiselect
|
||||
v-model="maxResults"
|
||||
class="max-results"
|
||||
placeholder="Select one"
|
||||
:options="[5, 10, 15, 20, 50, 100]"
|
||||
:searchable="false"
|
||||
:close-on-select="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="false"
|
||||
@input="onSearchChange(currentPage)"
|
||||
>
|
||||
</Multiselect>
|
||||
</div>
|
||||
<div class="mobile-filters-button">
|
||||
<button @click="toggleFiltersMenu">Filter</button>
|
||||
</div>
|
||||
</div>
|
||||
<pagination
|
||||
:current-page="currentPage"
|
||||
:pages="pages"
|
||||
@switch-page="onSearchChange"
|
||||
></pagination>
|
||||
</section>
|
||||
<div class="results column-grow-4">
|
||||
<client-only>
|
||||
<EthicalAd type="text" />
|
||||
</client-only>
|
||||
<SearchResult
|
||||
v-for="(result, index) in results"
|
||||
:id="result.mod_id.split('-')[1]"
|
||||
:key="result.mod_id"
|
||||
:author="result.author"
|
||||
:name="result.title"
|
||||
:description="result.description"
|
||||
:latest-version="result.latest_version"
|
||||
:created-at="result.date_created"
|
||||
:updated-at="result.date_modified"
|
||||
:downloads="result.downloads.toString()"
|
||||
:icon-url="result.icon_url"
|
||||
:author-url="result.author_url"
|
||||
:page-url="result.page_url"
|
||||
:categories="result.categories"
|
||||
:is-ad="index === -1"
|
||||
:is-modrinth="result.host === 'modrinth'"
|
||||
/>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="11" cy="11" r="8" />
|
||||
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="sort-paginate">
|
||||
<Multiselect
|
||||
v-model="sortType"
|
||||
class="sort-types"
|
||||
placeholder="Select one"
|
||||
track-by="display"
|
||||
label="display"
|
||||
:options="sortTypes"
|
||||
:searchable="false"
|
||||
:close-on-select="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="false"
|
||||
@input="onSearchChange(1)"
|
||||
>
|
||||
<template slot="singleLabel" slot-scope="{ option }">{{
|
||||
option.display
|
||||
}}</template>
|
||||
</Multiselect>
|
||||
<div class="mobile-filters-button">
|
||||
<button @click="toggleFiltersMenu">Filter...</button>
|
||||
<div v-if="results.length === 0" class="no-results">
|
||||
<p>No results found for your query!</p>
|
||||
</div>
|
||||
</div>
|
||||
<pagination
|
||||
:current-page="currentPage"
|
||||
:pages="pages"
|
||||
@switch-page="onSearchChange"
|
||||
></pagination>
|
||||
</section>
|
||||
<div class="results column-grow-4">
|
||||
<client-only>
|
||||
<EthicalAd type="text" />
|
||||
</client-only>
|
||||
<SearchResult
|
||||
v-for="(result, index) in results"
|
||||
:id="result.mod_id"
|
||||
:key="result.mod_id"
|
||||
:author="result.author"
|
||||
:name="result.title"
|
||||
:description="result.description"
|
||||
:latest-version="result.latest_version"
|
||||
:created-at="result.date_created"
|
||||
:updated-at="result.date_modified"
|
||||
:downloads="result.downloads.toString()"
|
||||
:icon-url="result.icon_url"
|
||||
:author-url="result.author_url"
|
||||
:page-url="result.page_url"
|
||||
:categories="result.categories"
|
||||
:is-ad="index === -1"
|
||||
/>
|
||||
<div v-if="results.length === 0" class="no-results">
|
||||
<p>No results found for your query!</p>
|
||||
</div>
|
||||
<section v-if="pages.length > 1" class="search-bottom">
|
||||
<div class="labeled-control">
|
||||
<h3>Per Page</h3>
|
||||
<Multiselect
|
||||
v-model="maxResults"
|
||||
class="max-results"
|
||||
placeholder="Select one"
|
||||
:options="[5, 10, 15, 20, 50, 100]"
|
||||
:searchable="false"
|
||||
:close-on-select="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="false"
|
||||
@input="onSearchChange(currentPage)"
|
||||
>
|
||||
</Multiselect>
|
||||
</div>
|
||||
<pagination
|
||||
:current-page="currentPage"
|
||||
:pages="pages"
|
||||
@switch-page="onSearchChangeToTop"
|
||||
></pagination>
|
||||
</section>
|
||||
</div>
|
||||
<section v-if="pages.length > 1" class="search-bottom">
|
||||
<Multiselect
|
||||
v-model="maxResults"
|
||||
class="max-results"
|
||||
placeholder="Select one"
|
||||
:options="[5, 10, 15, 20, 50, 100]"
|
||||
:searchable="false"
|
||||
:close-on-select="true"
|
||||
:show-labels="false"
|
||||
:allow-empty="false"
|
||||
@input="onSearchChange(currentPage)"
|
||||
>
|
||||
</Multiselect>
|
||||
<pagination
|
||||
:current-page="currentPage"
|
||||
:pages="pages"
|
||||
@switch-page="onSearchChangeToTop"
|
||||
></pagination>
|
||||
<section id="filters" class="filters">
|
||||
<div class="filters-wrapper">
|
||||
<section class="filter-group">
|
||||
<button class="filter-button-done" @click="toggleFiltersMenu">
|
||||
Done
|
||||
</button>
|
||||
<button @click="clearFilters">Reset filters</button>
|
||||
<h3>Categories</h3>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Technology"
|
||||
facet-name="categories:technology"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<TechCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Adventure"
|
||||
facet-name="categories:adventure"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<AdventureCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Magic"
|
||||
facet-name="categories:magic"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<MagicCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Utility"
|
||||
facet-name="categories:utility"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<UtilityCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Decoration"
|
||||
facet-name="categories:decoration"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<DecorationCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Library"
|
||||
facet-name="categories:library"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<LibraryCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Cursed"
|
||||
facet-name="categories:cursed"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<CursedCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="World Generation"
|
||||
facet-name="categories:worldgen"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<WorldGenCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Storage"
|
||||
facet-name="categories:storage"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<StorageCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Food"
|
||||
facet-name="categories:food"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<FoodCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Equipment"
|
||||
facet-name="categories:equipment"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<EquipmentCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Miscellaneous"
|
||||
facet-name="categories:misc"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<MiscCategory />
|
||||
</SearchFilter>
|
||||
<h3>Mod Loaders</h3>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Fabric"
|
||||
facet-name="categories:fabric"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<FabricLoader />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Forge"
|
||||
facet-name="categories:forge"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<ForgeLoader />
|
||||
</SearchFilter>
|
||||
<h3>Host</h3>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Modrinth"
|
||||
facet-name="host:modrinth"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<Modrinth />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="CurseForge"
|
||||
facet-name="host:curseforge"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<FlameAnvil />
|
||||
</SearchFilter>
|
||||
<h3>Versions</h3>
|
||||
<SearchFilter
|
||||
:active-filters="showVersions"
|
||||
display-name="Include snapshots"
|
||||
facet-name="snapshots"
|
||||
style="margin-bottom: 10px"
|
||||
@toggle="fillInitialVersions"
|
||||
/>
|
||||
</section>
|
||||
<multiselect
|
||||
v-model="selectedVersions"
|
||||
:options="versions"
|
||||
:loading="versions.length === 0"
|
||||
:multiple="true"
|
||||
:searchable="true"
|
||||
:show-no-results="false"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:show-labels="false"
|
||||
:limit="6"
|
||||
:hide-selected="true"
|
||||
placeholder="Choose versions..."
|
||||
@input="onSearchChange(1)"
|
||||
></multiselect>
|
||||
</div>
|
||||
<m-footer class="footer" />
|
||||
</section>
|
||||
</div>
|
||||
<section id="filters" class="filters">
|
||||
<div class="filters-wrapper">
|
||||
<section class="filter-group">
|
||||
<button class="filter-button-done" @click="toggleFiltersMenu">
|
||||
Done
|
||||
</button>
|
||||
<button @click="clearFilters">Clear Filters</button>
|
||||
<h3>Categories</h3>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Technology"
|
||||
facet-name="categories:technology"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<TechCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Adventure"
|
||||
facet-name="categories:adventure"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<AdventureCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Magic"
|
||||
facet-name="categories:magic"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<MagicCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Utility"
|
||||
facet-name="categories:utility"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<UtilityCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Decoration"
|
||||
facet-name="categories:decoration"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<DecorationCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Library"
|
||||
facet-name="categories:library"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<LibraryCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Cursed"
|
||||
facet-name="categories:cursed"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<CursedCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Worldgen"
|
||||
facet-name="categories:worldgen"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<WorldGenCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Storage"
|
||||
facet-name="categories:storage"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<StorageCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Food"
|
||||
facet-name="categories:food"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<FoodCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Equipment"
|
||||
facet-name="categories:equipment"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<EquipmentCategory />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Misc"
|
||||
facet-name="categories:misc"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<MiscCategory />
|
||||
</SearchFilter>
|
||||
<h3>Loaders</h3>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Forge"
|
||||
facet-name="categories:forge"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<ForgeLoader />
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Fabric"
|
||||
facet-name="categories:fabric"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
<FabricLoader />
|
||||
</SearchFilter>
|
||||
<h3>Platforms</h3>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Modrinth"
|
||||
facet-name="host:modrinth"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
</SearchFilter>
|
||||
<SearchFilter
|
||||
:active-filters="facets"
|
||||
display-name="Curseforge"
|
||||
facet-name="host:curseforge"
|
||||
@toggle="toggleFacet"
|
||||
>
|
||||
</SearchFilter>
|
||||
<h3>Versions</h3>
|
||||
<SearchFilter
|
||||
:active-filters="showVersions"
|
||||
display-name="Snapshots"
|
||||
facet-name="snapshots"
|
||||
style="margin-bottom: 10px"
|
||||
@toggle="fillInitialVersions"
|
||||
/>
|
||||
</section>
|
||||
<multiselect
|
||||
v-model="selectedVersions"
|
||||
:options="versions"
|
||||
:loading="versions.length === 0"
|
||||
:multiple="true"
|
||||
:searchable="true"
|
||||
:show-no-results="false"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:show-labels="false"
|
||||
:limit="6"
|
||||
:hide-selected="true"
|
||||
placeholder="Choose versions..."
|
||||
@input="onSearchChange(1)"
|
||||
></multiselect>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Multiselect from 'vue-multiselect'
|
||||
import axios from 'axios'
|
||||
import SearchResult from '@/components/ModResult'
|
||||
import SearchResult from '@/components/ProjectCard'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import SearchFilter from '@/components/SearchFilter'
|
||||
|
||||
import EthicalAd from '@/components/EthicalAd'
|
||||
import MFooter from '@/components/MFooter'
|
||||
import TechCategory from '~/assets/images/categories/tech.svg?inline'
|
||||
import AdventureCategory from '~/assets/images/categories/adventure.svg?inline'
|
||||
import CursedCategory from '~/assets/images/categories/cursed.svg?inline'
|
||||
@@ -287,9 +305,15 @@ import WorldGenCategory from '~/assets/images/categories/worldgen.svg?inline'
|
||||
import ForgeLoader from '~/assets/images/categories/forge.svg?inline'
|
||||
import FabricLoader from '~/assets/images/categories/fabric.svg?inline'
|
||||
|
||||
import Modrinth from '~/assets/images/categories/modrinth.svg?inline'
|
||||
import FlameAnvil from '~/assets/images/categories/flameanvil.svg?inline'
|
||||
|
||||
import SearchIcon from '~/assets/images/utils/search.svg?inline'
|
||||
|
||||
export default {
|
||||
auth: false,
|
||||
components: {
|
||||
MFooter,
|
||||
EthicalAd,
|
||||
SearchResult,
|
||||
Pagination,
|
||||
@@ -309,6 +333,9 @@ export default {
|
||||
WorldGenCategory,
|
||||
ForgeLoader,
|
||||
FabricLoader,
|
||||
Modrinth,
|
||||
FlameAnvil,
|
||||
SearchIcon,
|
||||
},
|
||||
async fetch() {
|
||||
if (this.$route.query.q) this.query = this.$route.query.q
|
||||
@@ -345,12 +372,12 @@ export default {
|
||||
currentPage: 1,
|
||||
sortTypes: [
|
||||
{ display: 'Relevance', name: 'relevance' },
|
||||
{ display: 'Total Downloads', name: 'downloads' },
|
||||
{ display: 'Newest', name: 'newest' },
|
||||
{ display: 'Updated', name: 'updated' },
|
||||
{ display: 'Download count', name: 'downloads' },
|
||||
{ display: 'Recently created', name: 'newest' },
|
||||
{ display: 'Recently updated', name: 'updated' },
|
||||
],
|
||||
sortType: { display: 'Relevance', name: 'relevance' },
|
||||
maxResults: 5,
|
||||
maxResults: 20,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -482,7 +509,7 @@ export default {
|
||||
url += `&v=${encodeURIComponent(this.selectedVersions)}`
|
||||
if (this.sortType.name !== 'relevance')
|
||||
url += `&s=${encodeURIComponent(this.sortType.name)}`
|
||||
if (this.maxResults > 5)
|
||||
if (this.maxResults > 20)
|
||||
url += `&m=${encodeURIComponent(this.maxResults)}`
|
||||
|
||||
window.history.pushState(new Date(), 'Mods', url)
|
||||
@@ -525,17 +552,32 @@ export default {
|
||||
|
||||
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
|
||||
<style lang="scss">
|
||||
.search-bar {
|
||||
.search-nav {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-flow: column;
|
||||
background: var(--color-raised-bg);
|
||||
border-radius: var(--size-rounded-card);
|
||||
padding: 0.25rem 1rem 0.25rem 1rem;
|
||||
margin-bottom: var(--spacing-card-md);
|
||||
input {
|
||||
border: none;
|
||||
background: transparent;
|
||||
min-width: 200px;
|
||||
}
|
||||
.iconified-input {
|
||||
width: 100%;
|
||||
}
|
||||
.sort-paginate {
|
||||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
.per-page {
|
||||
margin-left: 0.5rem;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 900px) {
|
||||
flex-flow: row;
|
||||
@@ -543,34 +585,45 @@ export default {
|
||||
width: auto;
|
||||
}
|
||||
.sort-paginate {
|
||||
display: block;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1024px) {
|
||||
.sort-paginate {
|
||||
.per-page {
|
||||
display: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-bottom {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
background: var(--color-raised-bg);
|
||||
border-radius: var(--size-rounded-card);
|
||||
padding: 0.25rem 1rem 0.25rem 1rem;
|
||||
select {
|
||||
width: 100px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
min-height: 96vh;
|
||||
.labeled-control {
|
||||
h3 {
|
||||
@extend %small-label;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-filters-button {
|
||||
display: inline-block;
|
||||
button {
|
||||
background: var(--color-bg);
|
||||
color: var(--color-text);
|
||||
border: 2px solid var(--color-grey-3);
|
||||
border-radius: var(--size-rounded-sm);
|
||||
padding: 0.5rem;
|
||||
margin-top: 0;
|
||||
height: 2.5rem;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
// Hide button on larger screens where it's not needed
|
||||
@@ -581,48 +634,47 @@ export default {
|
||||
|
||||
.filters {
|
||||
overflow-y: auto;
|
||||
background-color: var(--color-bg);
|
||||
border-left: 1px solid var(--color-grey-2);
|
||||
position: fixed;
|
||||
width: 100vw;
|
||||
right: -100vw;
|
||||
max-height: 100vh;
|
||||
min-width: 15%;
|
||||
top: 3.5rem;
|
||||
height: calc(100vh - 3.5rem);
|
||||
top: var(--size-navbar-height);
|
||||
height: calc(100vh - var(--size-navbar-height));
|
||||
transition: right 150ms;
|
||||
background-color: var(--color-raised-bg);
|
||||
flex-shrink: 0; // Stop shrinking when page contents change
|
||||
|
||||
.filters-wrapper {
|
||||
padding: 0 0.75rem;
|
||||
padding: 0.25rem 0.75rem 0.75rem 0.75rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: #718096;
|
||||
font-size: 0.8rem;
|
||||
letter-spacing: 0.02rem;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 1.5rem;
|
||||
text-transform: uppercase;
|
||||
@extend %large-label;
|
||||
margin-top: 1.25em;
|
||||
}
|
||||
|
||||
// Larger screens that don't need to collapse
|
||||
@media screen and (min-width: 900px) {
|
||||
position: sticky;
|
||||
width: 215px;
|
||||
padding-right: 1rem;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
// Desktop
|
||||
@media screen and (min-width: 1145px) {
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
&.active {
|
||||
right: 0;
|
||||
}
|
||||
// Larger screens that don't need to collapse
|
||||
@media screen and (min-width: 900px) {
|
||||
top: 0;
|
||||
right: auto;
|
||||
position: unset;
|
||||
height: unset;
|
||||
max-height: unset;
|
||||
transition: none;
|
||||
margin-left: var(--spacing-card-lg);
|
||||
overflow-y: unset;
|
||||
padding-right: 1rem;
|
||||
width: 18vw;
|
||||
background-color: transparent;
|
||||
.filters-wrapper {
|
||||
background-color: var(--color-raised-bg);
|
||||
border-radius: var(--size-rounded-card);
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1024px) {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-group {
|
||||
@@ -631,17 +683,6 @@ export default {
|
||||
button {
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
padding: 5px 0;
|
||||
outline: none;
|
||||
color: var(--color-grey-5);
|
||||
background-color: var(--color-grey-1);
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-grey-2);
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
|
||||
.filter-button-done {
|
||||
@@ -654,65 +695,12 @@ export default {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Desktop
|
||||
@media screen and (min-width: 1145px) {
|
||||
margin-top: 2em;
|
||||
}
|
||||
}
|
||||
|
||||
.iconified-select {
|
||||
margin-left: 1em;
|
||||
align-items: center;
|
||||
display: inline-flex;
|
||||
flex-direction: row-reverse;
|
||||
|
||||
select {
|
||||
padding-left: 2.5rem;
|
||||
|
||||
&:hover {
|
||||
& + svg {
|
||||
color: var(--color-grey-6);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
& + svg {
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
color: var(--color-grey-5);
|
||||
margin-right: -2rem;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
width: 220px;
|
||||
padding: 0.5rem 1rem;
|
||||
background: var(--color-bg);
|
||||
border: 2px solid var(--color-grey-3);
|
||||
border-radius: var(--size-rounded-sm);
|
||||
color: var(--color-grey-9);
|
||||
font-size: 1rem;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--color-grey-4);
|
||||
color: var(--color-text);
|
||||
}
|
||||
}
|
||||
|
||||
.sort-types {
|
||||
min-width: 200px;
|
||||
border: 2px solid var(--color-grey-3);
|
||||
border-radius: var(--size-rounded-sm);
|
||||
border: none;
|
||||
border-radius: var(--size-rounded-control);
|
||||
|
||||
.multiselect__tags {
|
||||
padding: 10px 50px 0 8px;
|
||||
@@ -723,45 +711,14 @@ select {
|
||||
.no-results {
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
font-size: 30px;
|
||||
font-size: 1.25rem;
|
||||
color: var(--color-text);
|
||||
background-color: var(--color-grey-1);
|
||||
margin-bottom: var(--spacing-card-md);
|
||||
background: var(--color-raised-bg);
|
||||
border-radius: var(--size-rounded-card);
|
||||
}
|
||||
|
||||
.max-results {
|
||||
max-width: 80px;
|
||||
}
|
||||
|
||||
.multiselect__content-wrapper {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.multiselect__tags {
|
||||
border: 2px solid var(--color-grey-3);
|
||||
border-radius: var(--size-rounded-sm);
|
||||
}
|
||||
|
||||
.multiselect__tags,
|
||||
.multiselect__spinner {
|
||||
background: var(--color-bg);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.multiselect__spinner::before,
|
||||
.multiselect__spinner::after {
|
||||
border-top-color: var(--color-brand);
|
||||
}
|
||||
|
||||
.multiselect__option--selected.multiselect__option--highlight,
|
||||
.multiselect__option,
|
||||
.multiselect__single,
|
||||
.multiselect__input {
|
||||
color: var(--color-text);
|
||||
background: var(--color-bg);
|
||||
}
|
||||
|
||||
.multiselect__option--highlight,
|
||||
.multiselect__tag {
|
||||
background: var(--color-brand);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,178 +0,0 @@
|
||||
<template>
|
||||
<div class="main">
|
||||
<h1>Privacy Policy</h1>
|
||||
|
||||
<p>
|
||||
At Modrinth, accessible from https://modrinth.com, one of our main
|
||||
priorities is the privacy of our visitors. This Privacy Policy document
|
||||
contains types of information that is collected and recorded by Modrinth
|
||||
and how we use it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If you have additional questions or require more information about our
|
||||
Privacy Policy, do not hesitate to contact us.
|
||||
</p>
|
||||
|
||||
<h2>Log Files</h2>
|
||||
|
||||
<p>
|
||||
Modrinth follows a standard procedure of using log files. These files log
|
||||
visitors when they visit websites. All hosting companies do this and a
|
||||
part of hosting services' analytics. The information collected by log
|
||||
files include internet protocol (IP) addresses, browser type, Internet
|
||||
Service Provider (ISP), date and time stamp, referring/exit pages, and
|
||||
possibly the number of clicks. These are not linked to any information
|
||||
that is personally identifiable. The purpose of the information is for
|
||||
analyzing trends, administering the site, tracking users' movement on the
|
||||
website, and gathering demographic information.
|
||||
</p>
|
||||
|
||||
<h2>Cookies and Web Beacons</h2>
|
||||
|
||||
<p>
|
||||
Like any other website, Modrinth uses 'cookies'. These cookies are used to
|
||||
store information including visitors' preferences, and the pages on the
|
||||
website that the visitor accessed or visited. The information is used to
|
||||
optimize the users' experience by customizing our web page content based
|
||||
on visitors' browser type and/or other information.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
For more general information on cookies, please read
|
||||
<a href="https://www.privacypolicies.com/blog/cookies/"
|
||||
>"What Are Cookies"</a
|
||||
>.
|
||||
</p>
|
||||
|
||||
<h2>Our Advertising Partners</h2>
|
||||
|
||||
<p>
|
||||
Some of advertisers on our site may use cookies and web beacons. Our
|
||||
advertising partners are listed below. Each of our advertising partners
|
||||
has their own Privacy Policy for their policies on user data. For easier
|
||||
access, we hyperlinked to their Privacy Policies below.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<p>EthicalAds</p>
|
||||
<p>
|
||||
<a href="https://www.ethicalads.io/privacy-policy/"
|
||||
>https://www.ethicalads.io/privacy-policy/</a
|
||||
>
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Privacy Policies</h2>
|
||||
|
||||
<P
|
||||
>You may consult this list to find the Privacy Policy for each of the
|
||||
advertising partners of Modrinth.</P
|
||||
>
|
||||
|
||||
<p>
|
||||
Third-party ad servers or ad networks uses technologies like cookies,
|
||||
JavaScript, or Web Beacons that are used in their respective
|
||||
advertisements and links that appear on Modrinth, which are sent directly
|
||||
to users' browser. They automatically receive your IP address when this
|
||||
occurs. These technologies are used to measure the effectiveness of their
|
||||
advertising campaigns and/or to personalize the advertising content that
|
||||
you see on websites that you visit.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Note that Modrinth has no access to or control over these cookies that are
|
||||
used by third-party advertisers.
|
||||
</p>
|
||||
|
||||
<h2>Third Party Privacy Policies</h2>
|
||||
|
||||
<p>
|
||||
Modrinth's Privacy Policy does not apply to other advertisers or websites.
|
||||
Thus, we are advising you to consult the respective Privacy Policies of
|
||||
these third-party ad servers for more detailed information. It may include
|
||||
their practices and instructions about how to opt-out of certain options.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You can choose to disable cookies through your individual browser options.
|
||||
To know more detailed information about cookie management with specific
|
||||
web browsers, it can be found at the browsers' respective websites. What
|
||||
Are Cookies?
|
||||
</p>
|
||||
|
||||
<h2>Children's Information</h2>
|
||||
|
||||
<p>
|
||||
Another part of our priority is adding protection for children while using
|
||||
the internet. We encourage parents and guardians to observe, participate
|
||||
in, and/or monitor and guide their online activity.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Modrinth does not knowingly collect any Personal Identifiable Information
|
||||
from children under the age of 13. If you think that your child provided
|
||||
this kind of information on our website, we strongly encourage you to
|
||||
contact us immediately and we will do our best efforts to promptly remove
|
||||
such information from our records.
|
||||
</p>
|
||||
|
||||
<h2>Online Privacy Policy Only</h2>
|
||||
|
||||
<p>
|
||||
This Privacy Policy applies only to our online activities and is valid for
|
||||
visitors to our website with regards to the information that they shared
|
||||
and/or collect in Modrinth. This policy is not applicable to any
|
||||
information collected offline or via channels other than this website.
|
||||
</p>
|
||||
|
||||
<h2>Consent</h2>
|
||||
|
||||
<p>
|
||||
By using our website, you hereby consent to our Privacy Policy and agree
|
||||
to its Terms and Conditions.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
auth: false,
|
||||
layout: 'home',
|
||||
head: {
|
||||
title: 'Privacy - Modrinth',
|
||||
meta: [
|
||||
{
|
||||
hid: 'description',
|
||||
name: 'description',
|
||||
content:
|
||||
'The privacy policy of Modrinth, an open source modding platform. Modrinth currently supports Minecraft, including the forge and fabric mod loaders.',
|
||||
},
|
||||
{
|
||||
hid: 'apple-mobile-web-app-title',
|
||||
name: 'apple-mobile-web-app-title',
|
||||
content: 'Privacy Policy',
|
||||
},
|
||||
{
|
||||
hid: 'og:title',
|
||||
name: 'og:title',
|
||||
content: 'Privacy Policy',
|
||||
},
|
||||
{
|
||||
hid: 'og:url',
|
||||
name: 'og:url',
|
||||
content: `https://modrinth.com/privacy`,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main {
|
||||
margin: 0 auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
</style>
|
||||
187
pages/tos.vue
@@ -1,187 +0,0 @@
|
||||
<template>
|
||||
<div class="main">
|
||||
<h1>Terms and Conditions</h1>
|
||||
|
||||
<h2>1. Terms</h2>
|
||||
|
||||
<p>
|
||||
By accessing this Website, accessible from https://modrinth.com, you are
|
||||
agreeing to be bound by these Website Terms and Conditions of Use and
|
||||
agree that you are responsible for the agreement with any applicable local
|
||||
laws. If you disagree with any of these terms, you are prohibited from
|
||||
accessing this site. The materials contained in this Website are protected
|
||||
by copyright and trade mark law.
|
||||
</p>
|
||||
|
||||
<h2>2. Use License</h2>
|
||||
|
||||
<p>
|
||||
Permission is granted to temporarily download one copy of the materials on
|
||||
Guavy LLC's Website for personal, non-commercial transitory viewing only.
|
||||
This is the grant of a license, not a transfer of title, and under this
|
||||
license you may not:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>modify or copy the materials;</li>
|
||||
<li>
|
||||
use the materials for any commercial purpose or for any public display;
|
||||
</li>
|
||||
<li>
|
||||
attempt to reverse engineer any software contained on Guavy LLC's
|
||||
Website;
|
||||
</li>
|
||||
<li>
|
||||
remove any copyright or other proprietary notations from the materials;
|
||||
or
|
||||
</li>
|
||||
<li>
|
||||
transferring the materials to another person or "mirror" the materials
|
||||
on any other server.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
This will let Guavy LLC to terminate upon violations of any of these
|
||||
restrictions. Upon termination, your viewing right will also be terminated
|
||||
and you should destroy any downloaded materials in your possession whether
|
||||
it is printed or electronic format.
|
||||
</p>
|
||||
|
||||
<h2>3. Disclaimer</h2>
|
||||
|
||||
<p>
|
||||
All the materials on Guavy LLC’s Website are provided "as is". Guavy LLC
|
||||
makes no warranties, may it be expressed or implied, therefore negates all
|
||||
other warranties. Furthermore, Guavy LLC does not make any representations
|
||||
concerning the accuracy or reliability of the use of the materials on its
|
||||
Website or otherwise relating to such materials or any sites linked to
|
||||
this Website.
|
||||
</p>
|
||||
|
||||
<h2>4. Limitations</h2>
|
||||
|
||||
<p>
|
||||
Guavy LLC or its suppliers will not be hold accountable for any damages
|
||||
that will arise with the use or inability to use the materials on Guavy
|
||||
LLC’s Website, even if Guavy LLC or an authorize representative of this
|
||||
Website has been notified, orally or written, of the possibility of such
|
||||
damage. Some jurisdiction does not allow limitations on implied warranties
|
||||
or limitations of liability for incidental damages, these limitations may
|
||||
not apply to you.
|
||||
</p>
|
||||
|
||||
<h2>5. Revisions and Errata</h2>
|
||||
|
||||
<p>
|
||||
The materials appearing on Guavy LLC’s Website may include technical,
|
||||
typographical, or photographic errors. Guavy LLC will not promise that any
|
||||
of the materials in this Website are accurate, complete, or current. Guavy
|
||||
LLC may change the materials contained on its Website at any time without
|
||||
notice. Guavy LLC does not make any commitment to update the materials.
|
||||
</p>
|
||||
|
||||
<h2>6. Links</h2>
|
||||
|
||||
<p>
|
||||
Guavy LLC has not reviewed all of the sites linked to its Website and is
|
||||
not responsible for the contents of any such linked site. The presence of
|
||||
any link does not imply endorsement by Guavy LLC of the site. The use of
|
||||
any linked website is at the user’s own risk.
|
||||
</p>
|
||||
|
||||
<h2>7. Site Terms of Use Modifications</h2>
|
||||
|
||||
<p>
|
||||
Guavy LLC may revise these Terms of Use for its Website at any time
|
||||
without prior notice. By using this Website, you are agreeing to be bound
|
||||
by the current version of these Terms and Conditions of Use.
|
||||
</p>
|
||||
|
||||
<h2>8. Your Privacy</h2>
|
||||
|
||||
<p>Please read our <nuxt-link to="/privacy"> Privacy Policy</nuxt-link>.</p>
|
||||
|
||||
<h2>9. Governing Law</h2>
|
||||
|
||||
<p>
|
||||
Any claim related to Guavy LLC's Website shall be governed by the laws of
|
||||
us without regards to its conflict of law provisions.
|
||||
</p>
|
||||
|
||||
<h2>10. Content</h2>
|
||||
|
||||
<p>
|
||||
When you upload text, software, mods, scripts, graphics, photos, audio,
|
||||
videos, links, interactive features and other materials that may be viewed
|
||||
on, or accessed through Modrinth, we refer to it as “Content”.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
You must own or have the necessary licenses, rights, consents, and
|
||||
permissions to store, share or distribute the Content that is uploaded
|
||||
under your Modrinth account.
|
||||
</li>
|
||||
<li>
|
||||
You are responsible for all activity and Content that is uploaded under
|
||||
your Modrinth account.
|
||||
</li>
|
||||
<li>
|
||||
You must not transmit any viruses, worms, malware, or any other code of
|
||||
a destructive nature through Modrinth.
|
||||
</li>
|
||||
<li>
|
||||
You retain all of your ownership rights to your Content. We do not claim
|
||||
any ownership in or to any of your Content.
|
||||
</li>
|
||||
<li>
|
||||
To enable us to provide the services of Modrinth, you hereby grant us a
|
||||
worldwide, non-exclusive, royalty-free, and unrestricted license to use,
|
||||
reproduce, distribute copies, prepare derivative works of, or display
|
||||
Content in connection with Modrinth in any medium and for any purpose
|
||||
(including commercial purposes), which is irrevocable.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
auth: false,
|
||||
layout: 'home',
|
||||
head: {
|
||||
title: 'TOS - Modrinth',
|
||||
meta: [
|
||||
{
|
||||
hid: 'description',
|
||||
name: 'description',
|
||||
content:
|
||||
'The Terms of Service of Modrinth, an open source modding platform. Modrinth currently supports Minecraft, including the forge and fabric mod loaders.',
|
||||
},
|
||||
{
|
||||
hid: 'apple-mobile-web-app-title',
|
||||
name: 'apple-mobile-web-app-title',
|
||||
content: 'Terms of Service',
|
||||
},
|
||||
{
|
||||
hid: 'og:title',
|
||||
name: 'og:title',
|
||||
content: 'Terms of Service',
|
||||
},
|
||||
{
|
||||
hid: 'og:url',
|
||||
name: 'og:url',
|
||||
content: `https://modrinth.com/tos`,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.main {
|
||||
margin: 0 auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,49 +1,94 @@
|
||||
<template>
|
||||
<div class="content">
|
||||
<div class="user-profile">
|
||||
<img :src="user.avatar_url" :alt="user.username" />
|
||||
<div class="info">
|
||||
<h1>{{ user.username }}</h1>
|
||||
<p class="joined-text">Joined {{ $dayjs(user.created).fromNow() }}</p>
|
||||
<p v-if="user.bio" class="bio">{{ user.bio }}</p>
|
||||
<p v-if="user.role === 'admin'" class="badge red">Admin</p>
|
||||
<p v-if="user.role === 'moderator'" class="badge yellow">Moderator</p>
|
||||
<p v-if="user.role === 'developer'" class="badge green">Developer</p>
|
||||
<div class="page-container">
|
||||
<div class="page-contents">
|
||||
<div class="sidebar-l">
|
||||
<div class="card">
|
||||
<div class="user-info">
|
||||
<img :src="user.avatar_url" :alt="user.username" />
|
||||
<div class="text">
|
||||
<h2>{{ user.username }}</h2>
|
||||
<p v-if="user.role === 'admin'" class="badge red">Admin</p>
|
||||
<p v-if="user.role === 'moderator'" class="badge yellow">
|
||||
Moderator
|
||||
</p>
|
||||
<p v-if="user.role === 'developer'" class="badge green">
|
||||
Developer
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="user.bio" class="bio">{{ user.bio }}</p>
|
||||
</div>
|
||||
<div class="card stats">
|
||||
<div class="stat">
|
||||
<CalendarIcon />
|
||||
<div class="info">
|
||||
<h4>Created</h4>
|
||||
<p
|
||||
v-tooltip="
|
||||
$dayjs(user.created).format(
|
||||
'[Created on] YYYY-MM-DD [at] HH:mm A'
|
||||
)
|
||||
"
|
||||
class="value"
|
||||
>
|
||||
{{ $dayjs(user.created).fromNow() }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<DownloadIcon />
|
||||
<div class="info">
|
||||
<h4>Downloads</h4>
|
||||
<p class="value">
|
||||
{{ sumDownloads() }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<m-footer class="footer" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<client-only>
|
||||
<EthicalAd />
|
||||
</client-only>
|
||||
<div class="mods">
|
||||
<SearchResult
|
||||
v-for="result in mods"
|
||||
:id="result.mod_id"
|
||||
:key="result.mod_id"
|
||||
:name="result.title"
|
||||
:description="result.description"
|
||||
:created-at="result.published"
|
||||
:updated-at="result.updated"
|
||||
:downloads="result.downloads.toString()"
|
||||
:icon-url="result.icon_url"
|
||||
:author-url="result.author_url"
|
||||
:categories="result.categories"
|
||||
:is-modrinth="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<client-only>
|
||||
<EthicalAd />
|
||||
</client-only>
|
||||
<div class="user-mods">
|
||||
<SearchResult
|
||||
v-for="result in mods"
|
||||
:id="result.mod_id"
|
||||
:key="result.mod_id"
|
||||
:name="result.title"
|
||||
:description="result.description"
|
||||
:latest-version="result.versions[0]"
|
||||
:created-at="result.published"
|
||||
:updated-at="result.updated"
|
||||
:downloads="result.downloads.toString()"
|
||||
:icon-url="result.icon_url"
|
||||
:author-url="result.author_url"
|
||||
:page-url="result.page_url"
|
||||
:categories="result.categories"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import SearchResult from '@/components/ModResult'
|
||||
import SearchResult from '@/components/ProjectCard'
|
||||
import EthicalAd from '@/components/EthicalAd'
|
||||
import MFooter from '@/components/MFooter'
|
||||
|
||||
import CalendarIcon from '~/assets/images/utils/calendar.svg?inline'
|
||||
import DownloadIcon from '~/assets/images/utils/download.svg?inline'
|
||||
|
||||
export default {
|
||||
auth: false,
|
||||
components: {
|
||||
EthicalAd,
|
||||
SearchResult,
|
||||
CalendarIcon,
|
||||
DownloadIcon,
|
||||
MFooter,
|
||||
},
|
||||
async asyncData(data) {
|
||||
let res = await axios.get(
|
||||
@@ -67,56 +112,61 @@ export default {
|
||||
user,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatNumber(x) {
|
||||
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
},
|
||||
sumDownloads() {
|
||||
let sum = 0
|
||||
|
||||
for (const mod of this.mods) {
|
||||
sum += mod.downloads
|
||||
}
|
||||
|
||||
return this.formatNumber(sum)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-profile {
|
||||
@media screen and (min-width: 900px) {
|
||||
display: inline-flex;
|
||||
text-align: left;
|
||||
.sidebar-l {
|
||||
min-width: 21rem;
|
||||
|
||||
.user-info {
|
||||
@extend %row;
|
||||
img {
|
||||
width: 6rem;
|
||||
height: 6rem;
|
||||
margin-right: var(--spacing-card-md);
|
||||
border-radius: var(--size-rounded-icon);
|
||||
}
|
||||
.text {
|
||||
h2 {
|
||||
margin: 0;
|
||||
color: var(--color-text-dark);
|
||||
font-size: var(--font-size-lg);
|
||||
}
|
||||
.badge {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
margin-left: 15px;
|
||||
.stats {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.stat {
|
||||
@extend %stat;
|
||||
|
||||
img {
|
||||
border-radius: var(--size-rounded-md);
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
.info {
|
||||
@media screen and (min-width: 900px) {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.joined-text {
|
||||
margin-top: 5px;
|
||||
color: var(--color-grey-4);
|
||||
}
|
||||
|
||||
.bio {
|
||||
margin-top: 5px;
|
||||
font-size: 16pt;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-block;
|
||||
svg {
|
||||
padding: 0.25rem;
|
||||
border-radius: 50%;
|
||||
background-color: var(--color-button-bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-mods {
|
||||
border-top: 1px solid var(--color-grey-1);
|
||||
padding-top: 10px;
|
||||
margin: 10px;
|
||||
* {
|
||||
margin-left: 0;
|
||||
}
|
||||
.mods {
|
||||
}
|
||||
</style>
|
||||
|
||||
17
plugins/compiled-markdown-directive.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import Vue from 'vue'
|
||||
import xss from 'xss'
|
||||
import marked from 'marked'
|
||||
|
||||
function compileMarkdown(target, markdown) {
|
||||
target.innerHTML = xss(marked(markdown))
|
||||
}
|
||||
|
||||
Vue.directive('compiled-markdown', {
|
||||
bind(el, binding, vnode) {
|
||||
compileMarkdown(el, binding.value)
|
||||
},
|
||||
|
||||
update(el, binding, vnode) {
|
||||
compileMarkdown(el, binding.value)
|
||||
},
|
||||
})
|
||||