mirror of
https://github.com/glitch-soc/mastodon.git
synced 2026-03-29 03:00:33 +02:00
Compare commits
24 Commits
bf1e2abbf4
...
8f4a8a2af4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f4a8a2af4 | ||
|
|
88c0f52e99 | ||
|
|
a56b739c68 | ||
|
|
183a42a5ee | ||
|
|
303a5478af | ||
|
|
dfbf908870 | ||
|
|
aa067370d8 | ||
|
|
5e0db46b2a | ||
|
|
c06eb371e6 | ||
|
|
53617cef5a | ||
|
|
d730f6b0c5 | ||
|
|
addeb28292 | ||
|
|
5e3387539e | ||
|
|
4323963053 | ||
|
|
5651900b89 | ||
|
|
d1b996b7e3 | ||
|
|
fed26a41fa | ||
|
|
37d309bcaf | ||
|
|
d25f672c50 | ||
|
|
15c9088761 | ||
|
|
da1505a495 | ||
|
|
d1f690f50c | ||
|
|
da2b75bdcd | ||
|
|
adf8a3601d |
42
.github/workflows/build-releases.yml
vendored
42
.github/workflows/build-releases.yml
vendored
@@ -9,7 +9,44 @@ permissions:
|
||||
packages: write
|
||||
|
||||
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:
|
||||
needs: check-latest-stable
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: Dockerfile
|
||||
@@ -20,13 +57,14 @@ jobs:
|
||||
# Only tag with latest when ran against the latest stable branch
|
||||
# This needs to be updated after each minor version release
|
||||
flavor: |
|
||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.5.') }}
|
||||
latest=${{ needs.check-latest-stable.outputs.latest }}
|
||||
tags: |
|
||||
type=pep440,pattern={{raw}}
|
||||
type=pep440,pattern=v{{major}}.{{minor}}
|
||||
secrets: inherit
|
||||
|
||||
build-image-streaming:
|
||||
needs: check-latest-stable
|
||||
uses: ./.github/workflows/build-container-image.yml
|
||||
with:
|
||||
file_to_build: streaming/Dockerfile
|
||||
@@ -37,7 +75,7 @@ jobs:
|
||||
# Only tag with latest when ran against the latest stable branch
|
||||
# This needs to be updated after each minor version release
|
||||
flavor: |
|
||||
latest=${{ startsWith(github.ref, 'refs/tags/v4.5.') }}
|
||||
latest=${{ needs.check-latest-stable.outputs.latest }}
|
||||
tags: |
|
||||
type=pep440,pattern={{raw}}
|
||||
type=pep440,pattern=v{{major}}.{{minor}}
|
||||
|
||||
@@ -53,7 +53,7 @@ GEM
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
active_model_serializers (0.10.15)
|
||||
active_model_serializers (0.10.16)
|
||||
actionpack (>= 4.1)
|
||||
activemodel (>= 4.1)
|
||||
case_transform (>= 0.2)
|
||||
@@ -481,7 +481,7 @@ GEM
|
||||
addressable (~> 2.8)
|
||||
nokogiri (~> 1.12)
|
||||
omniauth (~> 2.1)
|
||||
omniauth-rails_csrf_protection (2.0.0)
|
||||
omniauth-rails_csrf_protection (2.0.1)
|
||||
actionpack (>= 4.2)
|
||||
omniauth (~> 2.0)
|
||||
omniauth-saml (2.2.4)
|
||||
@@ -839,7 +839,8 @@ GEM
|
||||
stackprof (0.2.27)
|
||||
starry (0.2.0)
|
||||
base64
|
||||
stoplight (5.6.0)
|
||||
stoplight (5.7.0)
|
||||
concurrent-ruby
|
||||
zeitwerk
|
||||
stringio (3.1.8)
|
||||
strong_migrations (2.5.1)
|
||||
|
||||
@@ -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-call */
|
||||
|
||||
import type { ComponentPropsWithoutRef } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { InterceptStatusClicks } from 'flavours/glitch/components/status/intercept_status_clicks';
|
||||
import { StatusQuoteManager } from 'flavours/glitch/components/status_quoted';
|
||||
import type { TopStatuses } from 'flavours/glitch/models/annual_report';
|
||||
import { makeGetStatus } from 'flavours/glitch/selectors';
|
||||
@@ -29,6 +33,24 @@ export const HighlightedPost: React.FC<{
|
||||
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) {
|
||||
return <div className={classNames(styles.box, styles.mostBoostedPost)} />;
|
||||
}
|
||||
@@ -72,7 +94,9 @@ export const HighlightedPost: React.FC<{
|
||||
{context === 'modal' && <p>{label}</p>}
|
||||
</div>
|
||||
|
||||
<StatusQuoteManager showActions={false} id={statusId} />
|
||||
<InterceptStatusClicks onPreventedClick={handleClick}>
|
||||
<StatusQuoteManager showActions={false} id={statusId} />
|
||||
</InterceptStatusClicks>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,18 +10,17 @@ $mobile-breakpoint: 540px;
|
||||
}
|
||||
|
||||
.modalWrapper {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 40px;
|
||||
overflow-y: auto;
|
||||
pointer-events: none;
|
||||
scrollbar-color: var(--color-text-secondary) var(--color-bg-secondary);
|
||||
|
||||
@media (width < $mobile-breakpoint) {
|
||||
padding-inline: 10px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.loading-indicator .circular-progress {
|
||||
@@ -50,37 +49,51 @@ $mobile-breakpoint: 540px;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
--gradient-strength: 0.4;
|
||||
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
max-width: 600px;
|
||||
padding: 24px;
|
||||
padding-top: 40px;
|
||||
contain: layout;
|
||||
flex: 0 0 auto;
|
||||
pointer-events: auto;
|
||||
pointer-events: all;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-bg-primary);
|
||||
background:
|
||||
radial-gradient(at 40% 87%, #240c9a99 0, transparent 50%),
|
||||
radial-gradient(at 19% 10%, #6b0c9a99 0, transparent 50%),
|
||||
radial-gradient(at 90% 27%, #9a0c8299 0, transparent 50%),
|
||||
radial-gradient(at 16% 95%, #1e948299 0, transparent 50%),
|
||||
radial-gradient(at 80% 91%, #16dae499 0, transparent 50%)
|
||||
radial-gradient(
|
||||
at 10% 27%,
|
||||
rgba(83, 12, 154, var(--gradient-strength)) 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);
|
||||
border-radius: 40px;
|
||||
|
||||
@media (width < $mobile-breakpoint) {
|
||||
padding-inline: 12px;
|
||||
padding-bottom: 12px;
|
||||
border-radius: 28px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
background: inherit;
|
||||
border-radius: inherit;
|
||||
filter: blur(20px);
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +105,7 @@ $mobile-breakpoint: 540px;
|
||||
font-family: silkscreen-wrapstodon, monospace;
|
||||
font-size: 28px;
|
||||
line-height: 1;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 4px;
|
||||
padding-inline: 40px; // Prevent overlap with close button
|
||||
|
||||
@media (width < $mobile-breakpoint) {
|
||||
@@ -116,7 +129,7 @@ $mobile-breakpoint: 540px;
|
||||
|
||||
.box {
|
||||
position: relative;
|
||||
padding: 16px;
|
||||
padding: 24px;
|
||||
border-radius: 16px;
|
||||
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%);
|
||||
@@ -150,7 +163,6 @@ $mobile-breakpoint: 540px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 16px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
text-wrap: balance;
|
||||
@@ -164,6 +176,10 @@ $mobile-breakpoint: 540px;
|
||||
text-transform: uppercase;
|
||||
color: #c2c8ff;
|
||||
font-weight: 500;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.statLarge {
|
||||
@@ -185,7 +201,7 @@ $mobile-breakpoint: 540px;
|
||||
|
||||
.mostBoostedPost {
|
||||
padding: 0;
|
||||
padding-top: 8px;
|
||||
padding-top: 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -260,7 +276,7 @@ $mobile-breakpoint: 540px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
gap: 16px;
|
||||
|
||||
p {
|
||||
max-width: 460px;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { defineMessage, useIntl } from 'react-intl';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import { useLocation } from 'react-router';
|
||||
|
||||
@@ -23,11 +23,6 @@ import { NewPosts } from './new_posts';
|
||||
|
||||
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' }> = ({
|
||||
context = 'standalone',
|
||||
}) => {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { closeModal } from '@/flavours/glitch/actions/modal';
|
||||
import { useAppDispatch } from '@/flavours/glitch/store';
|
||||
|
||||
import { AnnualReport } from '.';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
@@ -12,13 +15,30 @@ const AnnualReportModal: React.FC<{
|
||||
onChangeBackgroundColor('var(--color-bg-media-base)');
|
||||
}, [onChangeBackgroundColor]);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const handleCloseModal = useCallback<React.MouseEventHandler<HTMLDivElement>>(
|
||||
(e) => {
|
||||
if (e.target === e.currentTarget)
|
||||
dispatch(
|
||||
closeModal({ modalType: 'ANNUAL_REPORT', ignoreFocus: false }),
|
||||
);
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
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
|
||||
className={classNames(
|
||||
'modal-root__modal',
|
||||
styles.modalWrapper,
|
||||
'theme-dark',
|
||||
)}
|
||||
onClick={handleCloseModal}
|
||||
>
|
||||
<AnnualReport context='modal' />
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback } from 'react';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { useIntl } from 'react-intl';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { resetCompose, focusCompose } from '@/flavours/glitch/actions/compose';
|
||||
import { closeModal } from '@/flavours/glitch/actions/modal';
|
||||
@@ -9,9 +9,19 @@ import { Button } from '@/flavours/glitch/components/button';
|
||||
import type { AnnualReport as AnnualReportData } from '@/flavours/glitch/models/annual_report';
|
||||
import { useAppDispatch } from '@/flavours/glitch/store';
|
||||
|
||||
import { shareMessage } from '.';
|
||||
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 }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -21,7 +31,7 @@ export const ShareButton: FC<{ report: AnnualReportData }> = ({ report }) => {
|
||||
archetypeNames[report.data.archetype],
|
||||
);
|
||||
const shareLines = [
|
||||
intl.formatMessage(shareMessage, {
|
||||
intl.formatMessage(messages.share_message, {
|
||||
archetype: archetypeName,
|
||||
}),
|
||||
];
|
||||
@@ -37,5 +47,10 @@ export const ShareButton: FC<{ report: AnnualReportData }> = ({ report }) => {
|
||||
dispatch(closeModal({ modalType: 'ANNUAL_REPORT', ignoreFocus: false }));
|
||||
}, [report, intl, dispatch]);
|
||||
|
||||
return <Button text='Share here' onClick={handleShareClick} />;
|
||||
return (
|
||||
<Button
|
||||
text={intl.formatMessage(messages.share_on_mastodon)}
|
||||
onClick={handleShareClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
.wrapper {
|
||||
max-width: max-content;
|
||||
margin-inline: auto;
|
||||
padding: 40px 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 2rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
$mobile-breakpoint: 540px;
|
||||
|
||||
.wrapper {
|
||||
box-sizing: border-box;
|
||||
max-width: 600px;
|
||||
margin-inline: auto;
|
||||
padding: 40px 10px;
|
||||
|
||||
@media (width < $mobile-breakpoint) {
|
||||
padding-top: 0;
|
||||
padding-inline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-top: 2rem;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 2rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
|
||||
a:any-link {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.2em;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,10 @@ import type { FC } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { IconLogo } from '@/flavours/glitch/components/logo';
|
||||
import { me } from '@/flavours/glitch/initial_state';
|
||||
|
||||
import { AnnualReport } from './index';
|
||||
import classes from './shared_page.module.css';
|
||||
import classes from './shared_page.module.scss';
|
||||
|
||||
export const WrapstodonSharedPage: FC = () => {
|
||||
return (
|
||||
@@ -18,6 +19,28 @@ export const WrapstodonSharedPage: FC = () => {
|
||||
defaultMessage='Generated with {heart} by the Mastodon team'
|
||||
values={{ heart: '♥' }}
|
||||
/>
|
||||
<nav className={classes.nav}>
|
||||
<a href='/about'>
|
||||
<FormattedMessage
|
||||
id='footer.about_this_server'
|
||||
defaultMessage='About'
|
||||
/>
|
||||
</a>
|
||||
{!me && (
|
||||
<a href='https://joinmastodon.org/servers'>
|
||||
<FormattedMessage
|
||||
id='annual_report.shared_page.sign_up'
|
||||
defaultMessage='Sign up'
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
<a href='https://joinmastodon.org/sponsors'>
|
||||
<FormattedMessage
|
||||
id='annual_report.shared_page.donate'
|
||||
defaultMessage='Donate'
|
||||
/>
|
||||
</a>
|
||||
</nav>
|
||||
</footer>
|
||||
</main>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
{
|
||||
"about.fork_disclaimer": "Glitch-soc er fri programvare med åpen kildekode, forgrenet fra Mastodon.",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.html_meta": "Formater innleggene dine med HTML",
|
||||
"compose.content-type.markdown": "Markdown",
|
||||
"compose.content-type.markdown_meta": "Formater innleggene dine med Markdown",
|
||||
"compose.content-type.plain": "Ren tekst",
|
||||
"compose.disable_threaded_mode": "Deaktiver trådmodus",
|
||||
"compose.enable_threaded_mode": "Aktiver trådmodus",
|
||||
"confirmations.deprecated_settings.confirm": "Bruk Mastodon-innstillinger",
|
||||
"federation.federated.short": "Føderert",
|
||||
"federation.local_only.short": "Kun lokalt",
|
||||
"navigation_bar.app_settings": "App-innstillinger",
|
||||
"settings.always_show_spoilers_field": "Aktiver alltid feltet for innholdsvarsler",
|
||||
"settings.close": "Lukk",
|
||||
"settings.content_warnings": "Content warnings",
|
||||
"settings.preferences": "Preferences"
|
||||
"settings.content_warnings.regexp": "Regulært uttrykk",
|
||||
"settings.pop_in_left": "Venstre",
|
||||
"settings.pop_in_player": "Aktiver flytende avspiller",
|
||||
"settings.pop_in_right": "Høyre",
|
||||
"settings.preferences": "Preferences",
|
||||
"settings.side_arm.none": "Ingen"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,23 @@
|
||||
{
|
||||
"settings.content_warnings": "Content warnings",
|
||||
"settings.preferences": "Preferences"
|
||||
"about.fork_disclaimer": "Glitch-soc er fri programvare med åpen kildekode, forgrenet fra Mastodon.",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.html_meta": "Formater innleggene dine med HTML",
|
||||
"compose.content-type.markdown": "Markdown",
|
||||
"compose.content-type.markdown_meta": "Formater innleggene dine med Markdown",
|
||||
"compose.content-type.plain": "Ren tekst",
|
||||
"compose.disable_threaded_mode": "Deaktiver trådmodus",
|
||||
"compose.enable_threaded_mode": "Aktiver trådmodus",
|
||||
"confirmations.deprecated_settings.confirm": "Bruk Mastodon-innstillinger",
|
||||
"federation.federated.short": "Føderert",
|
||||
"federation.local_only.short": "Kun lokalt",
|
||||
"navigation_bar.app_settings": "App-innstillinger",
|
||||
"settings.always_show_spoilers_field": "Aktiver alltid feltet for innholdsvarsler",
|
||||
"settings.close": "Lukk",
|
||||
"settings.content_warnings": "Innholdsvarsler",
|
||||
"settings.content_warnings.regexp": "Regulært uttrykk",
|
||||
"settings.pop_in_left": "Venstre",
|
||||
"settings.pop_in_player": "Aktiver flytende avspiller",
|
||||
"settings.pop_in_right": "Høyre",
|
||||
"settings.preferences": "Brukerinnstillinger",
|
||||
"settings.side_arm.none": "Ingen"
|
||||
}
|
||||
|
||||
@@ -9,13 +9,25 @@
|
||||
"column.reblogged_by": "Inpulsionado por",
|
||||
"column_header.profile": "Perfil",
|
||||
"community.column_settings.allow_local_only": "Mostrar os toots apenas locais",
|
||||
"compose.attach.doodle": "Desenhe algo",
|
||||
"compose.change_federation": "Alterar configurações de federação",
|
||||
"compose.content-type.change": "Alterrar opções avançadas de formatação",
|
||||
"compose.content-type.html": "HTML",
|
||||
"compose.content-type.html_meta": "Formatar suas publicações usando HTML",
|
||||
"compose.content-type.markdown": "Markdown",
|
||||
"compose.content-type.markdown_meta": "Formatar suas publicações usando Markdown",
|
||||
"compose.content-type.plain": "Texto sem formatação",
|
||||
"compose.content-type.plain_meta": "Escrever sem formatação avançada",
|
||||
"confirmation_modal.do_not_ask_again": "Não pedir confirmação novamente",
|
||||
"confirmations.deprecated_settings.confirm": "Usar preferências do Mastodon",
|
||||
"confirmations.deprecated_settings.message": "Alguns dos {app_settings} específicos do dispositivo que você está usando foram substituídos por Mastodon {preferences} e serão substituídos:",
|
||||
"direct.group_by_conversations": "Agrupar por conversa",
|
||||
"favourite_modal.favourite": "Favoritar publicação?",
|
||||
"federation.federated.long": "Permitir que esta publicação alcance outros servidores",
|
||||
"federation.federated.short": "Federado",
|
||||
"federation.local_only.long": "Evitar que esta publicação alcance outros servidores",
|
||||
"federation.local_only.short": "Somente local",
|
||||
"firehose.column_settings.allow_local_only": "Exibir publicações somente locais em \"Todas\"",
|
||||
"home.column_settings.advanced": "Avançado",
|
||||
"home.column_settings.filter_regex": "Filtrar com uma expressão regular",
|
||||
"home.column_settings.show_direct": "Mostrar DMs",
|
||||
@@ -24,6 +36,7 @@
|
||||
"keyboard_shortcuts.secondary_toot": "para enviar toot usando a configuração de privacidade secundária",
|
||||
"moved_to_warning": "Esta conta foi como movida para {moved_to_link} e, portanto, pode não aceitar novos seguidores.",
|
||||
"navigation_bar.app_settings": "Configurações do aplicativo",
|
||||
"notifications.column_settings.filter_bar.show_bar": "Exibir barra de filtro",
|
||||
"settings.always_show_spoilers_field": "Sempre ativar o campo Aviso de Conteúdo",
|
||||
"settings.close": "Fechar",
|
||||
"settings.compose_box_opts": "Caixa de composição",
|
||||
@@ -37,6 +50,8 @@
|
||||
"settings.content_warnings_unfold_opts": "Opções de auto-revelar",
|
||||
"settings.deprecated_setting": "Essa configuração agora é controlada pelo {settings_page_link} do Mastodon",
|
||||
"settings.enable_content_warnings_auto_unfold": "Revelar automaticamente os avisos de conteúdo",
|
||||
"settings.fullwidth_view": "Estender colunas para preencher a largura (somente modo Desktop)",
|
||||
"settings.fullwidth_view_hint": "Estende as colunas para ocupar todo o espaço disponível.",
|
||||
"settings.general": "Geral",
|
||||
"settings.hicolor_privacy_icons": "Ícones de privacidade com cores de alto contraste",
|
||||
"settings.hicolor_privacy_icons.hint": "Exibir ícones de privacidade em cores brilhantes e facilmente distinguíveis",
|
||||
@@ -84,11 +99,14 @@
|
||||
"settings.tag_misleading_links.hint": "Acrescentar uma indicação visual com o link hospedeiro alvo a cada link que não o mencione explicitamente",
|
||||
"settings.wide_view": "Visualização ampla (apenas no Modo desktop)",
|
||||
"settings.wide_view_hint": "Estica as colunas para preencher melhor o espaço disponível.",
|
||||
"status.filtered": "Filtrado",
|
||||
"status.has_audio": "Possui um arquivo de áudio anexado",
|
||||
"status.has_pictures": "Possui uma imagem anexada",
|
||||
"status.has_preview_card": "Possui uma pré-visualização anexada",
|
||||
"status.has_video": "Possui um vídeo anexado",
|
||||
"status.hide": "Ocultar publicação",
|
||||
"status.in_reply_to": "Este toot é uma resposta",
|
||||
"status.is_poll": "Este toot é uma enquete",
|
||||
"status.local_only": "Visível apenas em sua instância"
|
||||
"status.local_only": "Visível apenas em sua instância",
|
||||
"status.show_filter_reason": "Mostrar mesmo assim"
|
||||
}
|
||||
|
||||
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-call */
|
||||
|
||||
import type { ComponentPropsWithoutRef } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { InterceptStatusClicks } from 'mastodon/components/status/intercept_status_clicks';
|
||||
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
|
||||
import type { TopStatuses } from 'mastodon/models/annual_report';
|
||||
import { makeGetStatus } from 'mastodon/selectors';
|
||||
@@ -29,6 +33,24 @@ export const HighlightedPost: React.FC<{
|
||||
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) {
|
||||
return <div className={classNames(styles.box, styles.mostBoostedPost)} />;
|
||||
}
|
||||
@@ -72,7 +94,9 @@ export const HighlightedPost: React.FC<{
|
||||
{context === 'modal' && <p>{label}</p>}
|
||||
</div>
|
||||
|
||||
<StatusQuoteManager showActions={false} id={statusId} />
|
||||
<InterceptStatusClicks onPreventedClick={handleClick}>
|
||||
<StatusQuoteManager showActions={false} id={statusId} />
|
||||
</InterceptStatusClicks>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -10,18 +10,17 @@ $mobile-breakpoint: 540px;
|
||||
}
|
||||
|
||||
.modalWrapper {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 40px;
|
||||
overflow-y: auto;
|
||||
pointer-events: none;
|
||||
scrollbar-color: var(--color-text-secondary) var(--color-bg-secondary);
|
||||
|
||||
@media (width < $mobile-breakpoint) {
|
||||
padding-inline: 10px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.loading-indicator .circular-progress {
|
||||
@@ -50,37 +49,51 @@ $mobile-breakpoint: 540px;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
--gradient-strength: 0.4;
|
||||
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
max-width: 600px;
|
||||
padding: 24px;
|
||||
padding-top: 40px;
|
||||
contain: layout;
|
||||
flex: 0 0 auto;
|
||||
pointer-events: auto;
|
||||
pointer-events: all;
|
||||
color: var(--color-text-primary);
|
||||
background: var(--color-bg-primary);
|
||||
background:
|
||||
radial-gradient(at 40% 87%, #240c9a99 0, transparent 50%),
|
||||
radial-gradient(at 19% 10%, #6b0c9a99 0, transparent 50%),
|
||||
radial-gradient(at 90% 27%, #9a0c8299 0, transparent 50%),
|
||||
radial-gradient(at 16% 95%, #1e948299 0, transparent 50%),
|
||||
radial-gradient(at 80% 91%, #16dae499 0, transparent 50%)
|
||||
radial-gradient(
|
||||
at 10% 27%,
|
||||
rgba(83, 12, 154, var(--gradient-strength)) 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);
|
||||
border-radius: 40px;
|
||||
|
||||
@media (width < $mobile-breakpoint) {
|
||||
padding-inline: 12px;
|
||||
padding-bottom: 12px;
|
||||
border-radius: 28px;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
background: inherit;
|
||||
border-radius: inherit;
|
||||
filter: blur(20px);
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +105,7 @@ $mobile-breakpoint: 540px;
|
||||
font-family: silkscreen-wrapstodon, monospace;
|
||||
font-size: 28px;
|
||||
line-height: 1;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 4px;
|
||||
padding-inline: 40px; // Prevent overlap with close button
|
||||
|
||||
@media (width < $mobile-breakpoint) {
|
||||
@@ -116,7 +129,7 @@ $mobile-breakpoint: 540px;
|
||||
|
||||
.box {
|
||||
position: relative;
|
||||
padding: 16px;
|
||||
padding: 24px;
|
||||
border-radius: 16px;
|
||||
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%);
|
||||
@@ -150,7 +163,6 @@ $mobile-breakpoint: 540px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 16px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
text-wrap: balance;
|
||||
@@ -164,6 +176,10 @@ $mobile-breakpoint: 540px;
|
||||
text-transform: uppercase;
|
||||
color: #c2c8ff;
|
||||
font-weight: 500;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.statLarge {
|
||||
@@ -185,7 +201,7 @@ $mobile-breakpoint: 540px;
|
||||
|
||||
.mostBoostedPost {
|
||||
padding: 0;
|
||||
padding-top: 8px;
|
||||
padding-top: 24px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -260,7 +276,7 @@ $mobile-breakpoint: 540px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
gap: 16px;
|
||||
|
||||
p {
|
||||
max-width: 460px;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { defineMessage, useIntl } from 'react-intl';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import { useLocation } from 'react-router';
|
||||
|
||||
@@ -23,11 +23,6 @@ import { NewPosts } from './new_posts';
|
||||
|
||||
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' }> = ({
|
||||
context = 'standalone',
|
||||
}) => {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { closeModal } from '@/mastodon/actions/modal';
|
||||
import { useAppDispatch } from '@/mastodon/store';
|
||||
|
||||
import { AnnualReport } from '.';
|
||||
import styles from './index.module.scss';
|
||||
|
||||
@@ -12,13 +15,30 @@ const AnnualReportModal: React.FC<{
|
||||
onChangeBackgroundColor('var(--color-bg-media-base)');
|
||||
}, [onChangeBackgroundColor]);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const handleCloseModal = useCallback<React.MouseEventHandler<HTMLDivElement>>(
|
||||
(e) => {
|
||||
if (e.target === e.currentTarget)
|
||||
dispatch(
|
||||
closeModal({ modalType: 'ANNUAL_REPORT', ignoreFocus: false }),
|
||||
);
|
||||
},
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
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
|
||||
className={classNames(
|
||||
'modal-root__modal',
|
||||
styles.modalWrapper,
|
||||
'theme-dark',
|
||||
)}
|
||||
onClick={handleCloseModal}
|
||||
>
|
||||
<AnnualReport context='modal' />
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback } 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 { 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 { useAppDispatch } from '@/mastodon/store';
|
||||
|
||||
import { shareMessage } from '.';
|
||||
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 }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -21,7 +31,7 @@ export const ShareButton: FC<{ report: AnnualReportData }> = ({ report }) => {
|
||||
archetypeNames[report.data.archetype],
|
||||
);
|
||||
const shareLines = [
|
||||
intl.formatMessage(shareMessage, {
|
||||
intl.formatMessage(messages.share_message, {
|
||||
archetype: archetypeName,
|
||||
}),
|
||||
];
|
||||
@@ -37,5 +47,10 @@ export const ShareButton: FC<{ report: AnnualReportData }> = ({ report }) => {
|
||||
dispatch(closeModal({ modalType: 'ANNUAL_REPORT', ignoreFocus: false }));
|
||||
}, [report, intl, dispatch]);
|
||||
|
||||
return <Button text='Share here' onClick={handleShareClick} />;
|
||||
return (
|
||||
<Button
|
||||
text={intl.formatMessage(messages.share_on_mastodon)}
|
||||
onClick={handleShareClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
.wrapper {
|
||||
max-width: max-content;
|
||||
margin-inline: auto;
|
||||
padding: 40px 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
align-items: center;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 2rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
$mobile-breakpoint: 540px;
|
||||
|
||||
.wrapper {
|
||||
box-sizing: border-box;
|
||||
max-width: 600px;
|
||||
margin-inline: auto;
|
||||
padding: 40px 10px;
|
||||
|
||||
@media (width < $mobile-breakpoint) {
|
||||
padding-top: 0;
|
||||
padding-inline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-top: 2rem;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 2rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
|
||||
a:any-link {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 0.2em;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,10 @@ import type { FC } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { IconLogo } from '@/mastodon/components/logo';
|
||||
import { me } from '@/mastodon/initial_state';
|
||||
|
||||
import { AnnualReport } from './index';
|
||||
import classes from './shared_page.module.css';
|
||||
import classes from './shared_page.module.scss';
|
||||
|
||||
export const WrapstodonSharedPage: FC = () => {
|
||||
return (
|
||||
@@ -18,6 +19,28 @@ export const WrapstodonSharedPage: FC = () => {
|
||||
defaultMessage='Generated with {heart} by the Mastodon team'
|
||||
values={{ heart: '♥' }}
|
||||
/>
|
||||
<nav className={classes.nav}>
|
||||
<a href='/about'>
|
||||
<FormattedMessage
|
||||
id='footer.about_this_server'
|
||||
defaultMessage='About'
|
||||
/>
|
||||
</a>
|
||||
{!me && (
|
||||
<a href='https://joinmastodon.org/servers'>
|
||||
<FormattedMessage
|
||||
id='annual_report.shared_page.sign_up'
|
||||
defaultMessage='Sign up'
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
<a href='https://joinmastodon.org/sponsors'>
|
||||
<FormattedMessage
|
||||
id='annual_report.shared_page.donate'
|
||||
defaultMessage='Donate'
|
||||
/>
|
||||
</a>
|
||||
</nav>
|
||||
</footer>
|
||||
</main>
|
||||
);
|
||||
|
||||
@@ -117,7 +117,9 @@
|
||||
"annual_report.announcement.action_view": "View my Wrapstodon",
|
||||
"annual_report.announcement.description": "Discover more about your engagement on Mastodon over the past year.",
|
||||
"annual_report.announcement.title": "Wrapstodon {year} has arrived",
|
||||
"annual_report.shared_page.donate": "Donate",
|
||||
"annual_report.shared_page.footer": "Generated with {heart} by the Mastodon team",
|
||||
"annual_report.shared_page.sign_up": "Sign up",
|
||||
"annual_report.summary.archetype.booster.desc_public": "{name} stayed on the hunt for posts to boost, amplifying other creators with perfect aim.",
|
||||
"annual_report.summary.archetype.booster.desc_self": "You stayed on the hunt for posts to boost, amplifying other creators with perfect aim.",
|
||||
"annual_report.summary.archetype.booster.name": "The Archer",
|
||||
@@ -152,6 +154,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.we_wont_tell_bernie": "We won't tell Bernie.",
|
||||
"annual_report.summary.share_message": "I got the {archetype} archetype!",
|
||||
"annual_report.summary.share_on_mastodon": "Share on Mastodon",
|
||||
"attachments_list.unprocessed": "(unprocessed)",
|
||||
"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.",
|
||||
|
||||
@@ -5,14 +5,14 @@ class AnnualReport::TopStatuses < AnnualReport::Source
|
||||
{
|
||||
top_statuses: {
|
||||
by_reblogs: status_identifier(most_reblogged_status),
|
||||
by_favourites: status_identifier(most_favourited_status),
|
||||
by_replies: status_identifier(most_replied_status),
|
||||
by_favourites: nil,
|
||||
by_replies: nil,
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
def eligible?
|
||||
report_statuses.public_visibility.exists?
|
||||
report_statuses.distributable_visibility.exists?
|
||||
end
|
||||
|
||||
private
|
||||
@@ -43,7 +43,7 @@ class AnnualReport::TopStatuses < AnnualReport::Source
|
||||
|
||||
def base_scope
|
||||
report_statuses
|
||||
.public_visibility
|
||||
.distributable_visibility
|
||||
.joins(:status_stat)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -451,6 +451,10 @@ class Account < ApplicationRecord
|
||||
save!
|
||||
end
|
||||
|
||||
def featureable?
|
||||
local? && discoverable?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def prepare_contents
|
||||
|
||||
@@ -32,6 +32,8 @@ class CollectionItem < ApplicationRecord
|
||||
validates :account, presence: true, if: :accepted?
|
||||
validates :object_uri, presence: true, if: -> { account.nil? }
|
||||
|
||||
before_validation :set_position, on: :create
|
||||
|
||||
scope :ordered, -> { order(position: :asc) }
|
||||
scope :with_accounts, -> { includes(account: [:account_stat, :user]) }
|
||||
scope :not_blocked_by, ->(account) { where.not(accounts: { id: account.blocking }) }
|
||||
@@ -39,4 +41,12 @@ class CollectionItem < ApplicationRecord
|
||||
def local_item_with_remote_account?
|
||||
local? && account&.remote?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_position
|
||||
return if position_changed?
|
||||
|
||||
self.position = self.class.where(collection_id:).maximum(:position).to_i + 1
|
||||
end
|
||||
end
|
||||
|
||||
@@ -64,4 +64,8 @@ class AccountPolicy < ApplicationPolicy
|
||||
def review?
|
||||
role.can?(:manage_taxonomies)
|
||||
end
|
||||
|
||||
def feature?
|
||||
record.featureable? && !current_account.blocking?(record) && !record.blocking?(current_account)
|
||||
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,7 +9,9 @@
|
||||
= opengraph 'profile:username', acct(@account)[1..]
|
||||
|
||||
= render 'og_description', account: @account
|
||||
= render 'og_image', report: @generated_annual_report
|
||||
|
||||
= render_initial_state
|
||||
= flavoured_vite_typescript_tag 'wrapstodon.tsx', crossorigin: 'anonymous'
|
||||
|
||||
- content_for :html_classes, 'theme-dark'
|
||||
|
||||
@@ -31,7 +31,7 @@ el:
|
||||
glitch_guide_link_text: Και ομοίως για το glitch-soc!
|
||||
auth:
|
||||
captcha_confirmation:
|
||||
hint_html: Απλώς ένα βήμα ακόμη! Για να επιβεβαιώσεις τον λογαριασμό σου, αυτός ο διακομιστής απαιτεί να λύσεις ένα CAPTCHA. Μπορείς να <a href="/about/more">επικοινωνήσεις με τον διαχειριστή του διακομιστή</a> αν έχεις ερωτήσεις ή χρειάζεσαι βοήθεια με την επιβεβαίωση του λογαριασμού σου.
|
||||
hint_html: Απλώς ένα βήμα ακόμα! Για να επιβεβαιώσεις τον λογαριασμό σου, αυτός ο διακομιστής απαιτεί να λύσεις ένα CAPTCHA. Μπορείς να <a href="/about/more">επικοινωνήσεις με τον διαχειριστή του διακομιστή</a> αν έχεις ερωτήσεις ή χρειάζεσαι βοήθεια με την επιβεβαίωση του λογαριασμού σου.
|
||||
title: Επαλήθευση χρήστη
|
||||
generic:
|
||||
use_this: Χρησιμοποιήστε αυτό
|
||||
|
||||
@@ -1 +1,32 @@
|
||||
---
|
||||
nn:
|
||||
admin:
|
||||
custom_emojis:
|
||||
batch_copy_error: 'En feil oppsto ved kopiering av noen av de valgte emojiene: %{message}'
|
||||
batch_error: 'En feil oppsto: %{message}'
|
||||
settings:
|
||||
flavour_and_skin:
|
||||
title: Variant og tema
|
||||
hide_followers_count:
|
||||
desc_html: Ikke vis følgerantallet på brukerprofiler
|
||||
title: Skjul følgerantall
|
||||
other:
|
||||
preamble: Diverse innstillinger for glitch-soc som ikke passer i andre kategorier.
|
||||
title: Andre
|
||||
outgoing_spoilers:
|
||||
title: Innholdsvarsel for utgående innlegg
|
||||
show_reblogs_in_public_timelines:
|
||||
desc_html: Vis offentlige fremhevinger av offentlige innlegg i lokale og offentlige tidslinjer.
|
||||
title: Vis fremhevinger i offentlige tidslinjer
|
||||
show_replies_in_public_timelines:
|
||||
title: Vis svar i offentlige tidslinjer
|
||||
trending_status_cw:
|
||||
title: Tillat innlegg med innholdsvarsler å trende
|
||||
appearance:
|
||||
localization:
|
||||
glitch_guide_link: https://crowdin.com/project/glitch-soc
|
||||
glitch_guide_link_text: Det gjelder også glitch-soc!
|
||||
generic:
|
||||
use_this: Bruk dette
|
||||
settings:
|
||||
flavours: Varianter
|
||||
|
||||
@@ -1 +1,32 @@
|
||||
---
|
||||
'no':
|
||||
admin:
|
||||
custom_emojis:
|
||||
batch_copy_error: 'En feil oppsto ved kopiering av noen av de valgte emojiene: %{message}'
|
||||
batch_error: 'En feil oppsto: %{message}'
|
||||
settings:
|
||||
flavour_and_skin:
|
||||
title: Variant og tema
|
||||
hide_followers_count:
|
||||
desc_html: Ikke vis følgerantallet på brukerprofiler
|
||||
title: Skjul følgerantall
|
||||
other:
|
||||
preamble: Diverse innstillinger for glitch-soc som ikke passer i andre kategorier.
|
||||
title: Andre
|
||||
outgoing_spoilers:
|
||||
title: Innholdsvarsel for utgående innlegg
|
||||
show_reblogs_in_public_timelines:
|
||||
desc_html: Vis offentlige fremhevinger av offentlige innlegg i lokale og offentlige tidslinjer.
|
||||
title: Vis fremhevinger i offentlige tidslinjer
|
||||
show_replies_in_public_timelines:
|
||||
title: Vis svar i offentlige tidslinjer
|
||||
trending_status_cw:
|
||||
title: Tillat innlegg med innholdsvarsler å trende
|
||||
appearance:
|
||||
localization:
|
||||
glitch_guide_link: https://crowdin.com/project/glitch-soc
|
||||
glitch_guide_link_text: Det gjelder også glitch-soc!
|
||||
generic:
|
||||
use_this: Bruk dette
|
||||
settings:
|
||||
flavours: Varianter
|
||||
|
||||
@@ -8,7 +8,7 @@ el:
|
||||
setting_default_content_type_markdown: Κατά τη γραφή των τουτς, υποθέτει ότι χρησιμοποιείται το Markdown για μορφοποίηση πλούσιου κειμένου, εκτός αν ορίζεται διαφορετικά
|
||||
setting_default_content_type_plain: Κατά τη γραφή των τουτς, υποθέτει ότι είναι απλό κείμενο χωρίς ειδική μορφοποίηση, εκτός αν ορίζεται διαφορετικά (προεπιλεγμένη συμπεριφορά Mastodon)
|
||||
setting_default_language: Η γλώσσα των τουτ σας μπορεί να εντοπιστεί αυτόματα, αλλά δεν είναι πάντα ακριβής
|
||||
setting_show_followers_count: Εμφάνιση του αριθμού ακολούθων σας στο προφίλ σας. Αν αποκρύψετε τον αριθμό των ακολούθων σας, θα είναι κρυμμένος ακόμη και από εσάς, και μερικές εφαρμογές μπορεί να εμφανίσουν έναν αρνητικό αριθμό ακολούθων.
|
||||
setting_show_followers_count: Εμφάνιση του αριθμού ακολούθων σας στο προφίλ σας. Αν αποκρύψετε τον αριθμό των ακολούθων σας, θα είναι κρυμμένος ακόμα και από εσάς, και μερικές εφαρμογές μπορεί να εμφανίσουν έναν αρνητικό αριθμό ακολούθων.
|
||||
labels:
|
||||
defaults:
|
||||
setting_default_content_type: Προεπιλεγμένη μορφή για τουτς
|
||||
|
||||
@@ -8,7 +8,7 @@ ko:
|
||||
setting_default_content_type_markdown: 게시물을 작성할 때, 형식을 지정하지 않았다면, 마크다운이라고 가정합니다
|
||||
setting_default_content_type_plain: 게시물을 작성할 때, 형식을 지정하지 않았다면, 일반적인 텍스트라고 가정합니다. (마스토돈의 기본 동작)
|
||||
setting_default_language: 작성하는 게시물의 언어는 자동으로 설정될 수 있습니다, 하지만 언제나 정확하지는 않습니다
|
||||
setting_show_followers_count: 팔로워 카운트를 프로필에서 숨깁니다. 팔로워 수를 숨기면 나에게도 보이지 않으며 몇몇 앱에서는 팔로워 수가 음수로 표시될 수 있습니다.
|
||||
setting_show_followers_count: 팔로워 카운트를 프로필에 표시합니다. 팔로워 수를 숨기면 나에게도 보이지 않으며 몇몇 앱에서는 팔로워 수가 음수로 표시될 수 있습니다.
|
||||
setting_skin: 선택한 마스토돈 풍미의 스킨을 바꿉니다
|
||||
labels:
|
||||
defaults:
|
||||
|
||||
@@ -1 +1,15 @@
|
||||
---
|
||||
nn:
|
||||
simple_form:
|
||||
glitch_only: glitch-soc
|
||||
hints:
|
||||
defaults:
|
||||
setting_default_language: Språket i innleggene deres kan oppdages automatisk, men det er ikke alltid nøyaktig
|
||||
labels:
|
||||
defaults:
|
||||
setting_default_content_type: Standardformat for innlegg
|
||||
setting_default_content_type_html: HTML
|
||||
setting_default_content_type_markdown: Markdown
|
||||
setting_default_content_type_plain: Ren tekst
|
||||
setting_show_followers_count: Vis følgerantallet deres
|
||||
setting_skin: Tema
|
||||
|
||||
@@ -1 +1,15 @@
|
||||
---
|
||||
'no':
|
||||
simple_form:
|
||||
glitch_only: glitch-soc
|
||||
hints:
|
||||
defaults:
|
||||
setting_default_language: Språket i innleggene deres kan oppdages automatisk, men det er ikke alltid nøyaktig
|
||||
labels:
|
||||
defaults:
|
||||
setting_default_content_type: Standardformat for innlegg
|
||||
setting_default_content_type_html: HTML
|
||||
setting_default_content_type_markdown: Markdown
|
||||
setting_default_content_type_plain: Ren tekst
|
||||
setting_show_followers_count: Vis følgerantallet deres
|
||||
setting_skin: Tema
|
||||
|
||||
@@ -7,6 +7,8 @@ en:
|
||||
hosted_on: Mastodon hosted on %{domain}
|
||||
title: About
|
||||
accounts:
|
||||
errors:
|
||||
cannot_be_added_to_collections: This account cannot be added to collections.
|
||||
followers:
|
||||
one: Follower
|
||||
other: Followers
|
||||
|
||||
@@ -40,8 +40,8 @@ RSpec.describe AnnualReport::TopStatuses do
|
||||
.to include(
|
||||
top_statuses: include(
|
||||
by_reblogs: reblogged_status.id.to_s,
|
||||
by_favourites: favourited_status.id.to_s,
|
||||
by_replies: replied_status.id.to_s
|
||||
by_favourites: nil,
|
||||
by_replies: nil
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
@@ -781,4 +781,37 @@ RSpec.describe Account do
|
||||
expect(subject.reload.followers_count).to eq 15
|
||||
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
|
||||
|
||||
@@ -38,4 +38,23 @@ RSpec.describe CollectionItem do
|
||||
it { is_expected.to validate_presence_of(:object_uri) }
|
||||
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
|
||||
|
||||
@@ -156,4 +156,36 @@ RSpec.describe AccountPolicy do
|
||||
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
|
||||
|
||||
@@ -75,6 +75,33 @@ RSpec.describe 'Credentials' do
|
||||
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
|
||||
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,
|
||||
outDir,
|
||||
assetsDir: 'assets',
|
||||
assetsInlineLimit: (filePath, _) =>
|
||||
/\.woff2?$/.exec(filePath) ? false : undefined,
|
||||
rollupOptions: {
|
||||
input: await findEntrypoints(),
|
||||
output: {
|
||||
|
||||
88
yarn.lock
88
yarn.lock
@@ -12,10 +12,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@acemir/cssom@npm:^0.9.23":
|
||||
version: 0.9.24
|
||||
resolution: "@acemir/cssom@npm:0.9.24"
|
||||
checksum: 10c0/1c7bf8a61a74d9ecbc3b12fba697384461b3234441ed5a10f5c34aef91fdf4f1e3322fcd6659a8eaddd591eddc2259efd278212236100d90a6e16f77794d98bd
|
||||
"@acemir/cssom@npm:^0.9.28":
|
||||
version: 0.9.28
|
||||
resolution: "@acemir/cssom@npm:0.9.28"
|
||||
checksum: 10c0/1e192d216c4236171d9930b42b9a965052d4578b23c6ddaa17c7c3d0820ffb872258544a83af163ae2d41b3bdccd6b6c4c14b2d32eb9f8b8b63972d74f46bd83
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -46,29 +46,29 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@asamuzakjp/css-color@npm:^4.0.3":
|
||||
version: 4.0.4
|
||||
resolution: "@asamuzakjp/css-color@npm:4.0.4"
|
||||
"@asamuzakjp/css-color@npm:^4.1.0":
|
||||
version: 4.1.0
|
||||
resolution: "@asamuzakjp/css-color@npm:4.1.0"
|
||||
dependencies:
|
||||
"@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-tokenizer": "npm:^3.0.4"
|
||||
lru-cache: "npm:^11.1.0"
|
||||
checksum: 10c0/5a4eb3c8594f58f3df06c867a6cda4a33f702f5cd682d6afa5074813f16fd05e732653ac79bd6fc66390554e158ac478103ad5e885fd9cf154b69bb67639e82f
|
||||
lru-cache: "npm:^11.2.2"
|
||||
checksum: 10c0/097b9270a5befb765885dda43d6914ccbaa575565525d307e8ba3ba07f98e466062f4a77b9657e65160db9110c41c59cf5a6937479647f73637aeddf5c421579
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@asamuzakjp/dom-selector@npm:^6.7.4":
|
||||
version: 6.7.5
|
||||
resolution: "@asamuzakjp/dom-selector@npm:6.7.5"
|
||||
"@asamuzakjp/dom-selector@npm:^6.7.6":
|
||||
version: 6.7.6
|
||||
resolution: "@asamuzakjp/dom-selector@npm:6.7.6"
|
||||
dependencies:
|
||||
"@asamuzakjp/nwsapi": "npm:^2.3.9"
|
||||
bidi-js: "npm:^1.0.3"
|
||||
css-tree: "npm:^3.1.0"
|
||||
is-potential-custom-element-name: "npm:^1.0.1"
|
||||
lru-cache: "npm:^11.2.2"
|
||||
checksum: 10c0/72ac4dc45aac9165222345aacc1db51a84094f159e9e2fa71bc89befd2d78fd00a76c7ff9a8a1ceb60e7ce198a4ec0275a4d878bea67b756cadbf3d9680162c4
|
||||
lru-cache: "npm:^11.2.4"
|
||||
checksum: 10c0/1715faae0787f0c8430b3a0ff3db8576a5b9a4f964408d0808fc2060ab01e0c2f5d8e26409de54b8641433c891dab8b561b196e58798811146084c561a4954ce
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1275,7 +1275,7 @@ __metadata:
|
||||
languageName: node
|
||||
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
|
||||
resolution: "@csstools/css-color-parser@npm:3.1.0"
|
||||
dependencies:
|
||||
@@ -1297,7 +1297,7 @@ __metadata:
|
||||
languageName: node
|
||||
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
|
||||
resolution: "@csstools/css-syntax-patches-for-csstree@npm:1.0.14"
|
||||
peerDependencies:
|
||||
@@ -3341,10 +3341,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rolldown/pluginutils@npm:1.0.0-beta.47":
|
||||
version: 1.0.0-beta.47
|
||||
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.47"
|
||||
checksum: 10c0/eb0cfa7334d66f090c47eaac612174936b05f26e789352428cb6e03575b590f355de30d26b42576ea4e613d8887b587119d19b2e4b3a8909ceb232ca1cf746c8
|
||||
"@rolldown/pluginutils@npm:1.0.0-beta.53":
|
||||
version: 1.0.0-beta.53
|
||||
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.53"
|
||||
checksum: 10c0/e8b0a7eb76be22f6f103171f28072de821525a4e400454850516da91a7381957932ff0ce495f227bcb168e86815788b0c1d249ca9e34dca366a82c8825b714ce
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4830,18 +4830,18 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@vitejs/plugin-react@npm:^5.0.0":
|
||||
version: 5.1.1
|
||||
resolution: "@vitejs/plugin-react@npm:5.1.1"
|
||||
version: 5.1.2
|
||||
resolution: "@vitejs/plugin-react@npm:5.1.2"
|
||||
dependencies:
|
||||
"@babel/core": "npm:^7.28.5"
|
||||
"@babel/plugin-transform-react-jsx-self": "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"
|
||||
react-refresh: "npm:^0.18.0"
|
||||
peerDependencies:
|
||||
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
|
||||
checksum: 10c0/e590efaea1eabfbb1beb6e8c9fac0742fd299808e3368e63b2825ce24740adb8a28fcb2668b14b7ca1bdb42890cfefe94d02dd358dcbbf8a27ddf377b9a82abf
|
||||
checksum: 10c0/d788f269cdf7474425071ba7c4ea7013f174ddaef12b758defe809a551a03ac62a4a80cd858872deb618e7936ccc7cffe178bc12b62e9c836a467e13f15b9390
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6253,14 +6253,14 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cssstyle@npm:^5.3.3":
|
||||
version: 5.3.3
|
||||
resolution: "cssstyle@npm:5.3.3"
|
||||
"cssstyle@npm:^5.3.4":
|
||||
version: 5.3.4
|
||||
resolution: "cssstyle@npm:5.3.4"
|
||||
dependencies:
|
||||
"@asamuzakjp/css-color": "npm:^4.0.3"
|
||||
"@csstools/css-syntax-patches-for-csstree": "npm:^1.0.14"
|
||||
"@asamuzakjp/css-color": "npm:^4.1.0"
|
||||
"@csstools/css-syntax-patches-for-csstree": "npm:1.0.14"
|
||||
css-tree: "npm:^3.1.0"
|
||||
checksum: 10c0/0e082992851a1ded3662bda420f86dc1c90510a21cf237ddf573a1e121a722a3f78bb8f6eb46b33f267da25162e8e1fe968f7002114c9ab1d0d4e11dad9c5ee8
|
||||
checksum: 10c0/7499ea8cbc2f759ded275428e0811d147baa6a964a44577711cee5edabee2230cf76b6bd20a556603f99ebc6fff80afdcba6c00bcbb1d41ae50cd09cd9fe9a2d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -8959,12 +8959,12 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"jsdom@npm:^27.0.0":
|
||||
version: 27.2.0
|
||||
resolution: "jsdom@npm:27.2.0"
|
||||
version: 27.3.0
|
||||
resolution: "jsdom@npm:27.3.0"
|
||||
dependencies:
|
||||
"@acemir/cssom": "npm:^0.9.23"
|
||||
"@asamuzakjp/dom-selector": "npm:^6.7.4"
|
||||
cssstyle: "npm:^5.3.3"
|
||||
"@acemir/cssom": "npm:^0.9.28"
|
||||
"@asamuzakjp/dom-selector": "npm:^6.7.6"
|
||||
cssstyle: "npm:^5.3.4"
|
||||
data-urls: "npm:^6.0.0"
|
||||
decimal.js: "npm:^10.6.0"
|
||||
html-encoding-sniffer: "npm:^4.0.0"
|
||||
@@ -8987,7 +8987,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
canvas:
|
||||
optional: true
|
||||
checksum: 10c0/52d847e1aef099071d66d1d9aedcdd2f15e7ea781da9cfb41dc0d4caf741c5870c346396f8d1182d611427ae47a53f69a6f16410c698950e5809d3fed5a1672d
|
||||
checksum: 10c0/b022ed8f6ce175afd97fbd42eb65b03b2be3b23df86cf87f018b6d2e757682fe8348e719a14780d6fa3fe8a65e531ba71b38db80f312818a32b77f01e31f267e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -9394,10 +9394,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.2":
|
||||
version: 11.2.2
|
||||
resolution: "lru-cache@npm:11.2.2"
|
||||
checksum: 10c0/72d7831bbebc85e2bdefe01047ee5584db69d641c48d7a509e86f66f6ee111b30af7ec3bd68a967d47b69a4b1fa8bbf3872630bd06a63b6735e6f0a5f1c8e83d
|
||||
"lru-cache@npm:^11.0.0, lru-cache@npm:^11.2.2, lru-cache@npm:^11.2.4":
|
||||
version: 11.2.4
|
||||
resolution: "lru-cache@npm:11.2.4"
|
||||
checksum: 10c0/4a24f9b17537619f9144d7b8e42cd5a225efdfd7076ebe7b5e7dc02b860a818455201e67fbf000765233fe7e339d3c8229fc815e9b58ee6ede511e07608c19b2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -14077,8 +14077,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"vite@npm:^6.0.0 || ^7.0.0, vite@npm:^7.1.1":
|
||||
version: 7.2.6
|
||||
resolution: "vite@npm:7.2.6"
|
||||
version: 7.2.7
|
||||
resolution: "vite@npm:7.2.7"
|
||||
dependencies:
|
||||
esbuild: "npm:^0.25.0"
|
||||
fdir: "npm:^6.5.0"
|
||||
@@ -14127,7 +14127,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
vite: bin/vite.js
|
||||
checksum: 10c0/d444a159ab8f0f854d596d1938f201b449d59ed4d336e587be9dc89005467214d85848c212c2495f76a8421372ffe4d061d023d659600f1aaa3ba5ac13e804f7
|
||||
checksum: 10c0/0c502d9eb898d9c05061dbd8fd199f280b524bbb4c12ab5f88c7b12779947386684a269e4dd0aa424aa35bcd857f1aa44aadb9ea764702a5043af433052455b5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user