bump-merge

This commit is contained in:
Untone 2023-10-11 14:16:01 +03:00
commit a80f778325
41 changed files with 929 additions and 344 deletions

439
package-lock.json generated
View File

@ -126,6 +126,7 @@
"typograf": "7.1.0",
"uniqolor": "1.1.0",
"vite": "4.3.9",
"vite-plugin-mkcert": "1.16.0",
"vite-plugin-sass-dts": "1.3.11",
"vite-plugin-solid": "2.7.0",
"vite-plugin-ssr": "0.4.123",
@ -4000,6 +4001,215 @@
"node": ">= 8"
}
},
"node_modules/@octokit/auth-token": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz",
"integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==",
"dev": true,
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/core": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz",
"integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==",
"dev": true,
"dependencies": {
"@octokit/auth-token": "^3.0.0",
"@octokit/graphql": "^5.0.0",
"@octokit/request": "^6.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^9.0.0",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/endpoint": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz",
"integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==",
"dev": true,
"dependencies": {
"@octokit/types": "^9.0.0",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/endpoint/node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@octokit/graphql": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz",
"integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==",
"dev": true,
"dependencies": {
"@octokit/request": "^6.0.0",
"@octokit/types": "^9.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/openapi-types": {
"version": "18.1.1",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.1.1.tgz",
"integrity": "sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw==",
"dev": true
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz",
"integrity": "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==",
"dev": true,
"dependencies": {
"@octokit/tsconfig": "^1.0.2",
"@octokit/types": "^9.2.3"
},
"engines": {
"node": ">= 14"
},
"peerDependencies": {
"@octokit/core": ">=4"
}
},
"node_modules/@octokit/plugin-request-log": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
"dev": true,
"peerDependencies": {
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz",
"integrity": "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==",
"dev": true,
"dependencies": {
"@octokit/types": "^10.0.0"
},
"engines": {
"node": ">= 14"
},
"peerDependencies": {
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz",
"integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==",
"dev": true,
"dependencies": {
"@octokit/openapi-types": "^18.0.0"
}
},
"node_modules/@octokit/request": {
"version": "6.2.8",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz",
"integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==",
"dev": true,
"dependencies": {
"@octokit/endpoint": "^7.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^9.0.0",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/request-error": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz",
"integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==",
"dev": true,
"dependencies": {
"@octokit/types": "^9.0.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/request/node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/@octokit/request/node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dev": true,
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/@octokit/rest": {
"version": "19.0.13",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.13.tgz",
"integrity": "sha512-/EzVox5V9gYGdbAI+ovYj3nXQT1TtTHRT+0eZPcuC05UFSWO3mdO9UY1C0i2eLF9Un1ONJkAk+IEtYGAC+TahA==",
"dev": true,
"dependencies": {
"@octokit/core": "^4.2.1",
"@octokit/plugin-paginate-rest": "^6.1.2",
"@octokit/plugin-request-log": "^1.0.4",
"@octokit/plugin-rest-endpoint-methods": "^7.1.2"
},
"engines": {
"node": ">= 14"
}
},
"node_modules/@octokit/tsconfig": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz",
"integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==",
"dev": true
},
"node_modules/@octokit/types": {
"version": "9.3.2",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz",
"integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==",
"dev": true,
"dependencies": {
"@octokit/openapi-types": "^18.0.0"
}
},
"node_modules/@parcel/watcher": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.3.0.tgz",
@ -6343,6 +6553,12 @@
}
]
},
"node_modules/before-after-hook": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==",
"dev": true
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@ -7479,6 +7695,12 @@
"node": ">= 0.6.0"
}
},
"node_modules/deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
"dev": true
},
"node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
@ -17749,6 +17971,12 @@
"integrity": "sha512-j2XyokF24fsj+L5u6fbu4rM3RQc6VWJuAngYM2k0ZdG3yiVxt0smLkps2GmQIYqK8VkELGdM9vFU/HfOkK/zoQ==",
"dev": true
},
"node_modules/universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==",
"dev": true
},
"node_modules/universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
@ -17952,6 +18180,24 @@
}
}
},
"node_modules/vite-plugin-mkcert": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/vite-plugin-mkcert/-/vite-plugin-mkcert-1.16.0.tgz",
"integrity": "sha512-5r+g8SB9wZzLNUFekGwZo3e0P6QlS6rbxK5p9z/itxNAimsYohgjK/YfVPVxM9EuglP9hjridq0lUejo9v1nVg==",
"dev": true,
"dependencies": {
"@octokit/rest": "^19.0.5",
"axios": "^1.2.2",
"debug": "^4.3.4",
"picocolors": "^1.0.0"
},
"engines": {
"node": ">=v16.7.0"
},
"peerDependencies": {
"vite": ">=3"
}
},
"node_modules/vite-plugin-sass-dts": {
"version": "1.3.11",
"resolved": "https://registry.npmjs.org/vite-plugin-sass-dts/-/vite-plugin-sass-dts-1.3.11.tgz",
@ -21216,6 +21462,169 @@
"fastq": "^1.6.0"
}
},
"@octokit/auth-token": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-3.0.4.tgz",
"integrity": "sha512-TWFX7cZF2LXoCvdmJWY7XVPi74aSY0+FfBZNSXEXFkMpjcqsQwDSYVv5FhRFaI0V1ECnwbz4j59T/G+rXNWaIQ==",
"dev": true
},
"@octokit/core": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-4.2.4.tgz",
"integrity": "sha512-rYKilwgzQ7/imScn3M9/pFfUf4I1AZEH3KhyJmtPdE2zfaXAn2mFfUy4FbKewzc2We5y/LlKLj36fWJLKC2SIQ==",
"dev": true,
"requires": {
"@octokit/auth-token": "^3.0.0",
"@octokit/graphql": "^5.0.0",
"@octokit/request": "^6.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^9.0.0",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/endpoint": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-7.0.6.tgz",
"integrity": "sha512-5L4fseVRUsDFGR00tMWD/Trdeeihn999rTMGRMC1G/Ldi1uWlWJzI98H4Iak5DB/RVvQuyMYKqSK/R6mbSOQyg==",
"dev": true,
"requires": {
"@octokit/types": "^9.0.0",
"is-plain-object": "^5.0.0",
"universal-user-agent": "^6.0.0"
},
"dependencies": {
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"dev": true
}
}
},
"@octokit/graphql": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-5.0.6.tgz",
"integrity": "sha512-Fxyxdy/JH0MnIB5h+UQ3yCoh1FG4kWXfFKkpWqjZHw/p+Kc8Y44Hu/kCgNBT6nU1shNumEchmW/sUO1JuQnPcw==",
"dev": true,
"requires": {
"@octokit/request": "^6.0.0",
"@octokit/types": "^9.0.0",
"universal-user-agent": "^6.0.0"
}
},
"@octokit/openapi-types": {
"version": "18.1.1",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-18.1.1.tgz",
"integrity": "sha512-VRaeH8nCDtF5aXWnjPuEMIYf1itK/s3JYyJcWFJT8X9pSNnBtriDf7wlEWsGuhPLl4QIH4xM8fqTXDwJ3Mu6sw==",
"dev": true
},
"@octokit/plugin-paginate-rest": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.1.2.tgz",
"integrity": "sha512-qhrmtQeHU/IivxucOV1bbI/xZyC/iOBhclokv7Sut5vnejAIAEXVcGQeRpQlU39E0WwK9lNvJHphHri/DB6lbQ==",
"dev": true,
"requires": {
"@octokit/tsconfig": "^1.0.2",
"@octokit/types": "^9.2.3"
}
},
"@octokit/plugin-request-log": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
"integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
"dev": true,
"requires": {}
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.2.3.tgz",
"integrity": "sha512-I5Gml6kTAkzVlN7KCtjOM+Ruwe/rQppp0QU372K1GP7kNOYEKe8Xn5BW4sE62JAHdwpq95OQK/qGNyKQMUzVgA==",
"dev": true,
"requires": {
"@octokit/types": "^10.0.0"
},
"dependencies": {
"@octokit/types": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-10.0.0.tgz",
"integrity": "sha512-Vm8IddVmhCgU1fxC1eyinpwqzXPEYu0NrYzD3YZjlGjyftdLBTeqNblRC0jmJmgxbJIsQlyogVeGnrNaaMVzIg==",
"dev": true,
"requires": {
"@octokit/openapi-types": "^18.0.0"
}
}
}
},
"@octokit/request": {
"version": "6.2.8",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.8.tgz",
"integrity": "sha512-ow4+pkVQ+6XVVsekSYBzJC0VTVvh/FCTUUgTsboGq+DTeWdyIFV8WSCdo0RIxk6wSkBTHqIK1mYuY7nOBXOchw==",
"dev": true,
"requires": {
"@octokit/endpoint": "^7.0.0",
"@octokit/request-error": "^3.0.0",
"@octokit/types": "^9.0.0",
"is-plain-object": "^5.0.0",
"node-fetch": "^2.6.7",
"universal-user-agent": "^6.0.0"
},
"dependencies": {
"is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"dev": true
},
"node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dev": true,
"requires": {
"whatwg-url": "^5.0.0"
}
}
}
},
"@octokit/request-error": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-3.0.3.tgz",
"integrity": "sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==",
"dev": true,
"requires": {
"@octokit/types": "^9.0.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
}
},
"@octokit/rest": {
"version": "19.0.13",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.13.tgz",
"integrity": "sha512-/EzVox5V9gYGdbAI+ovYj3nXQT1TtTHRT+0eZPcuC05UFSWO3mdO9UY1C0i2eLF9Un1ONJkAk+IEtYGAC+TahA==",
"dev": true,
"requires": {
"@octokit/core": "^4.2.1",
"@octokit/plugin-paginate-rest": "^6.1.2",
"@octokit/plugin-request-log": "^1.0.4",
"@octokit/plugin-rest-endpoint-methods": "^7.1.2"
}
},
"@octokit/tsconfig": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@octokit/tsconfig/-/tsconfig-1.0.2.tgz",
"integrity": "sha512-I0vDR0rdtP8p2lGMzvsJzbhdOWy405HcGovrspJ8RRibHnyRgggUSNO5AIox5LmqiwmatHKYsvj6VGFHkqS7lA==",
"dev": true
},
"@octokit/types": {
"version": "9.3.2",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.3.2.tgz",
"integrity": "sha512-D4iHGTdAnEEVsB8fl95m1hiz7D5YiRdQ9b/OEb3BYRVwbLsGHcRVPz+u+BgRLNk0Q0/4iZCBqDN96j2XNxfXrA==",
"dev": true,
"requires": {
"@octokit/openapi-types": "^18.0.0"
}
},
"@parcel/watcher": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.3.0.tgz",
@ -22857,6 +23266,12 @@
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"dev": true
},
"before-after-hook": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==",
"dev": true
},
"binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@ -23663,6 +24078,12 @@
"integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==",
"dev": true
},
"deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
"dev": true
},
"dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
@ -31183,6 +31604,12 @@
"integrity": "sha512-j2XyokF24fsj+L5u6fbu4rM3RQc6VWJuAngYM2k0ZdG3yiVxt0smLkps2GmQIYqK8VkELGdM9vFU/HfOkK/zoQ==",
"dev": true
},
"universal-user-agent": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
"integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==",
"dev": true
},
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
@ -31316,6 +31743,18 @@
"rollup": "^3.21.0"
}
},
"vite-plugin-mkcert": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/vite-plugin-mkcert/-/vite-plugin-mkcert-1.16.0.tgz",
"integrity": "sha512-5r+g8SB9wZzLNUFekGwZo3e0P6QlS6rbxK5p9z/itxNAimsYohgjK/YfVPVxM9EuglP9hjridq0lUejo9v1nVg==",
"dev": true,
"requires": {
"@octokit/rest": "^19.0.5",
"axios": "^1.2.2",
"debug": "^4.3.4",
"picocolors": "^1.0.0"
}
},
"vite-plugin-sass-dts": {
"version": "1.3.11",
"resolved": "https://registry.npmjs.org/vite-plugin-sass-dts/-/vite-plugin-sass-dts-1.3.11.tgz",

View File

@ -146,6 +146,7 @@
"typograf": "7.1.0",
"uniqolor": "1.1.0",
"vite": "4.3.9",
"vite-plugin-mkcert": "1.16.0",
"vite-plugin-sass-dts": "1.3.11",
"vite-plugin-solid": "2.7.0",
"vite-plugin-ssr": "0.4.123",

View File

@ -1,3 +1 @@
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.99987 7.52552L14.1871 0.92334L15.9548 2.80968L9.76764 9.41185L15.9548 16.014L14.1871 17.9004L7.99987 11.2982L1.81269 17.9004L0.0449219 16.014L6.23211 9.41185L0.0449225 2.80968L1.81269 0.92334L7.99987 7.52552Z" fill="#141414"/>
</svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7.99987 6.23211L14.1871 0.0449219L15.9548 1.81269L9.76764 7.99987L15.9548 14.1871L14.1871 15.9548L7.99987 9.76764L1.81269 15.9548L0.0449219 14.1871L6.23211 7.99987L0.0449225 1.81269L1.81269 0.0449219L7.99987 6.23211Z" fill="currentColor"/></svg>

Before

Width:  |  Height:  |  Size: 382 B

After

Width:  |  Height:  |  Size: 351 B

View File

@ -29,6 +29,7 @@
"All topics": "All topics",
"Almost done! Check your email.": "Almost done! Just checking your email.",
"Are you sure you want to to proceed the action?": "Are you sure you want to to proceed the action?",
"Art": "Art",
"Artist": "Artist",
"Artworks": "Artworks",
"Audio": "Audio",
@ -134,6 +135,7 @@
"Forgot password?": "Forgot your password?",
"Forward": "Forward",
"Full name": "First and last name",
"Gallery": "Gallery",
"Gallery name": "Gallery name",
"Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine": "Get to know the most intelligent people of our time, edit and discuss the articles, share your expertise, rate and decide what to publish in the magazine",
"Go to main page": "Go to main page",
@ -199,6 +201,7 @@
"Most read": "Readable",
"Move down": "Move down",
"Move up": "Move up",
"Music": "Music",
"My feed": "My feed",
"My subscriptions": "Subscriptions",
"Name": "Name",

View File

@ -32,6 +32,7 @@
"All topics": "Все темы",
"Almost done! Check your email.": "Почти готово! Осталось подтвердить вашу почту.",
"Are you sure you want to to proceed the action?": "Вы уверены, что хотите продолжить?",
"Art": "Искусство",
"Artist": "Исполнитель",
"Artist...": "Исполнитель...",
"Artworks": "Артворки",
@ -139,6 +140,7 @@
"Forgot password?": "Забыли пароль?",
"Forward": "Переслать",
"Full name": "Имя и фамилия",
"Gallery": "Галерея",
"Gallery name": "Название галереи",
"Genre...": "Жанр...",
"Get notifications": "Получать уведомления",
@ -209,6 +211,7 @@
"Most read": "Читаемое",
"Move down": "Переместить вниз",
"Move up": "Переместить вверх",
"Music": "Музыка",
"My feed": "Моя лента",
"My subscriptions": "Подписки",
"Name": "Имя",

View File

@ -30,7 +30,7 @@ import { CreatePage } from '../pages/create.page'
import { EditPage } from '../pages/edit.page'
import { ConnectPage } from '../pages/connect.page'
import { InboxPage } from '../pages/inbox.page'
import { LayoutShoutsPage } from '../pages/layoutShouts.page'
import { ExpoPage } from '../pages/expo/expo.page'
import { SessionProvider } from '../context/session'
import { ProfileSettingsPage } from '../pages/profile/profileSettings.page'
import { ProfileSecurityPage } from '../pages/profile/profileSecurity.page'
@ -51,7 +51,8 @@ const pagesMap: Record<keyof typeof ROUTES, Component<PageProps>> = {
authorFollowing: AuthorPage,
authorFollowers: AuthorPage,
inbox: InboxPage,
expo: LayoutShoutsPage,
expo: ExpoPage,
expoLayout: ExpoPage,
connect: ConnectPage,
create: CreatePage,
edit: EditPage,

View File

@ -218,7 +218,7 @@ export const FullArticle = (props: Props) => {
<div class="row position-relative">
<article class="col-md-16 col-lg-14 col-xl-12 offset-md-5">
{/*TODO: Check styles.shoutTopic*/}
<Show when={props.article.layout !== 'audio'}>
<Show when={props.article.layout !== 'music'}>
<div class={styles.shoutHeader}>
<Show when={mainTopic()}>
<CardTopic title={mainTopic().title} slug={props.article.mainTopic} />
@ -256,7 +256,7 @@ export const FullArticle = (props: Props) => {
<Show when={props.article.lead}>
<section class={styles.lead} innerHTML={props.article.lead} />
</Show>
<Show when={props.article.layout === 'audio'}>
<Show when={props.article.layout === 'music'}>
<AudioHeader
title={props.article.title}
cover={props.article.cover}

View File

@ -473,6 +473,16 @@
.buttonWriteAuthorPage {
background: #f6f6f6 !important;
border-radius: 0.8rem;
&:hover {
background: #e9e9ee !important;
border-color: #e9e9ee;
}
&:active {
background: #ccc !important;
border-color: #ccc;
}
}
.authorPage {

View File

@ -2,7 +2,12 @@ import { Show } from 'solid-js'
import type { Shout } from '../../graphql/types.gen'
import { ArticleCard } from './ArticleCard'
export const Row1 = (props: { article: Shout; nodate?: boolean; noAuthorLink?: boolean }) => (
export const Row1 = (props: {
article: Shout
nodate?: boolean
noAuthorLink?: boolean
noauthor?: boolean
}) => (
<Show when={!!props.article}>
<div class="floor floor--one-article">
<div class="wide-container">
@ -10,7 +15,12 @@ export const Row1 = (props: { article: Shout; nodate?: boolean; noAuthorLink?: b
<div class="col-24">
<ArticleCard
article={props.article}
settings={{ isSingle: true, nodate: props.nodate, noAuthorLink: props.noAuthorLink }}
settings={{
isSingle: true,
nodate: props.nodate,
noAuthorLink: props.noAuthorLink,
noauthor: props.noauthor
}}
/>
</div>
</div>

View File

@ -13,6 +13,7 @@ export const Row2 = (props: {
isEqual?: boolean
nodate?: boolean
noAuthorLink?: boolean
noauthor?: boolean
}) => {
const [y, setY] = createSignal(0)
@ -33,7 +34,8 @@ export const Row2 = (props: {
settings={{
isWithCover: props.isEqual || x[y()][i()] === '16',
nodate: props.isEqual || props.nodate,
noAuthorLink: props.noAuthorLink
noAuthorLink: props.noAuthorLink,
noauthor: props.noauthor
}}
/>
</div>

View File

@ -8,6 +8,7 @@ export const Row3 = (props: {
header?: JSX.Element
nodate?: boolean
noAuthorLink?: boolean
noauthor?: boolean
}) => {
return (
<Show when={props.articles && props.articles.length > 0}>
@ -20,7 +21,11 @@ export const Row3 = (props: {
<div class="col-md-8">
<ArticleCard
article={a}
settings={{ nodate: props.nodate, noAuthorLink: props.noAuthorLink }}
settings={{
nodate: props.nodate,
noAuthorLink: props.noAuthorLink,
noauthor: props.noauthor
}}
/>
</div>
)}

View File

@ -375,7 +375,7 @@ export const Header = (props: Props) => {
>
<ul class="nodash">
<li class="item">
<a href="/expo/image">Искусство</a>
<a href="/expo">{t('Art')}</a>
</li>
<li class="item">
<a href="/podcasts">Подкасты</a>

View File

@ -17,18 +17,21 @@
background: #fff;
max-width: 1000px;
position: relative;
width: 100%;
@include media-breakpoint-up(sm) {
width: 80%;
&:not([class*='col-']) {
width: 100%;
@include media-breakpoint-up(sm) {
width: 80%;
}
}
.close {
position: absolute;
top: 2rem;
cursor: pointer;
height: 18px;
width: 16px;
height: 1.6rem;
width: 1.6rem;
opacity: 1;
padding: 0;
right: 2.4rem;

View File

@ -1,52 +0,0 @@
import { Icon } from '../_shared/Icon'
import { useLocalize } from '../../context/localize'
import './Topics.scss'
export const NavTopics = () => {
const { t } = useLocalize()
return (
<nav class="subnavigation wide-container text-2xl">
<ul class="topics">
<li class="item">
<a href="/expo/image">Искусство</a>
</li>
<li class="item">
<a href="/podcasts">Подкасты</a>
</li>
<li class="item">
<a href="">Спецпроекты</a>
</li>
<li class="item">
<a href="/topic/interview">#Интервью</a>
</li>
<li class="item">
<a href="/topic/reportage">#Репортажи</a>
</li>
<li class="item">
<a href="/topic/empiric">#Личный опыт</a>
</li>
<li class="item">
<a href="/topic/society">#Общество</a>
</li>
<li class="item">
<a href="/topic/culture">#Культура</a>
</li>
<li class="item">
<a href="/topic/theory">#Теории</a>
</li>
<li class="item">
<a href="/topic/poetry">#Поэзия</a>
</li>
<li class="item right">
<a href={`/topics`}>
<span>
{t('All topics')}
<Icon name="arrow-right-black" class={'icon'} />
</span>
</a>
</li>
</ul>
</nav>
)
}

View File

@ -1,8 +1,9 @@
.subnavigation {
.Topics {
@include font-size(1.4rem);
height: 6rem;
line-height: 6rem;
margin-bottom: 5rem !important;
margin-bottom: 3rem;
overflow: hidden;
position: relative;
transform: translateY(-2px);
@ -11,7 +12,7 @@
padding: 0 divide($container-padding-x, 2);
}
.topics {
.list {
display: flex;
flex-wrap: wrap;
font-weight: 500;
@ -32,32 +33,11 @@
}
a {
border-bottom: 0;
&:hover {
.icon {
filter: invert(1);
}
border-bottom: unset;
&.selected {
font-weight: 500;
border-bottom: 2px solid var(--default-color);
}
}
.icon {
display: inline-block;
margin-left: 0.3em;
position: relative;
top: 0.15em;
}
}
.selected {
color: black;
}
a {
color: #141414;
}
a:hover {
color: white;
}
}

View File

@ -0,0 +1,57 @@
import { Icon } from '../../_shared/Icon'
import { useLocalize } from '../../../context/localize'
import styles from './Topics.module.scss'
import { clsx } from 'clsx'
import { router, useRouter } from '../../../stores/router'
import { getPagePath } from '@nanostores/router'
export const Topics = () => {
const { t } = useLocalize()
const { page } = useRouter()
return (
<nav class={clsx('wide-container text-2xl', styles.Topics)}>
<ul class={styles.list}>
<li class={styles.item}>
<a class={clsx({ [styles.selected]: page().route === 'expo' })} href="/expo">
{t('Art')}
</a>
</li>
<li class={styles.item}>
<a href="/podcasts">Подкасты</a>
</li>
<li class={styles.item}>
<a href="">Спецпроекты</a>
</li>
<li class={styles.item}>
<a href="/topic/interview">#Интервью</a>
</li>
<li class={styles.item}>
<a href="/topic/reportage">#Репортажи</a>
</li>
<li class={styles.item}>
<a href="/topic/empiric">#Личный опыт</a>
</li>
<li class={styles.item}>
<a href="/topic/society">#Общество</a>
</li>
<li class={styles.item}>
<a href="/topic/culture">#Культура</a>
</li>
<li class={styles.item}>
<a href="/topic/theory">#Теории</a>
</li>
<li class={styles.item}>
<a href="/topic/poetry">#Поэзия</a>
</li>
<li class={clsx(styles.item, styles.right)}>
<a href={getPagePath(router, 'topics')}>
<span>
{t('All topics')}
<Icon name="arrow-right-black" class={'icon'} />
</span>
</a>
</li>
</ul>
</nav>
)
}

View File

@ -0,0 +1 @@
export { Topics } from './Topics'

View File

@ -3,7 +3,6 @@ import styles from './TopicBadge.module.scss'
import { FollowingEntity, Topic } from '../../../graphql/types.gen'
import { createMemo, createSignal, Show } from 'solid-js'
import { imageProxy } from '../../../utils/imageProxy'
import { capitalize } from '../../../utils'
import { Button } from '../../_shared/Button'
import { useSession } from '../../../context/session'
import { useLocalize } from '../../../context/localize'

View File

@ -16,8 +16,8 @@
.authorHeader {
border-bottom: 2px solid #000;
margin-bottom: 2.4rem;
margin-top: -3.2rem;
padding-bottom: 4rem;
padding-top: 2.6rem;
}
.ratingContainer {

View File

@ -207,34 +207,34 @@ export const AuthorView = (props: Props) => {
<Match when={page().route === 'author'}>
<Show when={sortedArticles().length === 1}>
<Row1 article={sortedArticles()[0]} noAuthorLink={true} nodate={true} />
<Row1 article={sortedArticles()[0]} noauthor={true} nodate={true} />
</Show>
<Show when={sortedArticles().length === 2}>
<Row2 articles={sortedArticles()} isEqual={true} noAuthorLink={true} nodate={true} />
<Row2 articles={sortedArticles()} isEqual={true} noauthor={true} nodate={true} />
</Show>
<Show when={sortedArticles().length === 3}>
<Row3 articles={sortedArticles()} noAuthorLink={true} nodate={true} />
<Row3 articles={sortedArticles()} noauthor={true} nodate={true} />
</Show>
<Show when={sortedArticles().length > 3}>
<Row1 article={sortedArticles()[0]} noAuthorLink={true} nodate={true} />
<Row2 articles={sortedArticles().slice(1, 3)} isEqual={true} noAuthorLink={true} />
<Row1 article={sortedArticles()[3]} noAuthorLink={true} nodate={true} />
<Row2 articles={sortedArticles().slice(4, 6)} isEqual={true} noAuthorLink={true} />
<Row1 article={sortedArticles()[6]} noAuthorLink={true} nodate={true} />
<Row2 articles={sortedArticles().slice(7, 9)} isEqual={true} noAuthorLink={true} />
<Row1 article={sortedArticles()[0]} noauthor={true} nodate={true} />
<Row2 articles={sortedArticles().slice(1, 3)} isEqual={true} noauthor={true} />
<Row1 article={sortedArticles()[3]} noauthor={true} nodate={true} />
<Row2 articles={sortedArticles().slice(4, 6)} isEqual={true} noauthor={true} />
<Row1 article={sortedArticles()[6]} noauthor={true} nodate={true} />
<Row2 articles={sortedArticles().slice(7, 9)} isEqual={true} noauthor={true} />
<For each={shouts()}>
{(shout) => (
<>
<Row1 article={shout[0]} noAuthorLink={true} nodate={true} />
<Row2 articles={shout.slice(1, 3)} isEqual={true} noAuthorLink={true} />
<Row1 article={shout[3]} noAuthorLink={true} nodate={true} />
<Row2 articles={shout.slice(4, 6)} isEqual={true} noAuthorLink={true} />
<Row1 article={shout[6]} noAuthorLink={true} nodate={true} />
<Row2 articles={shout.slice(7, 9)} isEqual={true} noAuthorLink={true} />
<Row1 article={shout[0]} noauthor={true} nodate={true} />
<Row2 articles={shout.slice(1, 3)} isEqual={true} noauthor={true} />
<Row1 article={shout[3]} noauthor={true} nodate={true} />
<Row2 articles={shout.slice(4, 6)} isEqual={true} noauthor={true} />
<Row1 article={shout[6]} noauthor={true} nodate={true} />
<Row2 articles={shout.slice(7, 9)} isEqual={true} noauthor={true} />
</>
)}
</For>

View File

@ -158,7 +158,7 @@ export const EditView = (props: Props) => {
const articleTitle = () => {
switch (props.shout.layout as LayoutType) {
case 'audio': {
case 'music': {
return t('Album name')
}
case 'image': {
@ -172,7 +172,7 @@ export const EditView = (props: Props) => {
const pageTitle = () => {
switch (props.shout.layout as LayoutType) {
case 'audio': {
case 'music': {
return t('Publish Album')
}
case 'image': {
@ -259,19 +259,19 @@ export const EditView = (props: Props) => {
<div class="col-md-19 col-lg-18 col-xl-16 offset-md-5">
<Show when={page().route === 'edit'}>
<div class={styles.headingActions}>
<Show when={!isSubtitleVisible() && props.shout.layout !== 'audio'}>
<Show when={!isSubtitleVisible() && props.shout.layout !== 'music'}>
<div class={styles.action} onClick={showSubtitleInput}>
{t('Add subtitle')}
</div>
</Show>
<Show when={!isLeadVisible() && props.shout.layout !== 'audio'}>
<Show when={!isLeadVisible() && props.shout.layout !== 'music'}>
<div class={styles.action} onClick={showLeadInput}>
{t('Add intro')}
</div>
</Show>
</div>
<>
<div class={clsx({ [styles.audioHeader]: props.shout.layout === 'audio' })}>
<div class={clsx({ [styles.audioHeader]: props.shout.layout === 'music' })}>
<div class={styles.inputContainer}>
<GrowingTextarea
allowEnterKey={true}
@ -286,7 +286,7 @@ export const EditView = (props: Props) => {
<div class={styles.validationError}>{formErrors.title}</div>
</Show>
<Show when={props.shout.layout === 'audio'}>
<Show when={props.shout.layout === 'music'}>
<div class={styles.additional}>
<input
type="text"
@ -314,7 +314,7 @@ export const EditView = (props: Props) => {
/>
</div>
</Show>
<Show when={props.shout.layout !== 'audio'}>
<Show when={props.shout.layout !== 'music'}>
<Show when={isSubtitleVisible()}>
<GrowingTextarea
textAreaRef={(el) => {
@ -340,7 +340,7 @@ export const EditView = (props: Props) => {
</Show>
</Show>
</div>
<Show when={props.shout.layout === 'audio'}>
<Show when={props.shout.layout === 'music'}>
<Show
when={form.coverImageUrl}
fallback={
@ -387,7 +387,7 @@ export const EditView = (props: Props) => {
/>
</Show>
<Show when={props.shout.layout === 'audio'}>
<Show when={props.shout.layout === 'music'}>
<AudioUploader
audio={mediaItems()}
baseFields={baseAudioFields()}

View File

@ -0,0 +1,17 @@
.Expo {
display: block;
background: #fef2f2;
padding: 0 0 4rem 0;
min-height: 100vh;
.navigation {
padding: 0 0;
}
.showMore {
display: flex;
width: 100%;
padding: 4rem 0 2rem;
align-items: center;
justify-content: center;
}
}

View File

@ -0,0 +1,174 @@
import styles from './Expo.module.scss'
import { LoadShoutsOptions, Shout } from '../../../graphql/types.gen'
import { createEffect, createMemo, createSignal, For, on, onCleanup, onMount, Show } from 'solid-js'
import { ArticleCard } from '../../Feed/ArticleCard'
import { Loading } from '../../_shared/Loading'
import { Button } from '../../_shared/Button'
import { useLocalize } from '../../../context/localize'
import { router, useRouter } from '../../../stores/router'
import { LayoutType } from '../../../pages/types'
import { loadShouts, resetSortedArticles, useArticlesStore } from '../../../stores/zine/articles'
import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll'
import { splitToPages } from '../../../utils/splitToPages'
import { clsx } from 'clsx'
import { getPagePath } from '@nanostores/router'
import { ConditionalWrapper } from '../../_shared/ConditionalWrapper'
type Props = {
shouts: Shout[]
}
export const PRERENDERED_ARTICLES_COUNT = 28
const LOAD_MORE_PAGE_SIZE = 16
export const Expo = (props: Props) => {
const [isLoaded, setIsLoaded] = createSignal<boolean>(Boolean(props.shouts))
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
const { t } = useLocalize()
const { page: getPage } = useRouter()
const getLayout = createMemo<LayoutType>(() => getPage().params['layout'] as LayoutType)
const { sortedArticles } = useArticlesStore({
shouts: isLoaded() ? props.shouts : []
})
const loadMore = async (count) => {
saveScrollPosition()
const options: LoadShoutsOptions = {
limit: count,
offset: sortedArticles().length
}
options.filters = getLayout() ? { layout: getLayout() } : { excludeLayout: 'article' }
const { hasMore } = await loadShouts(options)
setIsLoadMoreButtonVisible(hasMore)
restoreScrollPosition()
}
const pages = createMemo<Shout[][]>(() =>
splitToPages(sortedArticles(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE)
)
onMount(() => {
if (isLoaded()) {
return
}
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
setIsLoaded(true)
})
onMount(() => {
if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) {
loadMore(LOAD_MORE_PAGE_SIZE)
}
})
createEffect(
on(
() => getLayout(),
() => {
resetSortedArticles()
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
},
{ defer: true }
)
)
onCleanup(() => {
resetSortedArticles()
})
const handleLoadMoreClick = () => {
loadMore(LOAD_MORE_PAGE_SIZE)
}
return (
<div class={styles.Expo}>
<Show when={sortedArticles().length > 0} fallback={<Loading />}>
<div class="wide-container">
<ul class={clsx('view-switcher', styles.navigation)}>
<li class={clsx({ 'view-switcher__item--selected': !getLayout() })}>
<ConditionalWrapper
condition={Boolean(getLayout())}
wrapper={(children) => <a href={getPagePath(router, 'expo')}>{children}</a>}
>
<span class={clsx('linkReplacement')}>{t('All')}</span>
</ConditionalWrapper>
</li>
<li class={clsx({ 'view-switcher__item--selected': getLayout() === 'literature' })}>
<ConditionalWrapper
condition={getLayout() !== 'literature'}
wrapper={(children) => (
<a href={getPagePath(router, 'expoLayout', { layout: 'literature' })}>{children}</a>
)}
>
<span class={clsx('linkReplacement')}>{t('Literature')}</span>
</ConditionalWrapper>
</li>
<li class={clsx({ 'view-switcher__item--selected': getLayout() === 'music' })}>
<ConditionalWrapper
condition={getLayout() !== 'music'}
wrapper={(children) => (
<a href={getPagePath(router, 'expoLayout', { layout: 'music' })}>{children}</a>
)}
>
<span class={clsx('linkReplacement')}>{t('Music')}</span>
</ConditionalWrapper>
</li>
<li class={clsx({ 'view-switcher__item--selected': getLayout() === 'image' })}>
<ConditionalWrapper
condition={getLayout() !== 'image'}
wrapper={(children) => (
<a href={getPagePath(router, 'expoLayout', { layout: 'image' })}>{children}</a>
)}
>
<span class={clsx('linkReplacement')}>{t('Gallery')}</span>
</ConditionalWrapper>
</li>
<li class={clsx({ 'view-switcher__item--selected': getLayout() === 'video' })}>
<ConditionalWrapper
condition={getLayout() !== 'video'}
wrapper={(children) => (
<a href={getPagePath(router, 'expoLayout', { layout: 'video' })}>{children}</a>
)}
>
<span class={clsx('cursorPointer linkReplacement')}>{t('Video')}</span>
</ConditionalWrapper>
</li>
</ul>
<div class="row">
<For each={sortedArticles().slice(0, PRERENDERED_ARTICLES_COUNT)}>
{(shout) => (
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
<ArticleCard
article={shout}
settings={{ nodate: true, nosubtitle: true, noAuthorLink: true }}
/>
</div>
)}
</For>
<For each={pages()}>
{(page) => (
<For each={page}>
{(shout) => (
<div class="col-md-6 mt-md-5 col-sm-8 mt-sm-3">
<ArticleCard
article={shout}
settings={{ nodate: true, nosubtitle: true, noAuthorLink: true }}
/>
</div>
)}
</For>
)}
</For>
</div>
<Show when={isLoadMoreButtonVisible()}>
<div class={styles.showMore}>
<Button size="L" onClick={handleLoadMoreClick} value={t('Load more')} />
</div>
</Show>
</div>
</Show>
</div>
)
}

View File

@ -0,0 +1 @@
export { Expo } from './Expo'

View File

@ -1,6 +1,6 @@
import { createMemo, createSignal, For, onMount, Show } from 'solid-js'
import Banner from '../Discours/Banner'
import { NavTopics } from '../Nav/Topics'
import { Topics } from '../Nav/Topics'
import { Row5 } from '../Feed/Row5'
import { Row3 } from '../Feed/Row3'
import { Row2 } from '../Feed/Row2'
@ -104,7 +104,7 @@ export const HomeView = (props: Props) => {
return (
<Show when={sortedArticles().length > 0}>
<NavTopics />
<Topics />
<Row5 articles={sortedArticles().slice(0, 5)} nodate={true} />

View File

@ -1,3 +1,7 @@
.withPadding {
padding-top: 58px;
}
.zeroBottomPadding {
padding-bottom: 0;
}

View File

@ -18,6 +18,7 @@ type Props = {
hideFooter?: boolean
class?: string
withPadding?: boolean
zeroBottomPadding?: boolean
scrollToComments?: (value: boolean) => void
}
@ -44,7 +45,8 @@ export const PageLayout = (props: Props) => {
/>
<main
class={clsx('main-content', {
[styles.withPadding]: props.withPadding
[styles.withPadding]: props.withPadding,
[styles.zeroBottomPadding]: props.zeroBottomPadding
})}
classList={{ 'main-content--no-padding': !isHeaderFixed }}
>

View File

@ -44,7 +44,7 @@ export const CreatePage = () => {
</div>
</li>
<li>
<div class={styles.link} onClick={() => handleCreate('audio')}>
<div class={styles.link} onClick={() => handleCreate('music')}>
<Icon name="create-music" class={styles.icon} />
<div>{t('music')}</div>
</div>

View File

@ -0,0 +1,4 @@
import { ROUTES } from '../../stores/router'
import { getServerRoute } from '../../utils/getServerRoute'
export default getServerRoute(ROUTES.expo)

View File

@ -0,0 +1,17 @@
import type { PageContext } from '../../renderer/types'
import { apiClient } from '../../utils/apiClient'
import type { PageProps } from '../types'
import { PRERENDERED_ARTICLES_COUNT } from '../../components/Views/Expo/Expo'
export const onBeforeRender = async (_pageContext: PageContext) => {
const expoShouts = await apiClient.getShouts({
filters: { excludeLayout: 'article' },
limit: PRERENDERED_ARTICLES_COUNT
})
const pageProps: PageProps = { expoShouts }
return {
pageContext: {
pageProps
}
}
}

View File

@ -0,0 +1,44 @@
import { PageLayout } from '../../components/_shared/PageLayout'
import type { PageProps } from '../types'
import { Topics } from '../../components/Nav/Topics'
import { Expo } from '../../components/Views/Expo'
import { useLocalize } from '../../context/localize'
import { createMemo } from 'solid-js'
import { LayoutType } from '../types'
import { useRouter } from '../../stores/router'
import { Title } from '@solidjs/meta'
export const ExpoPage = (props: PageProps) => {
const { t } = useLocalize()
const { page: getPage } = useRouter()
const getLayout = createMemo<LayoutType>(() => getPage().params['layout'] as LayoutType)
const title = createMemo(() => {
switch (getLayout()) {
case 'music': {
return t('Audio')
}
case 'video': {
return t('Video')
}
case 'image': {
return t('Artworks')
}
case 'literature': {
return t('Literature')
}
default: {
return t('Art')
}
}
})
return (
<PageLayout withPadding={true} zeroBottomPadding={true}>
<Title>{title()}</Title>
<Topics />
<Expo shouts={props.expoShouts} />
</PageLayout>
)
}
export const Page = ExpoPage

View File

@ -0,0 +1,4 @@
import { ROUTES } from '../../stores/router'
import { getServerRoute } from '../../utils/getServerRoute'
export default getServerRoute(ROUTES.expoLayout)

View File

@ -0,0 +1,20 @@
import type { PageContext } from '../../renderer/types'
import { apiClient } from '../../utils/apiClient'
import type { PageProps } from '../types'
import { PRERENDERED_ARTICLES_COUNT } from '../../components/Views/Expo/Expo'
export const onBeforeRender = async (pageContext: PageContext) => {
const { layout } = pageContext.routeParams
const expoShouts = await apiClient.getShouts({
filters: { layout: layout },
limit: PRERENDERED_ARTICLES_COUNT
})
const pageProps: PageProps = { expoShouts }
return {
pageContext: {
pageProps
}
}
}

View File

@ -1,4 +0,0 @@
import { ROUTES } from '../stores/router'
import { getServerRoute } from '../utils/getServerRoute'
export default getServerRoute(ROUTES.expo)

View File

@ -1,18 +0,0 @@
import type { PageContext } from '../renderer/types'
import { apiClient } from '../utils/apiClient'
import type { PageProps } from './types'
import { PRERENDERED_ARTICLES_COUNT } from './layoutShouts.page'
export const onBeforeRender = async (pageContext: PageContext) => {
const { layout } = pageContext.routeParams
const layoutShouts = await apiClient.getShouts({ filters: { layout }, limit: PRERENDERED_ARTICLES_COUNT })
const pageProps: PageProps = { layoutShouts }
return {
pageContext: {
pageProps
}
}
}

View File

@ -1,187 +0,0 @@
import { PageLayout } from '../components/_shared/PageLayout'
import type { LayoutType, PageProps } from './types'
import { createEffect, createMemo, createSignal, For, onCleanup, onMount, Show } from 'solid-js'
import { loadShouts, resetSortedArticles, useArticlesStore } from '../stores/zine/articles'
import { router, useRouter } from '../stores/router'
import { Loading } from '../components/_shared/Loading'
import { restoreScrollPosition, saveScrollPosition } from '../utils/scroll'
import type { Shout } from '../graphql/types.gen'
import { splitToPages } from '../utils/splitToPages'
import { clsx } from 'clsx'
import { Row3 } from '../components/Feed/Row3'
import { Row2 } from '../components/Feed/Row2'
import { Beside } from '../components/Feed/Beside'
import { Slider } from '../components/_shared/Slider'
import { Row1 } from '../components/Feed/Row1'
import styles from '../styles/Topic.module.scss'
import { ArticleCard } from '../components/Feed/ArticleCard'
import { useLocalize } from '../context/localize'
import { getPagePath } from '@nanostores/router'
import { Title } from '@solidjs/meta'
export const PRERENDERED_ARTICLES_COUNT = 27
const LOAD_MORE_PAGE_SIZE = 9 // Row3 + Row3 + Row3
export const LayoutShoutsPage = (props: PageProps) => {
const { t } = useLocalize()
const { page: getPage } = useRouter()
const getLayout = createMemo<LayoutType>(() => getPage().params['layout'] as LayoutType)
const [isLoaded, setIsLoaded] = createSignal(
Boolean(props.layoutShouts) &&
props.layoutShouts.length > 0 &&
props.layoutShouts[0].layout === getLayout()
)
const { sortedArticles } = useArticlesStore({
shouts: isLoaded() ? props.layoutShouts : []
})
const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false)
const loadMore = async (count) => {
saveScrollPosition()
const { hasMore } = await loadShouts({
filters: { layout: getLayout() },
limit: count,
offset: sortedArticles().length
})
setIsLoadMoreButtonVisible(hasMore)
restoreScrollPosition()
}
const title = createMemo(() => {
const l = getLayout()
if (l === 'audio') return t('Audio')
if (l === 'video') return t('Video')
if (l === 'image') return t('Artworks')
return t('Literature')
})
const pages = createMemo<Shout[][]>(() =>
splitToPages(sortedArticles(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE)
)
onMount(() => {
if (isLoaded()) {
return
}
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
setIsLoaded(true)
})
onMount(() => {
if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) {
loadMore(LOAD_MORE_PAGE_SIZE)
}
})
createEffect((prevLayout) => {
if (prevLayout !== getLayout()) {
resetSortedArticles()
loadMore(PRERENDERED_ARTICLES_COUNT + LOAD_MORE_PAGE_SIZE)
}
return getLayout()
}, getLayout())
onCleanup(() => {
resetSortedArticles()
})
const handleLoadMoreClick = () => {
loadMore(LOAD_MORE_PAGE_SIZE)
}
return (
<PageLayout>
<Title>{title()}</Title>
<Show when={isLoaded()} fallback={<Loading />}>
<div class={styles.topicPage}>
<Show when={getLayout()}>
<div class="wide-container">
<h1>{title()}</h1>
</div>
<div class="wide-container">
<div class={clsx(styles.groupControls, 'row group__controls')}>
<div class="col-md-16">
<ul class="view-switcher">
<li classList={{ 'view-switcher__item--selected': getLayout() === 'audio' }}>
<a href={getPagePath(router, 'expo', { layout: 'audio' })}>{t('Audio')}</a>
</li>
<li classList={{ 'view-switcher__item--selected': getLayout() === 'video' }}>
<a href={getPagePath(router, 'expo', { layout: 'video' })}>{t('Video')}</a>
</li>
<li classList={{ 'view-switcher__item--selected': getLayout() === 'image' }}>
<a href={getPagePath(router, 'expo', { layout: 'image' })}>{t('Artworks')}</a>
</li>
<li classList={{ 'view-switcher__item--selected': getLayout() === 'literature' }}>
<a href={getPagePath(router, 'expo', { layout: 'literature' })}>{t('Literature')}</a>
</li>
</ul>
</div>
</div>
</div>
<Show when={sortedArticles().length > 0} fallback={<Loading />}>
<Row1 article={sortedArticles()[0]} />
<Row2 articles={sortedArticles().slice(1, 3)} />
<Slider title={title()}>
<For each={sortedArticles().slice(5, 11)}>
{(article) => (
<ArticleCard
article={article}
settings={{
additionalClass: 'swiper-slide',
isFloorImportant: true,
isWithCover: true,
nodate: true
}}
/>
)}
</For>
</Slider>
<Beside
beside={sortedArticles()[12]}
title={t('Top viewed')}
values={sortedArticles().slice(0, 5)}
wrapper={'top-article'}
/>
<Show when={sortedArticles().length > 5}>
<Row3 articles={sortedArticles().slice(13, 16)} />
<Row2 articles={sortedArticles().slice(16, 18)} />
<Row3 articles={sortedArticles().slice(18, 21)} />
<Row3 articles={sortedArticles().slice(21, 24)} />
<Row3 articles={sortedArticles().slice(24, 27)} />
</Show>
<For each={pages()}>
{(page) => (
<>
<Row3 articles={page.slice(0, 3)} />
<Row3 articles={page.slice(3, 6)} />
<Row3 articles={page.slice(6, 9)} />
</>
)}
</For>
<Show when={isLoadMoreButtonVisible()}>
<p class="load-more-container">
<button class="button" onClick={handleLoadMoreClick}>
{t('Load more')}
</button>
</p>
</Show>
</Show>
</Show>
</div>
</Show>
</PageLayout>
)
}
export const Page = LayoutShoutsPage

View File

@ -4,7 +4,7 @@ import type { Author, Chat, Shout, Topic } from '../graphql/types.gen'
// all the things (she said) that could be passed from the server
export type PageProps = {
article?: Shout
layoutShouts?: Shout[]
expoShouts?: Shout[]
authorShouts?: Shout[]
topicShouts?: Shout[]
homeShouts?: Shout[]
@ -24,7 +24,7 @@ export type RootSearchParams = {
lang: string
}
export type LayoutType = 'article' | 'audio' | 'video' | 'image' | 'literature'
export type LayoutType = 'article' | 'music' | 'video' | 'image' | 'literature'
export type FileTypeToUpload = 'image' | 'video' | 'doc' | 'audio'

View File

@ -37,7 +37,8 @@ export const ROUTES = {
projects: '/about/projects',
termsOfUse: '/about/terms-of-use',
thanks: '/about/thanks',
expo: '/expo/:layout',
expo: '/expo',
expoLayout: '/expo/:layout',
profileSettings: '/profile/settings',
profileSecurity: '/profile/security',
profileSubscriptions: '/profile/subscriptions',

View File

@ -623,7 +623,7 @@ figure {
a,
.linkReplacement,
button {
border-bottom: 2px solid #fff;
border-bottom: 2px solid transparent;
color: var(--link-color);
cursor: pointer;
font-weight: inherit;

View File

@ -325,7 +325,6 @@ export const apiClient = {
getShouts: async (options: LoadShoutsOptions) => {
const resp = await publicGraphQLClient.query(shoutsLoadBy, { options }).toPromise()
if (resp.error) {
console.error(resp)
}

View File

@ -2,18 +2,65 @@ import { defineConfig } from 'vite'
import solidPlugin from 'vite-plugin-solid'
import ssrPlugin from 'vite-plugin-ssr/plugin'
import sassDts from 'vite-plugin-sass-dts'
import mkcert from 'vite-plugin-mkcert'
const cssModuleHMR = () => {
return {
enforce: 'post',
name: 'css-module-hmr',
apply: 'serve',
handleHotUpdate(context) {
const { modules } = context
modules.forEach((module) => {
if (module.id.includes('.module.scss')) {
module.isSelfAccepting = true
}
})
}
}
}
const PATH_PREFIX = '/src/'
const getDevCssClassPrefix = (filename: string): string => {
return filename
.slice(filename.indexOf(PATH_PREFIX) + PATH_PREFIX.length)
.replace('.module.scss', '')
.replaceAll(/[/?\\]/g, '-')
}
const devGenerateScopedName = (name: string, filename: string, _css: string) =>
getDevCssClassPrefix(filename) + '__' + name
export default defineConfig(({ mode, command }) => {
const plugins = [
solidPlugin({ ssr: true }),
ssrPlugin({ includeAssetsImportedByServer: true }),
sassDts(),
cssModuleHMR()
]
if (command === 'serve') {
plugins.push(mkcert())
}
const isDev = mode === 'development'
export default defineConfig(() => {
return {
envPrefix: 'PUBLIC_',
plugins: [solidPlugin({ ssr: true }), ssrPlugin({ includeAssetsImportedByServer: true }), sassDts()],
plugins,
server: {
https: true,
port: 3000
},
css: {
devSourcemap: true,
devSourcemap: isDev,
preprocessorOptions: {
scss: { additionalData: '@import "src/styles/imports";\n' }
},
modules: {
generateScopedName: isDev ? devGenerateScopedName : '[hash:base64:5]'
}
},
build: {