mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-18 10:37:45 +00:00
Merge commit 'd730f6b0c5cfb18894d1a9e34d0aa2556dda3c62' into glitch-soc/merge-upstream
This commit is contained in:
42
.github/workflows/build-releases.yml
vendored
42
.github/workflows/build-releases.yml
vendored
@@ -9,7 +9,44 @@ permissions:
|
|||||||
packages: write
|
packages: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
check-latest-stable:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
latest: ${{ steps.check.outputs.is_latest_stable }}
|
||||||
|
steps:
|
||||||
|
# Repository needs to be cloned to list branches
|
||||||
|
- name: Clone repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check latest stable
|
||||||
|
shell: bash
|
||||||
|
id: check
|
||||||
|
run: |
|
||||||
|
ref="${GITHUB_REF#refs/tags/}"
|
||||||
|
|
||||||
|
if [[ "$ref" =~ ^v([0-9]+)\.([0-9]+)(\.[0-9]+)?$ ]]; then
|
||||||
|
current="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
|
||||||
|
else
|
||||||
|
echo "tag $ref is not semver"
|
||||||
|
echo "is_latest_stable=false" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
latest=$(git for-each-ref --format='%(refname:short)' "refs/remotes/origin/stable-*.*" \
|
||||||
|
| sed -E 's#^origin/stable-##' \
|
||||||
|
| sort -Vr \
|
||||||
|
| head -n1)
|
||||||
|
|
||||||
|
if [[ "$current" == "$latest" ]]; then
|
||||||
|
echo "is_latest_stable=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "is_latest_stable=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
build-image:
|
build-image:
|
||||||
|
needs: check-latest-stable
|
||||||
uses: ./.github/workflows/build-container-image.yml
|
uses: ./.github/workflows/build-container-image.yml
|
||||||
with:
|
with:
|
||||||
file_to_build: Dockerfile
|
file_to_build: Dockerfile
|
||||||
@@ -20,13 +57,14 @@ jobs:
|
|||||||
# Only tag with latest when ran against the latest stable branch
|
# Only tag with latest when ran against the latest stable branch
|
||||||
# This needs to be updated after each minor version release
|
# This needs to be updated after each minor version release
|
||||||
flavor: |
|
flavor: |
|
||||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.5.') }}
|
latest=${{ needs.check-latest-stable.outputs.latest }}
|
||||||
tags: |
|
tags: |
|
||||||
type=pep440,pattern={{raw}}
|
type=pep440,pattern={{raw}}
|
||||||
type=pep440,pattern=v{{major}}.{{minor}}
|
type=pep440,pattern=v{{major}}.{{minor}}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
build-image-streaming:
|
build-image-streaming:
|
||||||
|
needs: check-latest-stable
|
||||||
uses: ./.github/workflows/build-container-image.yml
|
uses: ./.github/workflows/build-container-image.yml
|
||||||
with:
|
with:
|
||||||
file_to_build: streaming/Dockerfile
|
file_to_build: streaming/Dockerfile
|
||||||
@@ -37,7 +75,7 @@ jobs:
|
|||||||
# Only tag with latest when ran against the latest stable branch
|
# Only tag with latest when ran against the latest stable branch
|
||||||
# This needs to be updated after each minor version release
|
# This needs to be updated after each minor version release
|
||||||
flavor: |
|
flavor: |
|
||||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.5.') }}
|
latest=${{ needs.check-latest-stable.outputs.latest }}
|
||||||
tags: |
|
tags: |
|
||||||
type=pep440,pattern={{raw}}
|
type=pep440,pattern={{raw}}
|
||||||
type=pep440,pattern=v{{major}}.{{minor}}
|
type=pep440,pattern=v{{major}}.{{minor}}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ GEM
|
|||||||
erubi (~> 1.11)
|
erubi (~> 1.11)
|
||||||
rails-dom-testing (~> 2.2)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.6)
|
rails-html-sanitizer (~> 1.6)
|
||||||
active_model_serializers (0.10.15)
|
active_model_serializers (0.10.16)
|
||||||
actionpack (>= 4.1)
|
actionpack (>= 4.1)
|
||||||
activemodel (>= 4.1)
|
activemodel (>= 4.1)
|
||||||
case_transform (>= 0.2)
|
case_transform (>= 0.2)
|
||||||
@@ -481,7 +481,7 @@ GEM
|
|||||||
addressable (~> 2.8)
|
addressable (~> 2.8)
|
||||||
nokogiri (~> 1.12)
|
nokogiri (~> 1.12)
|
||||||
omniauth (~> 2.1)
|
omniauth (~> 2.1)
|
||||||
omniauth-rails_csrf_protection (2.0.0)
|
omniauth-rails_csrf_protection (2.0.1)
|
||||||
actionpack (>= 4.2)
|
actionpack (>= 4.2)
|
||||||
omniauth (~> 2.0)
|
omniauth (~> 2.0)
|
||||||
omniauth-saml (2.2.4)
|
omniauth-saml (2.2.4)
|
||||||
@@ -839,7 +839,8 @@ GEM
|
|||||||
stackprof (0.2.27)
|
stackprof (0.2.27)
|
||||||
starry (0.2.0)
|
starry (0.2.0)
|
||||||
base64
|
base64
|
||||||
stoplight (5.6.0)
|
stoplight (5.7.0)
|
||||||
|
concurrent-ruby
|
||||||
zeitwerk
|
zeitwerk
|
||||||
stringio (3.1.8)
|
stringio (3.1.8)
|
||||||
strong_migrations (2.5.1)
|
strong_migrations (2.5.1)
|
||||||
|
|||||||
BIN
app/javascript/images/archetypes/previews/booster.jpg
Normal file
BIN
app/javascript/images/archetypes/previews/booster.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 170 KiB |
BIN
app/javascript/images/archetypes/previews/lurker.jpg
Normal file
BIN
app/javascript/images/archetypes/previews/lurker.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 145 KiB |
BIN
app/javascript/images/archetypes/previews/oracle.jpg
Normal file
BIN
app/javascript/images/archetypes/previews/oracle.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 167 KiB |
BIN
app/javascript/images/archetypes/previews/pollster.jpg
Normal file
BIN
app/javascript/images/archetypes/previews/pollster.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 165 KiB |
BIN
app/javascript/images/archetypes/previews/replier.jpg
Normal file
BIN
app/javascript/images/archetypes/previews/replier.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
@@ -0,0 +1,45 @@
|
|||||||
|
import { useCallback, useRef } from 'react';
|
||||||
|
|
||||||
|
export const InterceptStatusClicks: React.FC<{
|
||||||
|
onPreventedClick: (
|
||||||
|
clickedArea: 'account' | 'post',
|
||||||
|
event: React.MouseEvent,
|
||||||
|
) => void;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}> = ({ onPreventedClick, children }) => {
|
||||||
|
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
|
const handleClick = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
const clickTarget = e.target as Element;
|
||||||
|
const allowedElementsSelector =
|
||||||
|
'.video-player, .audio-player, .media-gallery, .content-warning';
|
||||||
|
const allowedElements = wrapperRef.current?.querySelectorAll(
|
||||||
|
allowedElementsSelector,
|
||||||
|
);
|
||||||
|
const isTargetClickAllowed =
|
||||||
|
allowedElements &&
|
||||||
|
Array.from(allowedElements).some((element) => {
|
||||||
|
return clickTarget === element || element.contains(clickTarget);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isTargetClickAllowed) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
const wasAccountAreaClicked = !!clickTarget.closest(
|
||||||
|
'a.status__display-name',
|
||||||
|
);
|
||||||
|
|
||||||
|
onPreventedClick(wasAccountAreaClicked ? 'account' : 'post', e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onPreventedClick],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={wrapperRef} onClickCapture={handleClick}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -4,10 +4,14 @@
|
|||||||
@typescript-eslint/no-unsafe-member-access,
|
@typescript-eslint/no-unsafe-member-access,
|
||||||
@typescript-eslint/no-unsafe-call */
|
@typescript-eslint/no-unsafe-call */
|
||||||
|
|
||||||
|
import type { ComponentPropsWithoutRef } from 'react';
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { InterceptStatusClicks } from 'mastodon/components/status/intercept_status_clicks';
|
||||||
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
|
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
|
||||||
import type { TopStatuses } from 'mastodon/models/annual_report';
|
import type { TopStatuses } from 'mastodon/models/annual_report';
|
||||||
import { makeGetStatus } from 'mastodon/selectors';
|
import { makeGetStatus } from 'mastodon/selectors';
|
||||||
@@ -29,6 +33,24 @@ export const HighlightedPost: React.FC<{
|
|||||||
statusId ? getStatus(state, { id: statusId }) : undefined,
|
statusId ? getStatus(state, { id: statusId }) : undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleClick = useCallback<
|
||||||
|
ComponentPropsWithoutRef<typeof InterceptStatusClicks>['onPreventedClick']
|
||||||
|
>(
|
||||||
|
(clickedArea) => {
|
||||||
|
const link: string =
|
||||||
|
clickedArea === 'account'
|
||||||
|
? status.getIn(['account', 'url'])
|
||||||
|
: status.get('url');
|
||||||
|
|
||||||
|
if (context === 'standalone') {
|
||||||
|
window.location.href = link;
|
||||||
|
} else {
|
||||||
|
window.open(link, '_blank');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[status, context],
|
||||||
|
);
|
||||||
|
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return <div className={classNames(styles.box, styles.mostBoostedPost)} />;
|
return <div className={classNames(styles.box, styles.mostBoostedPost)} />;
|
||||||
}
|
}
|
||||||
@@ -72,7 +94,9 @@ export const HighlightedPost: React.FC<{
|
|||||||
{context === 'modal' && <p>{label}</p>}
|
{context === 'modal' && <p>{label}</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<InterceptStatusClicks onPreventedClick={handleClick}>
|
||||||
<StatusQuoteManager showActions={false} id={statusId} />
|
<StatusQuoteManager showActions={false} id={statusId} />
|
||||||
|
</InterceptStatusClicks>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,18 +10,17 @@ $mobile-breakpoint: 540px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modalWrapper {
|
.modalWrapper {
|
||||||
position: absolute;
|
box-sizing: border-box;
|
||||||
inset: 0;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
pointer-events: none;
|
|
||||||
scrollbar-color: var(--color-text-secondary) var(--color-bg-secondary);
|
scrollbar-color: var(--color-text-secondary) var(--color-bg-secondary);
|
||||||
|
|
||||||
@media (width < $mobile-breakpoint) {
|
@media (width < $mobile-breakpoint) {
|
||||||
padding-inline: 10px;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-indicator .circular-progress {
|
.loading-indicator .circular-progress {
|
||||||
@@ -50,37 +49,51 @@ $mobile-breakpoint: 540px;
|
|||||||
}
|
}
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
|
--gradient-strength: 0.4;
|
||||||
|
|
||||||
|
box-sizing: border-box;
|
||||||
position: relative;
|
position: relative;
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
|
padding-top: 40px;
|
||||||
contain: layout;
|
contain: layout;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
pointer-events: auto;
|
pointer-events: all;
|
||||||
color: var(--color-text-primary);
|
color: var(--color-text-primary);
|
||||||
background: var(--color-bg-primary);
|
background: var(--color-bg-primary);
|
||||||
background:
|
background:
|
||||||
radial-gradient(at 40% 87%, #240c9a99 0, transparent 50%),
|
radial-gradient(
|
||||||
radial-gradient(at 19% 10%, #6b0c9a99 0, transparent 50%),
|
at 10% 27%,
|
||||||
radial-gradient(at 90% 27%, #9a0c8299 0, transparent 50%),
|
rgba(83, 12, 154, var(--gradient-strength)) 0,
|
||||||
radial-gradient(at 16% 95%, #1e948299 0, transparent 50%),
|
transparent 50%
|
||||||
radial-gradient(at 80% 91%, #16dae499 0, transparent 50%)
|
),
|
||||||
|
radial-gradient(
|
||||||
|
at 91% 10%,
|
||||||
|
rgba(30, 24, 223, var(--gradient-strength)) 0,
|
||||||
|
transparent 25%
|
||||||
|
),
|
||||||
|
radial-gradient(
|
||||||
|
at 10% 91%,
|
||||||
|
rgba(22, 218, 228, var(--gradient-strength)) 0,
|
||||||
|
transparent 40%
|
||||||
|
),
|
||||||
|
radial-gradient(
|
||||||
|
at 75% 87%,
|
||||||
|
rgba(37, 31, 217, var(--gradient-strength)) 0,
|
||||||
|
transparent 20%
|
||||||
|
),
|
||||||
|
radial-gradient(
|
||||||
|
at 84% 60%,
|
||||||
|
rgba(95, 30, 148, var(--gradient-strength)) 0,
|
||||||
|
transparent 40%
|
||||||
|
)
|
||||||
var(--color-bg-primary);
|
var(--color-bg-primary);
|
||||||
border-radius: 40px;
|
border-radius: 40px;
|
||||||
|
|
||||||
@media (width < $mobile-breakpoint) {
|
@media (width < $mobile-breakpoint) {
|
||||||
padding-inline: 12px;
|
padding-inline: 12px;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
border-radius: 28px;
|
border-radius: 0;
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
z-index: -1;
|
|
||||||
background: inherit;
|
|
||||||
border-radius: inherit;
|
|
||||||
filter: blur(20px);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +105,7 @@ $mobile-breakpoint: 540px;
|
|||||||
font-family: silkscreen-wrapstodon, monospace;
|
font-family: silkscreen-wrapstodon, monospace;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 4px;
|
||||||
padding-inline: 40px; // Prevent overlap with close button
|
padding-inline: 40px; // Prevent overlap with close button
|
||||||
|
|
||||||
@media (width < $mobile-breakpoint) {
|
@media (width < $mobile-breakpoint) {
|
||||||
@@ -116,7 +129,7 @@ $mobile-breakpoint: 540px;
|
|||||||
|
|
||||||
.box {
|
.box {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 16px;
|
padding: 24px;
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
background: rgb(from var(--color-bg-primary) r g b / 60%);
|
background: rgb(from var(--color-bg-primary) r g b / 60%);
|
||||||
box-shadow: inset 0 0 0 1px rgb(from var(--color-text-primary) r g b / 40%);
|
box-shadow: inset 0 0 0 1px rgb(from var(--color-text-primary) r g b / 40%);
|
||||||
@@ -150,7 +163,6 @@ $mobile-breakpoint: 540px;
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
padding: 16px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
text-wrap: balance;
|
text-wrap: balance;
|
||||||
@@ -164,6 +176,10 @@ $mobile-breakpoint: 540px;
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
color: #c2c8ff;
|
color: #c2c8ff;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: -3px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.statLarge {
|
.statLarge {
|
||||||
@@ -185,7 +201,7 @@ $mobile-breakpoint: 540px;
|
|||||||
|
|
||||||
.mostBoostedPost {
|
.mostBoostedPost {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
padding-top: 8px;
|
padding-top: 24px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +276,7 @@ $mobile-breakpoint: 540px;
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 12px;
|
gap: 16px;
|
||||||
|
|
||||||
p {
|
p {
|
||||||
max-width: 460px;
|
max-width: 460px;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { defineMessage, useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { useLocation } from 'react-router';
|
import { useLocation } from 'react-router';
|
||||||
|
|
||||||
@@ -23,11 +23,6 @@ import { NewPosts } from './new_posts';
|
|||||||
|
|
||||||
const moduleClassNames = classNames.bind(styles);
|
const moduleClassNames = classNames.bind(styles);
|
||||||
|
|
||||||
export const shareMessage = defineMessage({
|
|
||||||
id: 'annual_report.summary.share_message',
|
|
||||||
defaultMessage: 'I got the {archetype} archetype!',
|
|
||||||
});
|
|
||||||
|
|
||||||
export const AnnualReport: FC<{ context?: 'modal' | 'standalone' }> = ({
|
export const AnnualReport: FC<{ context?: 'modal' | 'standalone' }> = ({
|
||||||
context = 'standalone',
|
context = 'standalone',
|
||||||
}) => {
|
}) => {
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { useEffect } from 'react';
|
import { useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { closeModal } from '@/mastodon/actions/modal';
|
||||||
|
import { useAppDispatch } from '@/mastodon/store';
|
||||||
|
|
||||||
import { AnnualReport } from '.';
|
import { AnnualReport } from '.';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
@@ -12,13 +15,24 @@ const AnnualReportModal: React.FC<{
|
|||||||
onChangeBackgroundColor('var(--color-bg-media-base)');
|
onChangeBackgroundColor('var(--color-bg-media-base)');
|
||||||
}, [onChangeBackgroundColor]);
|
}, [onChangeBackgroundColor]);
|
||||||
|
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
const handleCloseModal = useCallback(() => {
|
||||||
|
dispatch(closeModal({ modalType: 'ANNUAL_REPORT', ignoreFocus: false }));
|
||||||
|
}, [dispatch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
// It's fine not to provide a keyboard handler here since there is a global
|
||||||
|
// [Esc] key listener that will close open modals.
|
||||||
|
// This onClick handler is needed since the modalWrapper styles overlap the
|
||||||
|
// default modal backdrop, preventing clicks to pass through.
|
||||||
|
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'modal-root__modal',
|
'modal-root__modal',
|
||||||
styles.modalWrapper,
|
styles.modalWrapper,
|
||||||
'theme-dark',
|
'theme-dark',
|
||||||
)}
|
)}
|
||||||
|
onClick={handleCloseModal}
|
||||||
>
|
>
|
||||||
<AnnualReport context='modal' />
|
<AnnualReport context='modal' />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
|
|
||||||
import { useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { resetCompose, focusCompose } from '@/mastodon/actions/compose';
|
import { resetCompose, focusCompose } from '@/mastodon/actions/compose';
|
||||||
import { closeModal } from '@/mastodon/actions/modal';
|
import { closeModal } from '@/mastodon/actions/modal';
|
||||||
@@ -9,9 +9,19 @@ import { Button } from '@/mastodon/components/button';
|
|||||||
import type { AnnualReport as AnnualReportData } from '@/mastodon/models/annual_report';
|
import type { AnnualReport as AnnualReportData } from '@/mastodon/models/annual_report';
|
||||||
import { useAppDispatch } from '@/mastodon/store';
|
import { useAppDispatch } from '@/mastodon/store';
|
||||||
|
|
||||||
import { shareMessage } from '.';
|
|
||||||
import { archetypeNames } from './archetype';
|
import { archetypeNames } from './archetype';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
share_message: {
|
||||||
|
id: 'annual_report.summary.share_message',
|
||||||
|
defaultMessage: 'I got the {archetype} archetype!',
|
||||||
|
},
|
||||||
|
share_on_mastodon: {
|
||||||
|
id: 'annual_report.summary.share_on_mastodon',
|
||||||
|
defaultMessage: 'Share on Mastodon',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export const ShareButton: FC<{ report: AnnualReportData }> = ({ report }) => {
|
export const ShareButton: FC<{ report: AnnualReportData }> = ({ report }) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
@@ -21,7 +31,7 @@ export const ShareButton: FC<{ report: AnnualReportData }> = ({ report }) => {
|
|||||||
archetypeNames[report.data.archetype],
|
archetypeNames[report.data.archetype],
|
||||||
);
|
);
|
||||||
const shareLines = [
|
const shareLines = [
|
||||||
intl.formatMessage(shareMessage, {
|
intl.formatMessage(messages.share_message, {
|
||||||
archetype: archetypeName,
|
archetype: archetypeName,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
@@ -37,5 +47,10 @@ export const ShareButton: FC<{ report: AnnualReportData }> = ({ report }) => {
|
|||||||
dispatch(closeModal({ modalType: 'ANNUAL_REPORT', ignoreFocus: false }));
|
dispatch(closeModal({ modalType: 'ANNUAL_REPORT', ignoreFocus: false }));
|
||||||
}, [report, intl, dispatch]);
|
}, [report, intl, dispatch]);
|
||||||
|
|
||||||
return <Button text='Share here' onClick={handleShareClick} />;
|
return (
|
||||||
|
<Button
|
||||||
|
text={intl.formatMessage(messages.share_on_mastodon)}
|
||||||
|
onClick={handleShareClick}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
|
$mobile-breakpoint: 540px;
|
||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
max-width: max-content;
|
box-sizing: border-box;
|
||||||
|
max-width: 600px;
|
||||||
margin-inline: auto;
|
margin-inline: auto;
|
||||||
padding: 40px 10px;
|
padding: 40px 10px;
|
||||||
|
|
||||||
|
@media (width < $mobile-breakpoint) {
|
||||||
|
padding-top: 0;
|
||||||
|
padding-inline: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
@@ -5,7 +5,7 @@ import { FormattedMessage } from 'react-intl';
|
|||||||
import { IconLogo } from '@/mastodon/components/logo';
|
import { IconLogo } from '@/mastodon/components/logo';
|
||||||
|
|
||||||
import { AnnualReport } from './index';
|
import { AnnualReport } from './index';
|
||||||
import classes from './shared_page.module.css';
|
import classes from './shared_page.module.scss';
|
||||||
|
|
||||||
export const WrapstodonSharedPage: FC = () => {
|
export const WrapstodonSharedPage: FC = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -152,6 +152,7 @@
|
|||||||
"annual_report.summary.percentile.text": "<topLabel>That puts you in the top</topLabel><percentage></percentage><bottomLabel>of {domain} users.</bottomLabel>",
|
"annual_report.summary.percentile.text": "<topLabel>That puts you in the top</topLabel><percentage></percentage><bottomLabel>of {domain} users.</bottomLabel>",
|
||||||
"annual_report.summary.percentile.we_wont_tell_bernie": "We won't tell Bernie.",
|
"annual_report.summary.percentile.we_wont_tell_bernie": "We won't tell Bernie.",
|
||||||
"annual_report.summary.share_message": "I got the {archetype} archetype!",
|
"annual_report.summary.share_message": "I got the {archetype} archetype!",
|
||||||
|
"annual_report.summary.share_on_mastodon": "Share on Mastodon",
|
||||||
"attachments_list.unprocessed": "(unprocessed)",
|
"attachments_list.unprocessed": "(unprocessed)",
|
||||||
"audio.hide": "Hide audio",
|
"audio.hide": "Hide audio",
|
||||||
"block_modal.remote_users_caveat": "We will ask the server {domain} to respect your decision. However, compliance is not guaranteed since some servers may handle blocks differently. Public posts may still be visible to non-logged-in users.",
|
"block_modal.remote_users_caveat": "We will ask the server {domain} to respect your decision. However, compliance is not guaranteed since some servers may handle blocks differently. Public posts may still be visible to non-logged-in users.",
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ class AnnualReport::TopStatuses < AnnualReport::Source
|
|||||||
{
|
{
|
||||||
top_statuses: {
|
top_statuses: {
|
||||||
by_reblogs: status_identifier(most_reblogged_status),
|
by_reblogs: status_identifier(most_reblogged_status),
|
||||||
by_favourites: status_identifier(most_favourited_status),
|
by_favourites: nil,
|
||||||
by_replies: status_identifier(most_replied_status),
|
by_replies: nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def eligible?
|
def eligible?
|
||||||
report_statuses.public_visibility.exists?
|
report_statuses.distributable_visibility.exists?
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -43,7 +43,7 @@ class AnnualReport::TopStatuses < AnnualReport::Source
|
|||||||
|
|
||||||
def base_scope
|
def base_scope
|
||||||
report_statuses
|
report_statuses
|
||||||
.public_visibility
|
.distributable_visibility
|
||||||
.joins(:status_stat)
|
.joins(:status_stat)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -451,6 +451,10 @@ class Account < ApplicationRecord
|
|||||||
save!
|
save!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def featureable?
|
||||||
|
local? && discoverable?
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def prepare_contents
|
def prepare_contents
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ class CollectionItem < ApplicationRecord
|
|||||||
validates :account, presence: true, if: :accepted?
|
validates :account, presence: true, if: :accepted?
|
||||||
validates :object_uri, presence: true, if: -> { account.nil? }
|
validates :object_uri, presence: true, if: -> { account.nil? }
|
||||||
|
|
||||||
|
before_validation :set_position, on: :create
|
||||||
|
|
||||||
scope :ordered, -> { order(position: :asc) }
|
scope :ordered, -> { order(position: :asc) }
|
||||||
scope :with_accounts, -> { includes(account: [:account_stat, :user]) }
|
scope :with_accounts, -> { includes(account: [:account_stat, :user]) }
|
||||||
scope :not_blocked_by, ->(account) { where.not(accounts: { id: account.blocking }) }
|
scope :not_blocked_by, ->(account) { where.not(accounts: { id: account.blocking }) }
|
||||||
@@ -39,4 +41,12 @@ class CollectionItem < ApplicationRecord
|
|||||||
def local_item_with_remote_account?
|
def local_item_with_remote_account?
|
||||||
local? && account&.remote?
|
local? && account&.remote?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_position
|
||||||
|
return if position_changed?
|
||||||
|
|
||||||
|
self.position = self.class.where(collection_id:).maximum(:position).to_i + 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -64,4 +64,8 @@ class AccountPolicy < ApplicationPolicy
|
|||||||
def review?
|
def review?
|
||||||
role.can?(:manage_taxonomies)
|
role.can?(:manage_taxonomies)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def feature?
|
||||||
|
record.featureable? && !current_account.blocking?(record) && !record.blocking?(current_account)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
23
app/services/add_account_to_collection_service.rb
Normal file
23
app/services/add_account_to_collection_service.rb
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddAccountToCollectionService
|
||||||
|
def call(collection, account)
|
||||||
|
raise ArgumentError unless collection.local?
|
||||||
|
|
||||||
|
@collection = collection
|
||||||
|
@account = account
|
||||||
|
|
||||||
|
raise Mastodon::NotPermittedError, I18n.t('accounts.errors.cannot_be_added_to_collections') unless AccountPolicy.new(@collection.account, @account).feature?
|
||||||
|
|
||||||
|
create_collection_item
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def create_collection_item
|
||||||
|
@collection.collection_items.create!(
|
||||||
|
account: @account,
|
||||||
|
state: :accepted
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
6
app/views/wrapstodon/_og_image.html.haml
Normal file
6
app/views/wrapstodon/_og_image.html.haml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
- if %w(lurker booster pollster replier oracle).include?(report.data['archetype'])
|
||||||
|
= opengraph 'og:image', frontend_asset_url("images/archetypes/previews/#{report.data['archetype']}.jpg")
|
||||||
|
= opengraph 'og:image:type', 'image/jpeg'
|
||||||
|
= opengraph 'og:image:width', 1200
|
||||||
|
= opengraph 'og:image:height', 630
|
||||||
|
= opengraph 'twitter:card', 'summary_large_image'
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
= opengraph 'profile:username', acct(@account)[1..]
|
= opengraph 'profile:username', acct(@account)[1..]
|
||||||
|
|
||||||
= render 'og_description', account: @account
|
= render 'og_description', account: @account
|
||||||
|
= render 'og_image', report: @generated_annual_report
|
||||||
|
|
||||||
= flavoured_vite_typescript_tag 'wrapstodon.tsx', crossorigin: 'anonymous'
|
= flavoured_vite_typescript_tag 'wrapstodon.tsx', crossorigin: 'anonymous'
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ en:
|
|||||||
hosted_on: Mastodon hosted on %{domain}
|
hosted_on: Mastodon hosted on %{domain}
|
||||||
title: About
|
title: About
|
||||||
accounts:
|
accounts:
|
||||||
|
errors:
|
||||||
|
cannot_be_added_to_collections: This account cannot be added to collections.
|
||||||
followers:
|
followers:
|
||||||
one: Follower
|
one: Follower
|
||||||
other: Followers
|
other: Followers
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ RSpec.describe AnnualReport::TopStatuses do
|
|||||||
.to include(
|
.to include(
|
||||||
top_statuses: include(
|
top_statuses: include(
|
||||||
by_reblogs: reblogged_status.id.to_s,
|
by_reblogs: reblogged_status.id.to_s,
|
||||||
by_favourites: favourited_status.id.to_s,
|
by_favourites: nil,
|
||||||
by_replies: replied_status.id.to_s
|
by_replies: nil
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -781,4 +781,37 @@ RSpec.describe Account do
|
|||||||
expect(subject.reload.followers_count).to eq 15
|
expect(subject.reload.followers_count).to eq 15
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#featureable?' do
|
||||||
|
subject { Fabricate.build(:account, domain: (local ? nil : 'example.com'), discoverable:) }
|
||||||
|
|
||||||
|
context 'when account is local' do
|
||||||
|
let(:local) { true }
|
||||||
|
|
||||||
|
context 'when account is discoverable' do
|
||||||
|
let(:discoverable) { true }
|
||||||
|
|
||||||
|
it 'returns `true`' do
|
||||||
|
expect(subject.featureable?).to be true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when account is not discoverable' do
|
||||||
|
let(:discoverable) { false }
|
||||||
|
|
||||||
|
it 'returns `false`' do
|
||||||
|
expect(subject.featureable?).to be false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when account is remote' do
|
||||||
|
let(:local) { false }
|
||||||
|
let(:discoverable) { true }
|
||||||
|
|
||||||
|
it 'returns `false`' do
|
||||||
|
expect(subject.featureable?).to be false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -38,4 +38,23 @@ RSpec.describe CollectionItem do
|
|||||||
it { is_expected.to validate_presence_of(:object_uri) }
|
it { is_expected.to validate_presence_of(:object_uri) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'Creation' do
|
||||||
|
let(:collection) { Fabricate(:collection) }
|
||||||
|
let(:other_collection) { Fabricate(:collection) }
|
||||||
|
let(:account) { Fabricate(:account) }
|
||||||
|
let(:other_account) { Fabricate(:account) }
|
||||||
|
|
||||||
|
it 'automatically sets the `position` if absent' do
|
||||||
|
first_item = collection.collection_items.create(account:)
|
||||||
|
second_item = collection.collection_items.create(account: other_account)
|
||||||
|
unrelated_item = other_collection.collection_items.create(account:)
|
||||||
|
custom_item = other_collection.collection_items.create(account: other_account, position: 7)
|
||||||
|
|
||||||
|
expect(first_item.position).to eq 1
|
||||||
|
expect(second_item.position).to eq 2
|
||||||
|
expect(unrelated_item.position).to eq 1
|
||||||
|
expect(custom_item.position).to eq 7
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -156,4 +156,36 @@ RSpec.describe AccountPolicy do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
permissions :feature? do
|
||||||
|
context 'when account is featureable?' do
|
||||||
|
it 'permits' do
|
||||||
|
expect(subject).to permit(alice, john)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when account is not featureable' do
|
||||||
|
before { allow(alice).to receive(:featureable?).and_return(false) }
|
||||||
|
|
||||||
|
it 'denies' do
|
||||||
|
expect(subject).to_not permit(john, alice)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when account is blocked' do
|
||||||
|
before { alice.block!(john) }
|
||||||
|
|
||||||
|
it 'denies' do
|
||||||
|
expect(subject).to_not permit(alice, john)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when account is blocking' do
|
||||||
|
before { john.block!(alice) }
|
||||||
|
|
||||||
|
it 'denies' do
|
||||||
|
expect(subject).to_not permit(alice, john)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -75,6 +75,33 @@ RSpec.describe 'Credentials' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with client credentials' do
|
||||||
|
let(:application) { Fabricate(:application, scopes: 'read admin:write') }
|
||||||
|
let(:token) { Fabricate(:client_credentials_token, application: application, scopes: 'read admin:write') }
|
||||||
|
let(:headers) { { 'Authorization' => "Bearer #{token.token}" } }
|
||||||
|
|
||||||
|
it 'returns http success and returns app information' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response).to have_http_status(200)
|
||||||
|
expect(response.content_type)
|
||||||
|
.to start_with('application/json')
|
||||||
|
|
||||||
|
expect(response.parsed_body).to match(
|
||||||
|
a_hash_including(
|
||||||
|
id: token.application.id.to_s,
|
||||||
|
name: token.application.name,
|
||||||
|
website: token.application.website,
|
||||||
|
scopes: token.application.scopes.map(&:to_s),
|
||||||
|
redirect_uris: token.application.redirect_uris,
|
||||||
|
# Deprecated properties as of 4.3:
|
||||||
|
redirect_uri: token.application.redirect_uri.split.first,
|
||||||
|
vapid_key: Rails.configuration.x.vapid.public_key
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'without an oauth token' do
|
context 'without an oauth token' do
|
||||||
let(:headers) { {} }
|
let(:headers) { {} }
|
||||||
|
|
||||||
|
|||||||
35
spec/services/add_account_to_collection_service_spec.rb
Normal file
35
spec/services/add_account_to_collection_service_spec.rb
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe AddAccountToCollectionService do
|
||||||
|
subject { described_class.new }
|
||||||
|
|
||||||
|
let(:collection) { Fabricate.create(:collection) }
|
||||||
|
|
||||||
|
describe '#call' do
|
||||||
|
context 'when given a featurable account' do
|
||||||
|
let(:account) { Fabricate(:account) }
|
||||||
|
|
||||||
|
it 'creates a new CollectionItem in the `accepted` state' do
|
||||||
|
expect do
|
||||||
|
subject.call(collection, account)
|
||||||
|
end.to change(collection.collection_items, :count).by(1)
|
||||||
|
|
||||||
|
new_item = collection.collection_items.last
|
||||||
|
expect(new_item.state).to eq 'accepted'
|
||||||
|
expect(new_item.account).to eq account
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when given an account that is not featureable' do
|
||||||
|
let(:account) { Fabricate(:account, discoverable: false) }
|
||||||
|
|
||||||
|
it 'raises an error' do
|
||||||
|
expect do
|
||||||
|
subject.call(collection, account)
|
||||||
|
end.to raise_error(Mastodon::NotPermittedError)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -120,6 +120,8 @@ export const config: UserConfigFnPromise = async ({ mode, command }) => {
|
|||||||
manifest: true,
|
manifest: true,
|
||||||
outDir,
|
outDir,
|
||||||
assetsDir: 'assets',
|
assetsDir: 'assets',
|
||||||
|
assetsInlineLimit: (filePath, _) =>
|
||||||
|
/\.woff2?$/.exec(filePath) ? false : undefined,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: await findEntrypoints(),
|
input: await findEntrypoints(),
|
||||||
output: {
|
output: {
|
||||||
|
|||||||
88
yarn.lock
88
yarn.lock
@@ -12,10 +12,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@acemir/cssom@npm:^0.9.23":
|
"@acemir/cssom@npm:^0.9.28":
|
||||||
version: 0.9.24
|
version: 0.9.28
|
||||||
resolution: "@acemir/cssom@npm:0.9.24"
|
resolution: "@acemir/cssom@npm:0.9.28"
|
||||||
checksum: 10c0/1c7bf8a61a74d9ecbc3b12fba697384461b3234441ed5a10f5c34aef91fdf4f1e3322fcd6659a8eaddd591eddc2259efd278212236100d90a6e16f77794d98bd
|
checksum: 10c0/1e192d216c4236171d9930b42b9a965052d4578b23c6ddaa17c7c3d0820ffb872258544a83af163ae2d41b3bdccd6b6c4c14b2d32eb9f8b8b63972d74f46bd83
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -46,29 +46,29 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@asamuzakjp/css-color@npm:^4.0.3":
|
"@asamuzakjp/css-color@npm:^4.1.0":
|
||||||
version: 4.0.4
|
version: 4.1.0
|
||||||
resolution: "@asamuzakjp/css-color@npm:4.0.4"
|
resolution: "@asamuzakjp/css-color@npm:4.1.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@csstools/css-calc": "npm:^2.1.4"
|
"@csstools/css-calc": "npm:^2.1.4"
|
||||||
"@csstools/css-color-parser": "npm:^3.0.10"
|
"@csstools/css-color-parser": "npm:^3.1.0"
|
||||||
"@csstools/css-parser-algorithms": "npm:^3.0.5"
|
"@csstools/css-parser-algorithms": "npm:^3.0.5"
|
||||||
"@csstools/css-tokenizer": "npm:^3.0.4"
|
"@csstools/css-tokenizer": "npm:^3.0.4"
|
||||||
lru-cache: "npm:^11.1.0"
|
lru-cache: "npm:^11.2.2"
|
||||||
checksum: 10c0/5a4eb3c8594f58f3df06c867a6cda4a33f702f5cd682d6afa5074813f16fd05e732653ac79bd6fc66390554e158ac478103ad5e885fd9cf154b69bb67639e82f
|
checksum: 10c0/097b9270a5befb765885dda43d6914ccbaa575565525d307e8ba3ba07f98e466062f4a77b9657e65160db9110c41c59cf5a6937479647f73637aeddf5c421579
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@asamuzakjp/dom-selector@npm:^6.7.4":
|
"@asamuzakjp/dom-selector@npm:^6.7.6":
|
||||||
version: 6.7.5
|
version: 6.7.6
|
||||||
resolution: "@asamuzakjp/dom-selector@npm:6.7.5"
|
resolution: "@asamuzakjp/dom-selector@npm:6.7.6"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@asamuzakjp/nwsapi": "npm:^2.3.9"
|
"@asamuzakjp/nwsapi": "npm:^2.3.9"
|
||||||
bidi-js: "npm:^1.0.3"
|
bidi-js: "npm:^1.0.3"
|
||||||
css-tree: "npm:^3.1.0"
|
css-tree: "npm:^3.1.0"
|
||||||
is-potential-custom-element-name: "npm:^1.0.1"
|
is-potential-custom-element-name: "npm:^1.0.1"
|
||||||
lru-cache: "npm:^11.2.2"
|
lru-cache: "npm:^11.2.4"
|
||||||
checksum: 10c0/72ac4dc45aac9165222345aacc1db51a84094f159e9e2fa71bc89befd2d78fd00a76c7ff9a8a1ceb60e7ce198a4ec0275a4d878bea67b756cadbf3d9680162c4
|
checksum: 10c0/1715faae0787f0c8430b3a0ff3db8576a5b9a4f964408d0808fc2060ab01e0c2f5d8e26409de54b8641433c891dab8b561b196e58798811146084c561a4954ce
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -1275,7 +1275,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@csstools/css-color-parser@npm:^3.0.10, @csstools/css-color-parser@npm:^3.1.0":
|
"@csstools/css-color-parser@npm:^3.1.0":
|
||||||
version: 3.1.0
|
version: 3.1.0
|
||||||
resolution: "@csstools/css-color-parser@npm:3.1.0"
|
resolution: "@csstools/css-color-parser@npm:3.1.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1297,7 +1297,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@csstools/css-syntax-patches-for-csstree@npm:^1.0.14":
|
"@csstools/css-syntax-patches-for-csstree@npm:1.0.14":
|
||||||
version: 1.0.14
|
version: 1.0.14
|
||||||
resolution: "@csstools/css-syntax-patches-for-csstree@npm:1.0.14"
|
resolution: "@csstools/css-syntax-patches-for-csstree@npm:1.0.14"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3341,10 +3341,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@rolldown/pluginutils@npm:1.0.0-beta.47":
|
"@rolldown/pluginutils@npm:1.0.0-beta.53":
|
||||||
version: 1.0.0-beta.47
|
version: 1.0.0-beta.53
|
||||||
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.47"
|
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.53"
|
||||||
checksum: 10c0/eb0cfa7334d66f090c47eaac612174936b05f26e789352428cb6e03575b590f355de30d26b42576ea4e613d8887b587119d19b2e4b3a8909ceb232ca1cf746c8
|
checksum: 10c0/e8b0a7eb76be22f6f103171f28072de821525a4e400454850516da91a7381957932ff0ce495f227bcb168e86815788b0c1d249ca9e34dca366a82c8825b714ce
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -4830,18 +4830,18 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@vitejs/plugin-react@npm:^5.0.0":
|
"@vitejs/plugin-react@npm:^5.0.0":
|
||||||
version: 5.1.1
|
version: 5.1.2
|
||||||
resolution: "@vitejs/plugin-react@npm:5.1.1"
|
resolution: "@vitejs/plugin-react@npm:5.1.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/core": "npm:^7.28.5"
|
"@babel/core": "npm:^7.28.5"
|
||||||
"@babel/plugin-transform-react-jsx-self": "npm:^7.27.1"
|
"@babel/plugin-transform-react-jsx-self": "npm:^7.27.1"
|
||||||
"@babel/plugin-transform-react-jsx-source": "npm:^7.27.1"
|
"@babel/plugin-transform-react-jsx-source": "npm:^7.27.1"
|
||||||
"@rolldown/pluginutils": "npm:1.0.0-beta.47"
|
"@rolldown/pluginutils": "npm:1.0.0-beta.53"
|
||||||
"@types/babel__core": "npm:^7.20.5"
|
"@types/babel__core": "npm:^7.20.5"
|
||||||
react-refresh: "npm:^0.18.0"
|
react-refresh: "npm:^0.18.0"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
|
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
|
||||||
checksum: 10c0/e590efaea1eabfbb1beb6e8c9fac0742fd299808e3368e63b2825ce24740adb8a28fcb2668b14b7ca1bdb42890cfefe94d02dd358dcbbf8a27ddf377b9a82abf
|
checksum: 10c0/d788f269cdf7474425071ba7c4ea7013f174ddaef12b758defe809a551a03ac62a4a80cd858872deb618e7936ccc7cffe178bc12b62e9c836a467e13f15b9390
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -6253,14 +6253,14 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"cssstyle@npm:^5.3.3":
|
"cssstyle@npm:^5.3.4":
|
||||||
version: 5.3.3
|
version: 5.3.4
|
||||||
resolution: "cssstyle@npm:5.3.3"
|
resolution: "cssstyle@npm:5.3.4"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@asamuzakjp/css-color": "npm:^4.0.3"
|
"@asamuzakjp/css-color": "npm:^4.1.0"
|
||||||
"@csstools/css-syntax-patches-for-csstree": "npm:^1.0.14"
|
"@csstools/css-syntax-patches-for-csstree": "npm:1.0.14"
|
||||||
css-tree: "npm:^3.1.0"
|
css-tree: "npm:^3.1.0"
|
||||||
checksum: 10c0/0e082992851a1ded3662bda420f86dc1c90510a21cf237ddf573a1e121a722a3f78bb8f6eb46b33f267da25162e8e1fe968f7002114c9ab1d0d4e11dad9c5ee8
|
checksum: 10c0/7499ea8cbc2f759ded275428e0811d147baa6a964a44577711cee5edabee2230cf76b6bd20a556603f99ebc6fff80afdcba6c00bcbb1d41ae50cd09cd9fe9a2d
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -8959,12 +8959,12 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"jsdom@npm:^27.0.0":
|
"jsdom@npm:^27.0.0":
|
||||||
version: 27.2.0
|
version: 27.3.0
|
||||||
resolution: "jsdom@npm:27.2.0"
|
resolution: "jsdom@npm:27.3.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@acemir/cssom": "npm:^0.9.23"
|
"@acemir/cssom": "npm:^0.9.28"
|
||||||
"@asamuzakjp/dom-selector": "npm:^6.7.4"
|
"@asamuzakjp/dom-selector": "npm:^6.7.6"
|
||||||
cssstyle: "npm:^5.3.3"
|
cssstyle: "npm:^5.3.4"
|
||||||
data-urls: "npm:^6.0.0"
|
data-urls: "npm:^6.0.0"
|
||||||
decimal.js: "npm:^10.6.0"
|
decimal.js: "npm:^10.6.0"
|
||||||
html-encoding-sniffer: "npm:^4.0.0"
|
html-encoding-sniffer: "npm:^4.0.0"
|
||||||
@@ -8987,7 +8987,7 @@ __metadata:
|
|||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
canvas:
|
canvas:
|
||||||
optional: true
|
optional: true
|
||||||
checksum: 10c0/52d847e1aef099071d66d1d9aedcdd2f15e7ea781da9cfb41dc0d4caf741c5870c346396f8d1182d611427ae47a53f69a6f16410c698950e5809d3fed5a1672d
|
checksum: 10c0/b022ed8f6ce175afd97fbd42eb65b03b2be3b23df86cf87f018b6d2e757682fe8348e719a14780d6fa3fe8a65e531ba71b38db80f312818a32b77f01e31f267e
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -9394,10 +9394,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.2":
|
"lru-cache@npm:^11.0.0, lru-cache@npm:^11.2.2, lru-cache@npm:^11.2.4":
|
||||||
version: 11.2.2
|
version: 11.2.4
|
||||||
resolution: "lru-cache@npm:11.2.2"
|
resolution: "lru-cache@npm:11.2.4"
|
||||||
checksum: 10c0/72d7831bbebc85e2bdefe01047ee5584db69d641c48d7a509e86f66f6ee111b30af7ec3bd68a967d47b69a4b1fa8bbf3872630bd06a63b6735e6f0a5f1c8e83d
|
checksum: 10c0/4a24f9b17537619f9144d7b8e42cd5a225efdfd7076ebe7b5e7dc02b860a818455201e67fbf000765233fe7e339d3c8229fc815e9b58ee6ede511e07608c19b2
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -14077,8 +14077,8 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"vite@npm:^6.0.0 || ^7.0.0, vite@npm:^7.1.1":
|
"vite@npm:^6.0.0 || ^7.0.0, vite@npm:^7.1.1":
|
||||||
version: 7.2.6
|
version: 7.2.7
|
||||||
resolution: "vite@npm:7.2.6"
|
resolution: "vite@npm:7.2.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: "npm:^0.25.0"
|
esbuild: "npm:^0.25.0"
|
||||||
fdir: "npm:^6.5.0"
|
fdir: "npm:^6.5.0"
|
||||||
@@ -14127,7 +14127,7 @@ __metadata:
|
|||||||
optional: true
|
optional: true
|
||||||
bin:
|
bin:
|
||||||
vite: bin/vite.js
|
vite: bin/vite.js
|
||||||
checksum: 10c0/d444a159ab8f0f854d596d1938f201b449d59ed4d336e587be9dc89005467214d85848c212c2495f76a8421372ffe4d061d023d659600f1aaa3ba5ac13e804f7
|
checksum: 10c0/0c502d9eb898d9c05061dbd8fd199f280b524bbb4c12ab5f88c7b12779947386684a269e4dd0aa424aa35bcd857f1aa44aadb9ea764702a5043af433052455b5
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user