mirror of
https://github.com/cheeaun/phanpy.git
synced 2025-03-14 04:08:32 +03:00
Merge branch 'cheeaun:main' into width-columns-css-fix
This commit is contained in:
commit
ef60f96816
60 changed files with 17553 additions and 16971 deletions
41
.github/ISSUE_TEMPLATE/bug_report.md
vendored
41
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -1,41 +0,0 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
- Which site: [e.g. dev.phanpy.social OR phanpy.social]
|
||||
- Which site version: [On Phanpy, go to Settings -> About]
|
||||
- Which instance: [e.g. mastodon.social]
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
81
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
81
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
|
@ -0,0 +1,81 @@
|
|||
name: "Bug report"
|
||||
description: "Create a report to help us improve"
|
||||
|
||||
labels:
|
||||
- "bug"
|
||||
|
||||
body:
|
||||
- type: input
|
||||
id: "site"
|
||||
attributes:
|
||||
label: "Site"
|
||||
description: |-
|
||||
What site(s) did you encounter this bug on?
|
||||
placeholder: |-
|
||||
phanpy.social
|
||||
|
||||
- type: input
|
||||
id: "version"
|
||||
attributes:
|
||||
label: "Version"
|
||||
description: |-
|
||||
Which Phanpy version(s) did you encounter this bug on?
|
||||
You can see and copy your current version by opening the Settings menu and scrolling down to the About section.
|
||||
placeholder: |-
|
||||
2024.10.08.0a176e2
|
||||
|
||||
- type: input
|
||||
id: "instance"
|
||||
attributes:
|
||||
label: "Instance"
|
||||
description: |-
|
||||
Which instance(s) did you encounter this bug on?
|
||||
placeholder: |-
|
||||
mastodon.social
|
||||
|
||||
- type: textarea
|
||||
id: "Browser"
|
||||
attributes:
|
||||
label: "Browser"
|
||||
description: |-
|
||||
Which browser(s) did you encounter this bug on?
|
||||
placeholder: |-
|
||||
- Firefox 132.0b5 on Windows 11
|
||||
- Safari 18 on iOS 18 on iPhone 16 Pro Max
|
||||
|
||||
- type: textarea
|
||||
id: "description"
|
||||
attributes:
|
||||
label: "Bug description"
|
||||
description: |-
|
||||
A concise description of what the bug is.
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
You can paste screenshots here and GitHub will convert them to Markdown for you.
|
||||
|
||||
- type: textarea
|
||||
id: "steps"
|
||||
attributes:
|
||||
label: "To reproduce"
|
||||
description: |-
|
||||
A list of steps that can be performed to make the bug happen again.
|
||||
If possible, add screenshots to help demonstrate the steps.
|
||||
You can paste screenshots here and GitHub will convert them to Markdown for you.
|
||||
placeholder: |-
|
||||
1. Go to '...'
|
||||
2. Click on '...'
|
||||
3. Scroll down to '...'
|
||||
4. See error
|
||||
|
||||
- type: textarea
|
||||
id: "behavior"
|
||||
attributes:
|
||||
label: "Expected behavior"
|
||||
description: |-
|
||||
A concise description of what you expected to happen.
|
||||
|
||||
- type: textarea
|
||||
id: "other"
|
||||
attributes:
|
||||
label: "Other"
|
||||
description: |-
|
||||
Anything you want to add?
|
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
blank_issues_enabled: true
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: 'enhancement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
37
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
37
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
name: "Feature request"
|
||||
description: "Suggest an idea for this project"
|
||||
|
||||
labels:
|
||||
- "enhancement"
|
||||
|
||||
|
||||
body:
|
||||
- type: textarea
|
||||
id: "problem"
|
||||
attributes:
|
||||
label: "Problem I have"
|
||||
description: |-
|
||||
If your request is related to a problem, please provide a clear and concise description of what the problem is.
|
||||
placeholder: |-
|
||||
I'm always frustrated when [...]
|
||||
|
||||
- type: textarea
|
||||
id: "solution"
|
||||
attributes:
|
||||
label: "Solution I'd like"
|
||||
description: |-
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
- type: textarea
|
||||
id: "alternatives"
|
||||
attributes:
|
||||
label: "Alternatives considered"
|
||||
description: |-
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
- type: textarea
|
||||
id: "other"
|
||||
attributes:
|
||||
label: "Other"
|
||||
description: |-
|
||||
Anything you want to add?
|
1
.github/workflows/main2prod.yml
vendored
1
.github/workflows/main2prod.yml
vendored
|
@ -7,6 +7,7 @@ on:
|
|||
|
||||
jobs:
|
||||
auto-pull-request:
|
||||
if: github.repository == 'cheeaun/phanpy'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: vsoch/pull-request-action@master
|
||||
|
|
|
@ -319,7 +319,7 @@ Costs involved in running and developing this web app:
|
|||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15791971/medium/88bdda3090339f16f6083390d32bb434_default.png" alt="" width="16" height="16" /> katullo11 (Italian)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/14677260/medium/e53420d200961f48602324e18c091bdc.png" alt="" width="16" height="16" /> Kytta (German)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16529521/medium/ae6add93a901b0fefa2d9b1077920d73.png" alt="" width="16" height="16" /> llun (Thai)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16291756/medium/e1c4210f15537394cc764b8bc2dffe37.jpg" alt="" width="16" height="16" /> lucasofchirst (Occitan, Portuguese, Portuguese, Brazilian)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16291756/medium/2366972cc86287353708aff1ded3f3c1.jpg" alt="" width="16" height="16" /> lucasofchirst (Occitan, Portuguese, Portuguese, Brazilian)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16537713/medium/825f0bf1a14fc545a76891a52839d86e_default.png" alt="" width="16" height="16" /> marcin.kozinski (Polish)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/13521465/medium/76cb9aa6b753ce900a70478bff7fcea0.png" alt="" width="16" height="16" /> mkljczkk (Polish)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/12882812/medium/77744d8db46e9a3e09030e1a02b7a572.jpeg" alt="" width="16" height="16" /> mojosoeun (Korean)
|
||||
|
@ -337,12 +337,14 @@ Costs involved in running and developing this web app:
|
|||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16539171/medium/0ce95ef6b3b0566136191fbedc1563d0.png" alt="" width="16" height="16" /> SadmL_AI (Russian)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/12381015/medium/35e3557fd61d85f9a5b84545d9e3feb4.png" alt="" width="16" height="16" /> shuuji3 (Japanese)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/14565190/medium/79100599131b7776e9803e4b696915a3_default.png" alt="" width="16" height="16" /> Sky_NiniKo (French)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/13143526/medium/30871da23d51d7e41bb02f3c92d7f104.png" alt="" width="16" height="16" /> Steffo99 (Italian)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16532441/medium/1a47e8d80c95636e02d2260f6e233ca5.png" alt="" width="16" height="16" /> Su5hicz (Czech)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16530049/medium/683f3581620c6b4a5c753b416ed695a7.jpeg" alt="" width="16" height="16" /> tferrermo (Spanish)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15752199/medium/7e9efd828c4691368d063b19d19eb894.png" alt="" width="16" height="16" /> tkbremnes (Norwegian Bokmal)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16527851/medium/649e5a9a8a8cc61ced670d89e9cca082.png" alt="" width="16" height="16" /> tux93 (German)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/14427566/medium/ab733b5044c21867fc5a9d1b22cd2c03.png" alt="" width="16" height="16" /> Vac31. (Lithuanian)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16026914/medium/e3ca187f354a298ef0c9d02a0ed17be7.jpg" alt="" width="16" height="16" /> valtlai (Finnish)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16608515/medium/85506c21dce8df07843ca11908ee3951.jpeg" alt="" width="16" height="16" /> vasiriri (Polish)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16563757/medium/af4556c13862d1fd593b51084a159b75_default.png" alt="" width="16" height="16" /> voyagercy (Chinese Traditional)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15982109/medium/9c03062bdc1d3c6d384dbfead97c26ba.jpeg" alt="" width="16" height="16" /> xabi_itzultzaile (Basque)
|
||||
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16556017/medium/216e0f7a0c35b079920366939a3aaca7_default.png" alt="" width="16" height="16" /> xen4n (Ukrainian)
|
||||
|
|
BIN
design/logo-bw-4.png
Normal file
BIN
design/logo-bw-4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
12
design/logo-bw-4.svg
Normal file
12
design/logo-bw-4.svg
Normal file
|
@ -0,0 +1,12 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" clip-rule="evenodd" viewBox="0 0 64 64">
|
||||
<path fill="none" d="M0 0h63.99v63.99H0z"/>
|
||||
<clipPath id="a">
|
||||
<path d="M0 0h63.99v63.99H0z"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#a)">
|
||||
<path d="M0 0h64.25v63.99H0z"/>
|
||||
<path fill="#fff" d="M37.77 11.47c14.64 3.75 19.04 16.56 15.9 31.3a12.55 12.55 0 0 1-6.36 8.7c-3.2 1.71-8.07 2.53-15.34.55l-9.64-2.4c-10.68-2.63-13.95-10.89-12.3-17.8 3.62-15.2 15.54-23.48 27.74-20.35Z"/>
|
||||
<path d="M36.76 15.43c12.29 3.15 15.55 14.11 12.9 26.5-.94 4.43-4.93 9.36-16.66 6.13l-9.68-2.41c-7.85-1.93-10.53-7.8-9.32-12.88 3.02-12.64 12.61-19.94 22.76-17.34Z"/>
|
||||
<path fill="#fff" d="M27.47 25c-1.46-.7-7.23 3.2-7.66 8.92-.18 2.39 4.55 3.23 5.07-.17.72-4.74 3.71-8.22 2.6-8.76Zm10.75 2c-2.09.32-.39 5.9-.6 10.72-.12 2.8 4.39 3.47 4.7 2.01 1.1-5.07-2.06-13.05-4.1-12.73Z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 954 B |
BIN
design/logo-wb-4.png
Normal file
BIN
design/logo-wb-4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
12
design/logo-wb-4.svg
Normal file
12
design/logo-wb-4.svg
Normal file
|
@ -0,0 +1,12 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" fill-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2" clip-rule="evenodd" viewBox="0 0 64 64">
|
||||
<path fill="none" d="M0 0h63.99v63.99H0z"/>
|
||||
<clipPath id="a">
|
||||
<path d="M0 0h63.99v63.99H0z"/>
|
||||
</clipPath>
|
||||
<g clip-path="url(#a)">
|
||||
<path fill="#fff" d="M0 0h64.25v63.99H0z"/>
|
||||
<path d="M37.77 11.47c14.64 3.75 19.04 16.56 15.9 31.3a12.55 12.55 0 0 1-6.36 8.7c-3.2 1.71-8.07 2.53-15.34.55l-9.64-2.4c-10.68-2.63-13.95-10.89-12.3-17.8 3.62-15.2 15.54-23.48 27.74-20.35Z"/>
|
||||
<path fill="#fff" d="M36.76 15.43c12.29 3.15 15.55 14.11 12.9 26.5-.94 4.43-4.93 9.36-16.66 6.13l-9.68-2.41c-7.85-1.93-10.53-7.8-9.32-12.88 3.02-12.64 12.61-19.94 22.76-17.34Z"/>
|
||||
<path d="M27.47 25c-1.46-.7-7.23 3.2-7.66 8.92-.18 2.39 4.55 3.23 5.07-.17.72-4.74 3.71-8.22 2.6-8.76Zm10.75 2c-2.09.32-.39 5.9-.6 10.72-.12 2.8 4.39 3.47 4.7 2.01 1.1-5.07-2.06-13.05-4.1-12.73Z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 954 B |
Binary file not shown.
540
package-lock.json
generated
540
package-lock.json
generated
File diff suppressed because it is too large
Load diff
26
package.json
26
package.json
|
@ -16,15 +16,15 @@
|
|||
"readme:i18n-volunteers": "node scripts/update-i18n-volunteers-readme.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@formatjs/intl-localematcher": "~0.5.4",
|
||||
"@formatjs/intl-segmenter": "~11.5.7",
|
||||
"@formatjs/intl-localematcher": "~0.5.5",
|
||||
"@formatjs/intl-segmenter": "~11.5.9",
|
||||
"@formkit/auto-animate": "~0.8.2",
|
||||
"@github/text-expander-element": "~2.7.1",
|
||||
"@github/text-expander-element": "~2.8.0",
|
||||
"@iconify-icons/mingcute": "~1.2.9",
|
||||
"@justinribeiro/lite-youtube": "~1.5.0",
|
||||
"@lingui/detect-locale": "~4.11.4",
|
||||
"@lingui/macro": "~4.11.4",
|
||||
"@lingui/react": "~4.11.4",
|
||||
"@lingui/detect-locale": "~4.13.0",
|
||||
"@lingui/macro": "~4.13.0",
|
||||
"@lingui/react": "~4.13.0",
|
||||
"@szhsin/react-menu": "~4.2.2",
|
||||
"compare-versions": "~6.1.1",
|
||||
"fast-blurhash": "~1.1.4",
|
||||
|
@ -36,11 +36,11 @@
|
|||
"js-cookie": "~3.0.5",
|
||||
"just-debounce-it": "~3.2.0",
|
||||
"lz-string": "~1.5.0",
|
||||
"masto": "~6.8.0",
|
||||
"masto": "~6.9.0",
|
||||
"moize": "~6.1.6",
|
||||
"p-retry": "~6.2.0",
|
||||
"p-throttle": "~6.2.0",
|
||||
"preact": "~10.24.0",
|
||||
"preact": "~10.24.3",
|
||||
"punycode": "~2.3.1",
|
||||
"react-hotkeys-hook": "~4.5.1",
|
||||
"react-intersection-observer": "~9.13.1",
|
||||
|
@ -51,22 +51,22 @@
|
|||
"tinyld": "~1.3.4",
|
||||
"toastify-js": "~1.12.0",
|
||||
"uid": "~2.0.2",
|
||||
"use-debounce": "~10.0.3",
|
||||
"use-debounce": "~10.0.4",
|
||||
"use-long-press": "~3.2.0",
|
||||
"use-resize-observer": "~9.1.0",
|
||||
"valtio": "2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ianvs/prettier-plugin-sort-imports": "~4.3.1",
|
||||
"@lingui/cli": "~4.11.4",
|
||||
"@lingui/vite-plugin": "~4.11.4",
|
||||
"@lingui/cli": "~4.13.0",
|
||||
"@lingui/vite-plugin": "~4.13.0",
|
||||
"@preact/preset-vite": "~2.9.1",
|
||||
"babel-plugin-macros": "~3.1.0",
|
||||
"postcss": "~8.4.47",
|
||||
"postcss-dark-theme-class": "~1.3.0",
|
||||
"postcss-preset-env": "~10.0.3",
|
||||
"postcss-preset-env": "~10.0.7",
|
||||
"twitter-text": "~3.1.0",
|
||||
"vite": "~5.4.7",
|
||||
"vite": "~5.4.9",
|
||||
"vite-plugin-generate-file": "~0.2.0",
|
||||
"vite-plugin-html-config": "~2.0.2",
|
||||
"vite-plugin-pwa": "~0.20.5",
|
||||
|
|
|
@ -413,7 +413,7 @@ function AccountInfo({
|
|||
<span>██</span> <Trans>Followers</Trans>
|
||||
</div>
|
||||
<div>
|
||||
<span>██</span> <Trans>Following</Trans>
|
||||
<span>██</span> <Trans id="following.stats">Following</Trans>
|
||||
</div>
|
||||
<div>
|
||||
<span>██</span> <Trans>Posts</Trans>
|
||||
|
@ -739,7 +739,10 @@ function AccountInfo({
|
|||
// states.showAccount = false;
|
||||
setTimeout(() => {
|
||||
states.showGenericAccounts = {
|
||||
heading: t`Following`,
|
||||
heading: t({
|
||||
id: 'following.stats',
|
||||
message: 'Following',
|
||||
}),
|
||||
fetchAccounts: fetchFollowing,
|
||||
instance,
|
||||
excludeRelationshipAttrs: isSelf ? ['following'] : [],
|
||||
|
@ -753,7 +756,7 @@ function AccountInfo({
|
|||
<span title={followingCount}>
|
||||
{shortenNumber(followingCount)}
|
||||
</span>{' '}
|
||||
<Trans>Following</Trans>
|
||||
<Trans id="following.stats">Following</Trans>
|
||||
<br />
|
||||
</LinkOrDiv>
|
||||
<LinkOrDiv
|
||||
|
|
|
@ -50,6 +50,7 @@ function Avatar({ url, size, alt = '', squircle, ...props }) {
|
|||
alt={alt}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
fetchPriority="low"
|
||||
crossOrigin={
|
||||
alphaCache[url] === undefined && !isMissing
|
||||
? 'anonymous'
|
||||
|
|
|
@ -197,6 +197,7 @@ function highlightText(text, { maxCharacters = Infinity }) {
|
|||
|
||||
// const rtf = new Intl.RelativeTimeFormat();
|
||||
const RTF = mem((locale) => new Intl.RelativeTimeFormat(locale || undefined));
|
||||
const LF = mem((locale) => new Intl.ListFormat(locale || undefined));
|
||||
|
||||
const CUSTOM_EMOJIS_COUNT = 100;
|
||||
|
||||
|
@ -210,6 +211,7 @@ function Compose({
|
|||
}) {
|
||||
const { i18n } = useLingui();
|
||||
const rtf = RTF(i18n.locale);
|
||||
const lf = LF(i18n.locale);
|
||||
|
||||
console.warn('RENDER COMPOSER');
|
||||
const { masto, instance } = api();
|
||||
|
@ -226,11 +228,11 @@ function Compose({
|
|||
const {
|
||||
statuses: {
|
||||
maxCharacters,
|
||||
maxMediaAttachments,
|
||||
maxMediaAttachments, // Beware: it can be undefined!
|
||||
charactersReservedPerUrl,
|
||||
} = {},
|
||||
mediaAttachments: {
|
||||
supportedMimeTypes = [],
|
||||
supportedMimeTypes,
|
||||
imageSizeLimit,
|
||||
imageMatrixLimit,
|
||||
videoSizeLimit,
|
||||
|
@ -600,15 +602,31 @@ function Compose({
|
|||
const handleItems = (e) => {
|
||||
const { items } = e.clipboardData || e.dataTransfer;
|
||||
const files = [];
|
||||
const unsupportedFiles = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
if (item.kind === 'file') {
|
||||
const file = item.getAsFile();
|
||||
if (file && supportedMimeTypes.includes(file.type)) {
|
||||
if (
|
||||
supportedMimeTypes !== undefined &&
|
||||
!supportedMimeTypes.includes(file.type)
|
||||
) {
|
||||
unsupportedFiles.push(file);
|
||||
} else {
|
||||
files.push(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unsupportedFiles.length > 0) {
|
||||
alert(
|
||||
plural(unsupportedFiles.length, {
|
||||
one: `File ${unsupportedFiles[0].name} is not supported.`,
|
||||
other: `Files ${lf.format(
|
||||
unsupportedFiles.map((f) => f.name),
|
||||
)} are not supported.`,
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (files.length > 0 && mediaAttachments.length >= maxMediaAttachments) {
|
||||
alert(
|
||||
plural(maxMediaAttachments, {
|
||||
|
@ -623,16 +641,19 @@ function Compose({
|
|||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
// Auto-cut-off files to avoid exceeding maxMediaAttachments
|
||||
const max = maxMediaAttachments - mediaAttachments.length;
|
||||
const allowedFiles = files.slice(0, max);
|
||||
if (allowedFiles.length <= 0) {
|
||||
alert(
|
||||
plural(maxMediaAttachments, {
|
||||
one: 'You can only attach up to 1 file.',
|
||||
other: 'You can only attach up to # files.',
|
||||
}),
|
||||
);
|
||||
return;
|
||||
let allowedFiles = files;
|
||||
if (maxMediaAttachments !== undefined) {
|
||||
const max = maxMediaAttachments - mediaAttachments.length;
|
||||
allowedFiles = allowedFiles.slice(0, max);
|
||||
if (allowedFiles.length <= 0) {
|
||||
alert(
|
||||
plural(maxMediaAttachments, {
|
||||
one: 'You can only attach up to 1 file.',
|
||||
other: 'You can only attach up to # files.',
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
const mediaFiles = allowedFiles.map((file) => ({
|
||||
file,
|
||||
|
@ -1307,8 +1328,11 @@ function Compose({
|
|||
<label class="toolbar-button">
|
||||
<input
|
||||
type="file"
|
||||
accept={supportedMimeTypes.join(',')}
|
||||
multiple={mediaAttachments.length < maxMediaAttachments - 1}
|
||||
accept={supportedMimeTypes?.join(',')}
|
||||
multiple={
|
||||
maxMediaAttachments === undefined ||
|
||||
maxMediaAttachments - mediaAttachments >= 2
|
||||
}
|
||||
disabled={
|
||||
uiState === 'loading' ||
|
||||
mediaAttachments.length >= maxMediaAttachments ||
|
||||
|
@ -1400,7 +1424,8 @@ function Compose({
|
|||
class="toolbar-button gif-picker-button"
|
||||
disabled={
|
||||
uiState === 'loading' ||
|
||||
mediaAttachments.length >= maxMediaAttachments ||
|
||||
(maxMediaAttachments !== undefined &&
|
||||
mediaAttachments.length >= maxMediaAttachments) ||
|
||||
!!poll
|
||||
}
|
||||
onClick={() => {
|
||||
|
|
|
@ -13,6 +13,7 @@ export default function CustomEmoji({ staticUrl, alt, url }) {
|
|||
height="16"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
fetchPriority="low"
|
||||
/>
|
||||
</picture>
|
||||
);
|
||||
|
|
|
@ -17,12 +17,17 @@ function EmojiText({ text, emojis }) {
|
|||
// 'g',
|
||||
// );
|
||||
const regex = shortcodesRegexp(emojis.map((e) => e.shortcode));
|
||||
const elements = text.split(regex).map((word) => {
|
||||
const elements = text.split(regex).map((word, i) => {
|
||||
const emoji = emojis.find((e) => e.shortcode === word);
|
||||
if (emoji) {
|
||||
const { url, staticUrl } = emoji;
|
||||
return (
|
||||
<CustomEmoji staticUrl={staticUrl} alt={word} url={url} key={word} />
|
||||
<CustomEmoji
|
||||
staticUrl={staticUrl}
|
||||
alt={word}
|
||||
url={url}
|
||||
key={word + '-' + i} // Handle >= 2 same shortcodes
|
||||
/>
|
||||
);
|
||||
}
|
||||
return word;
|
||||
|
|
|
@ -190,7 +190,7 @@ function NavMenu(props) {
|
|||
<MenuLink to="/following">
|
||||
<Icon icon="following" size="l" />{' '}
|
||||
<span>
|
||||
<Trans>Following</Trans>
|
||||
<Trans id="following.title">Following</Trans>
|
||||
</span>
|
||||
</MenuLink>
|
||||
)}
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Fragment } from 'preact';
|
|||
import { memo } from 'preact/compat';
|
||||
|
||||
import { api } from '../utils/api';
|
||||
import { isFiltered } from '../utils/filters';
|
||||
import shortenNumber from '../utils/shorten-number';
|
||||
import states, { statusKey } from '../utils/states';
|
||||
import { getCurrentAccountID } from '../utils/store-utils';
|
||||
|
@ -451,6 +452,16 @@ function Notification({
|
|||
notificationsCount > 0 && notificationsCount > sampleAccounts?.length;
|
||||
const expandAccounts = diffCount ? 'remote' : 'local';
|
||||
|
||||
// If there's a status and filter action is 'hide', then the notification is hidden
|
||||
// TODO: Handle 'warn' action one day
|
||||
if (!!status?.filtered) {
|
||||
const isOwnPost = status?.account?.id === currentAccount;
|
||||
const filterInfo = isFiltered(status.filtered, 'notifications');
|
||||
if (!isSelf && !isOwnPost && filterInfo?.action === 'hide') {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
class={`notification notification-${type}`}
|
||||
|
|
|
@ -134,7 +134,10 @@ const fetchAccountTitle = pmem(async ({ id }) => {
|
|||
export const SHORTCUTS_META = {
|
||||
following: {
|
||||
id: 'home',
|
||||
title: (_, index) => (index === 0 ? t`Home` : t`Following`),
|
||||
title: (_, index) =>
|
||||
index === 0
|
||||
? t`Home`
|
||||
: t({ id: 'following.title', message: 'Following' }),
|
||||
path: '/',
|
||||
icon: 'home',
|
||||
},
|
||||
|
|
|
@ -1292,6 +1292,9 @@ function Status({
|
|||
</span>
|
||||
</>
|
||||
}
|
||||
itemProps={{
|
||||
className: 'danger',
|
||||
}}
|
||||
menuItemClassName="danger"
|
||||
onClick={() => {
|
||||
// const yes = confirm('Delete this post?');
|
||||
|
@ -2785,6 +2788,8 @@ function Card({ card, selfReferential, selfAuthor, instance }) {
|
|||
width={width}
|
||||
height={height}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
fetchPriority="low"
|
||||
alt={imageDescription || ''}
|
||||
onError={(e) => {
|
||||
try {
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
"code": "de-DE",
|
||||
"nativeName": "Deutsch",
|
||||
"name": "German",
|
||||
"completion": 96
|
||||
"completion": 95
|
||||
},
|
||||
{
|
||||
"code": "eo-UY",
|
||||
|
@ -57,7 +57,7 @@
|
|||
"code": "fr-FR",
|
||||
"nativeName": "français",
|
||||
"name": "French",
|
||||
"completion": 99
|
||||
"completion": 98
|
||||
},
|
||||
{
|
||||
"code": "gl-ES",
|
||||
|
@ -87,13 +87,13 @@
|
|||
"code": "kab",
|
||||
"nativeName": "Taqbaylit",
|
||||
"name": "Kabyle",
|
||||
"completion": 100
|
||||
"completion": 99
|
||||
},
|
||||
{
|
||||
"code": "ko-KR",
|
||||
"nativeName": "한국어",
|
||||
"name": "Korean",
|
||||
"completion": 97
|
||||
"completion": 96
|
||||
},
|
||||
{
|
||||
"code": "lt-LT",
|
||||
|
@ -105,7 +105,7 @@
|
|||
"code": "nb-NO",
|
||||
"nativeName": "norsk bokmål",
|
||||
"name": "Norwegian Bokmål",
|
||||
"completion": 31
|
||||
"completion": 37
|
||||
},
|
||||
{
|
||||
"code": "nl-NL",
|
||||
|
|
1196
src/locales/ar-SA.po
generated
1196
src/locales/ar-SA.po
generated
File diff suppressed because it is too large
Load diff
1118
src/locales/ca-ES.po
generated
1118
src/locales/ca-ES.po
generated
File diff suppressed because it is too large
Load diff
1196
src/locales/cs-CZ.po
generated
1196
src/locales/cs-CZ.po
generated
File diff suppressed because it is too large
Load diff
1196
src/locales/de-DE.po
generated
1196
src/locales/de-DE.po
generated
File diff suppressed because it is too large
Load diff
982
src/locales/en.po
generated
982
src/locales/en.po
generated
File diff suppressed because it is too large
Load diff
986
src/locales/eo-UY.po
generated
986
src/locales/eo-UY.po
generated
File diff suppressed because it is too large
Load diff
1010
src/locales/es-ES.po
generated
1010
src/locales/es-ES.po
generated
File diff suppressed because it is too large
Load diff
1084
src/locales/eu-ES.po
generated
1084
src/locales/eu-ES.po
generated
File diff suppressed because it is too large
Load diff
1134
src/locales/fa-IR.po
generated
1134
src/locales/fa-IR.po
generated
File diff suppressed because it is too large
Load diff
1198
src/locales/fi-FI.po
generated
1198
src/locales/fi-FI.po
generated
File diff suppressed because it is too large
Load diff
1200
src/locales/fr-FR.po
generated
1200
src/locales/fr-FR.po
generated
File diff suppressed because it is too large
Load diff
1200
src/locales/gl-ES.po
generated
1200
src/locales/gl-ES.po
generated
File diff suppressed because it is too large
Load diff
1194
src/locales/he-IL.po
generated
1194
src/locales/he-IL.po
generated
File diff suppressed because it is too large
Load diff
1206
src/locales/it-IT.po
generated
1206
src/locales/it-IT.po
generated
File diff suppressed because it is too large
Load diff
1198
src/locales/ja-JP.po
generated
1198
src/locales/ja-JP.po
generated
File diff suppressed because it is too large
Load diff
1200
src/locales/kab.po
generated
1200
src/locales/kab.po
generated
File diff suppressed because it is too large
Load diff
1196
src/locales/ko-KR.po
generated
1196
src/locales/ko-KR.po
generated
File diff suppressed because it is too large
Load diff
984
src/locales/lt-LT.po
generated
984
src/locales/lt-LT.po
generated
File diff suppressed because it is too large
Load diff
1086
src/locales/nb-NO.po
generated
1086
src/locales/nb-NO.po
generated
File diff suppressed because it is too large
Load diff
1208
src/locales/nl-NL.po
generated
1208
src/locales/nl-NL.po
generated
File diff suppressed because it is too large
Load diff
1194
src/locales/oc-FR.po
generated
1194
src/locales/oc-FR.po
generated
File diff suppressed because it is too large
Load diff
1202
src/locales/pl-PL.po
generated
1202
src/locales/pl-PL.po
generated
File diff suppressed because it is too large
Load diff
1200
src/locales/pt-BR.po
generated
1200
src/locales/pt-BR.po
generated
File diff suppressed because it is too large
Load diff
1200
src/locales/pt-PT.po
generated
1200
src/locales/pt-PT.po
generated
File diff suppressed because it is too large
Load diff
1202
src/locales/ru-RU.po
generated
1202
src/locales/ru-RU.po
generated
File diff suppressed because it is too large
Load diff
1194
src/locales/th-TH.po
generated
1194
src/locales/th-TH.po
generated
File diff suppressed because it is too large
Load diff
1194
src/locales/uk-UA.po
generated
1194
src/locales/uk-UA.po
generated
File diff suppressed because it is too large
Load diff
1200
src/locales/zh-CN.po
generated
1200
src/locales/zh-CN.po
generated
File diff suppressed because it is too large
Load diff
1194
src/locales/zh-TW.po
generated
1194
src/locales/zh-TW.po
generated
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,14 @@ import useTitle from '../utils/useTitle';
|
|||
const LIMIT = 20;
|
||||
|
||||
function Following({ title, path, id, ...props }) {
|
||||
useTitle(title || t`Following`, path || '/following');
|
||||
useTitle(
|
||||
title ||
|
||||
t({
|
||||
id: 'following.title',
|
||||
message: 'Following',
|
||||
}),
|
||||
path || '/following',
|
||||
);
|
||||
const { masto, streaming, instance } = api();
|
||||
const snapStates = useSnapshot(states);
|
||||
const homeIterator = useRef();
|
||||
|
@ -131,7 +138,7 @@ function Following({ title, path, id, ...props }) {
|
|||
|
||||
return (
|
||||
<Timeline
|
||||
title={title || t`Following`}
|
||||
title={title || t({ id: 'following.title', message: 'Following' })}
|
||||
id={id || 'following'}
|
||||
emptyText={t`Nothing to see here.`}
|
||||
errorText={t`Unable to load posts.`}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#settings-container {
|
||||
background-color: var(--bg-faded-color);
|
||||
/* Prevent immediate text size change affecting max width */
|
||||
max-width: calc(40 * var(--current-text-size) - 50px - 16px);
|
||||
}
|
||||
|
||||
#settings-container main h3 {
|
||||
|
|
|
@ -63,7 +63,14 @@ function Settings({ onClose }) {
|
|||
// }, []);
|
||||
|
||||
return (
|
||||
<div id="settings-container" class="sheet" tabIndex="-1">
|
||||
<div
|
||||
id="settings-container"
|
||||
class="sheet"
|
||||
tabIndex="-1"
|
||||
style={{
|
||||
'--current-text-size': `${currentTextSize}px`,
|
||||
}}
|
||||
>
|
||||
{!!onClose && (
|
||||
<button type="button" class="sheet-close" onClick={onClose}>
|
||||
<Icon icon="x" alt={t`Close`} />
|
||||
|
|
|
@ -44,6 +44,8 @@ import useTitle from '../utils/useTitle';
|
|||
|
||||
import getInstanceStatusURL from './../utils/get-instance-status-url';
|
||||
|
||||
const { PHANPY_DEFAULT_INSTANCE: DEFAULT_INSTANCE } = import.meta.env;
|
||||
|
||||
const LIMIT = 40;
|
||||
const SUBCOMMENTS_OPEN_ALL_LIMIT = 10;
|
||||
const MAX_WEIGHT = 5;
|
||||
|
@ -562,7 +564,10 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
|||
useTitle(
|
||||
heroDisplayName && heroContentText
|
||||
? `${heroDisplayName}: "${heroContentText}"`
|
||||
: t`Post`,
|
||||
: t({
|
||||
id: 'post.title',
|
||||
message: 'Post',
|
||||
}),
|
||||
'/:instance?/s/:id',
|
||||
);
|
||||
|
||||
|
@ -788,7 +793,14 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
|||
not possible.
|
||||
</Trans>
|
||||
</p>
|
||||
<Link to="/login" class="button">
|
||||
<Link
|
||||
to={
|
||||
DEFAULT_INSTANCE
|
||||
? `/login?instance=${DEFAULT_INSTANCE}&submit=1`
|
||||
: '/login'
|
||||
}
|
||||
class="button"
|
||||
>
|
||||
<Trans>Log in</Trans>
|
||||
</Link>
|
||||
</div>
|
||||
|
@ -1085,7 +1097,7 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
|
|||
</>
|
||||
) : (
|
||||
<>
|
||||
Post{' '}
|
||||
<Trans id="post.title">Post</Trans>{' '}
|
||||
<button
|
||||
type="button"
|
||||
class="ancestors-indicator light small"
|
||||
|
|
|
@ -8,7 +8,7 @@ function emojifyText(text, emojis = []) {
|
|||
const { shortcode, staticUrl, url } = emoji;
|
||||
text = text.replace(
|
||||
new RegExp(`:${shortcode}:`, 'g'),
|
||||
`<picture><source srcset="${staticUrl}" media="(prefers-reduced-motion: reduce)"></source><img class="shortcode-emoji emoji" src="${url}" alt=":${shortcode}:" width="16" height="16" loading="lazy" decoding="async" /></picture>`,
|
||||
`<picture><source srcset="${staticUrl}" media="(prefers-reduced-motion: reduce)"></source><img class="shortcode-emoji emoji" src="${url}" alt=":${shortcode}:" width="16" height="16" loading="lazy" decoding="async" fetchPriority="low" /></picture>`,
|
||||
);
|
||||
});
|
||||
// console.log(text, emojis);
|
||||
|
|
|
@ -19,20 +19,27 @@ function escapeHTML(html) {
|
|||
|
||||
const LINK_REGEX = /<a/i;
|
||||
const HTTP_LINK_REGEX = /^https?:\/\//i;
|
||||
const MENTION_REGEX = /^@[^@]+(@[^@]+)?$/g;
|
||||
const HASHTAG_REGEX = /^#[^#]+$/g;
|
||||
const CODE_BLOCK_REGEX = /^```[^]+```$/g;
|
||||
const CODE_BLOCK_START_REGEX = /^```/g;
|
||||
const CODE_BLOCK_END_REGEX = /```$/g;
|
||||
const INLINE_CODE_REGEX = /`[^`]+`/g;
|
||||
const MENTION_REGEX = /^@[^@]+(@[^@]+)?$/;
|
||||
const HASHTAG_REGEX = /^#[^#]+$/;
|
||||
const CODE_BLOCK_REGEX = /^```[^]+```$/;
|
||||
const CODE_BLOCK_START_REGEX = /^```/;
|
||||
const CODE_BLOCK_END_REGEX = /```$/;
|
||||
const INLINE_CODE_REGEX = /`[^`]+`/;
|
||||
const TWITTER_DOMAIN_REGEX = /(twitter|x)\.com/i;
|
||||
const TWITTER_MENTION_REGEX = /@[a-zA-Z0-9_]+@(twitter|x)\.com/g;
|
||||
const TWITTER_MENTION_REGEX = /@[a-zA-Z0-9_]+@(twitter|x)\.com/;
|
||||
const TWITTER_MENTION_CAPTURE_REGEX = /(@([a-zA-Z0-9_]+)@(twitter|x)\.com)/g;
|
||||
const CODE_INLINE_CAPTURE_REGEX = /(`[^]+?`)/g;
|
||||
|
||||
function createDOM(html, isDocumentFragment) {
|
||||
const tpl = document.createElement('template');
|
||||
tpl.innerHTML = html;
|
||||
return isDocumentFragment ? tpl.content : tpl;
|
||||
if (isDocumentFragment) {
|
||||
const tpl = document.createElement('template');
|
||||
tpl.innerHTML = html;
|
||||
return tpl.content;
|
||||
} else {
|
||||
const tpl = document.createElement('div');
|
||||
tpl.innerHTML = html;
|
||||
return tpl;
|
||||
}
|
||||
}
|
||||
|
||||
function _enhanceContent(content, opts = {}) {
|
||||
|
@ -110,13 +117,11 @@ function _enhanceContent(content, opts = {}) {
|
|||
// ======
|
||||
// Convert :shortcode: to <img />
|
||||
let textNodes;
|
||||
if (enhancedContent.includes(':')) {
|
||||
if (enhancedContent.includes(':') && emojis?.length) {
|
||||
textNodes = extractTextNodes(dom);
|
||||
for (const node of textNodes) {
|
||||
let html = escapeHTML(node.nodeValue);
|
||||
if (emojis) {
|
||||
html = emojifyText(html, emojis);
|
||||
}
|
||||
html = emojifyText(html, emojis);
|
||||
fauxDiv.innerHTML = html;
|
||||
node.replaceWith(...fauxDiv.childNodes);
|
||||
}
|
||||
|
@ -193,7 +198,7 @@ function _enhanceContent(content, opts = {}) {
|
|||
for (const node of textNodes) {
|
||||
let html = escapeHTML(node.nodeValue);
|
||||
if (INLINE_CODE_REGEX.test(html)) {
|
||||
html = html.replaceAll(/(`[^]+?`)/g, '<code>$1</code>');
|
||||
html = html.replaceAll(CODE_INLINE_CAPTURE_REGEX, '<code>$1</code>');
|
||||
}
|
||||
fauxDiv.innerHTML = html;
|
||||
// const nodes = [...fauxDiv.childNodes];
|
||||
|
|
|
@ -118,18 +118,14 @@ export function getCurrentInstance() {
|
|||
// Massage these instance configurations to match the Mastodon API
|
||||
// - Pleroma
|
||||
function getInstanceConfiguration(instance) {
|
||||
const {
|
||||
configuration,
|
||||
maxMediaAttachments,
|
||||
maxTootChars,
|
||||
pleroma,
|
||||
pollLimits,
|
||||
} = instance;
|
||||
const { configuration, maxMediaAttachments, maxTootChars, pollLimits } =
|
||||
instance;
|
||||
|
||||
const statuses = configuration?.statuses || {};
|
||||
if (maxMediaAttachments) {
|
||||
statuses.maxMediaAttachments ??= maxMediaAttachments;
|
||||
}
|
||||
|
||||
if (maxTootChars) {
|
||||
statuses.maxCharacters ??= maxTootChars;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue