Merge remote-tracking branch 'origin/develop' into group-gallery

This commit is contained in:
Alex Gleason 2023-04-11 11:01:37 -05:00
commit 7720df2ebe
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
31 changed files with 1489 additions and 1007 deletions

View File

@ -139,6 +139,7 @@ const StatusList: React.FC<IStatusList> = ({
onMoveDown={handleMoveDown}
contextType={timelineId}
showGroup={showGroup}
variant={divideType === 'border' ? 'slim' : 'rounded'}
/>
);
};
@ -172,6 +173,7 @@ const StatusList: React.FC<IStatusList> = ({
onMoveDown={handleMoveDown}
contextType={timelineId}
showGroup={showGroup}
variant={divideType === 'border' ? 'slim' : 'default'}
/>
));
};
@ -245,7 +247,7 @@ const StatusList: React.FC<IStatusList> = ({
isLoading={isLoading}
showLoading={isLoading && statusIds.size === 0}
onLoadMore={handleLoadOlder}
placeholderComponent={PlaceholderStatus}
placeholderComponent={() => <PlaceholderStatus variant={divideType === 'border' ? 'slim' : 'rounded'} />}
placeholderCount={20}
ref={node}
className={clsx('divide-y divide-solid divide-gray-200 dark:divide-gray-800', {

View File

@ -50,7 +50,7 @@ export interface IStatus {
featured?: boolean
hideActionBar?: boolean
hoverable?: boolean
variant?: 'default' | 'rounded'
variant?: 'default' | 'rounded' | 'slim'
showGroup?: boolean
accountAction?: React.ReactElement
}

View File

@ -20,7 +20,7 @@ export type CardSizes = keyof typeof sizes
interface ICard {
/** The type of card. */
variant?: 'default' | 'rounded'
variant?: 'default' | 'rounded' | 'slim'
/** Card size preset. */
size?: CardSizes
/** Extra classnames for the <div> element. */
@ -37,6 +37,7 @@ const Card = React.forwardRef<HTMLDivElement, ICard>(({ children, variant = 'def
className={clsx({
'bg-white dark:bg-primary-900 text-gray-900 dark:text-gray-100 shadow-lg dark:shadow-none': variant === 'rounded',
[sizes[size]]: variant === 'rounded',
'py-4': variant === 'slim',
}, className)}
>
{children}

View File

@ -26,6 +26,7 @@ const Toggle: React.FC<IToggle> = ({ id, size = 'md', name, checked, onChange, r
'cursor-default': disabled,
})}
onClick={handleClick}
type='button'
>
<div className={clsx('rounded-full bg-white transition-transform', {
'h-4.5 w-4.5': size === 'sm',

View File

@ -110,7 +110,7 @@ test('import entities with override', () => {
const now = new Date();
const action = entitiesFetchSuccess(entities, 'TestEntity', 'thingies', {
const action = entitiesFetchSuccess(entities, 'TestEntity', 'thingies', 'end', {
next: undefined,
prev: undefined,
totalCount: 2,

View File

@ -1,4 +1,4 @@
import type { Entity, EntityListState } from './types';
import type { Entity, EntityListState, ImportPosition } from './types';
const ENTITIES_IMPORT = 'ENTITIES_IMPORT' as const;
const ENTITIES_DELETE = 'ENTITIES_DELETE' as const;
@ -10,12 +10,13 @@ const ENTITIES_FETCH_FAIL = 'ENTITIES_FETCH_FAIL' as const;
const ENTITIES_INVALIDATE_LIST = 'ENTITIES_INVALIDATE_LIST' as const;
/** Action to import entities into the cache. */
function importEntities(entities: Entity[], entityType: string, listKey?: string) {
function importEntities(entities: Entity[], entityType: string, listKey?: string, pos?: ImportPosition) {
return {
type: ENTITIES_IMPORT,
entityType,
entities,
listKey,
pos,
};
}
@ -62,6 +63,7 @@ function entitiesFetchSuccess(
entities: Entity[],
entityType: string,
listKey?: string,
pos?: ImportPosition,
newState?: EntityListState,
overwrite = false,
) {
@ -70,6 +72,7 @@ function entitiesFetchSuccess(
entityType,
entities,
listKey,
pos,
newState,
overwrite,
};

View File

@ -30,7 +30,7 @@ function useCreateEntity<TEntity extends Entity = Entity, Data = unknown>(
const entity = schema.parse(result.data);
// TODO: optimistic updating
dispatch(importEntities([entity], entityType, listKey));
dispatch(importEntities([entity], entityType, listKey, 'start'));
if (callbacks.onSuccess) {
callbacks.onSuccess(entity);

View File

@ -54,7 +54,7 @@ function useEntities<TEntity extends Entity>(
const next = useListState(path, 'next');
const prev = useListState(path, 'prev');
const fetchPage = async(req: EntityFn<void>, overwrite = false): Promise<void> => {
const fetchPage = async(req: EntityFn<void>, pos: 'start' | 'end', overwrite = false): Promise<void> => {
// Get `isFetching` state from the store again to prevent race conditions.
const isFetching = selectListState(getState(), path, 'fetching');
if (isFetching) return;
@ -67,7 +67,7 @@ function useEntities<TEntity extends Entity>(
const parsedCount = realNumberSchema.safeParse(response.headers['x-total-count']);
const totalCount = parsedCount.success ? parsedCount.data : undefined;
dispatch(entitiesFetchSuccess(entities, entityType, listKey, {
dispatch(entitiesFetchSuccess(entities, entityType, listKey, pos, {
next: getNextLink(response),
prev: getPrevLink(response),
totalCount: Number(totalCount) >= entities.length ? totalCount : undefined,
@ -83,18 +83,18 @@ function useEntities<TEntity extends Entity>(
};
const fetchEntities = async(): Promise<void> => {
await fetchPage(entityFn, true);
await fetchPage(entityFn, 'end', true);
};
const fetchNextPage = async(): Promise<void> => {
if (next) {
await fetchPage(() => api.get(next));
await fetchPage(() => api.get(next), 'end');
}
};
const fetchPreviousPage = async(): Promise<void> => {
if (prev) {
await fetchPage(() => api.get(prev));
await fetchPage(() => api.get(prev), 'start');
}
};

View File

@ -14,7 +14,7 @@ import {
import { createCache, createList, updateStore, updateList } from './utils';
import type { DeleteEntitiesOpts } from './actions';
import type { Entity, EntityCache, EntityListState } from './types';
import type { Entity, EntityCache, EntityListState, ImportPosition } from './types';
enableMapSet();
@ -29,6 +29,7 @@ const importEntities = (
entityType: string,
entities: Entity[],
listKey?: string,
pos?: ImportPosition,
newState?: EntityListState,
overwrite = false,
): State => {
@ -43,7 +44,7 @@ const importEntities = (
list.ids = new Set();
}
list = updateList(list, entities);
list = updateList(list, entities, pos);
if (newState) {
list.state = newState;
@ -159,7 +160,7 @@ const invalidateEntityList = (state: State, entityType: string, listKey: string)
function reducer(state: Readonly<State> = {}, action: EntityAction): State {
switch (action.type) {
case ENTITIES_IMPORT:
return importEntities(state, action.entityType, action.entities, action.listKey);
return importEntities(state, action.entityType, action.entities, action.listKey, action.pos);
case ENTITIES_DELETE:
return deleteEntities(state, action.entityType, action.ids, action.opts);
case ENTITIES_DISMISS:
@ -167,7 +168,7 @@ function reducer(state: Readonly<State> = {}, action: EntityAction): State {
case ENTITIES_INCREMENT:
return incrementEntities(state, action.entityType, action.listKey, action.diff);
case ENTITIES_FETCH_SUCCESS:
return importEntities(state, action.entityType, action.entities, action.listKey, action.newState, action.overwrite);
return importEntities(state, action.entityType, action.entities, action.listKey, action.pos, action.newState, action.overwrite);
case ENTITIES_FETCH_REQUEST:
return setFetching(state, action.entityType, action.listKey, true);
case ENTITIES_FETCH_FAIL:

View File

@ -47,10 +47,14 @@ interface EntityCache<TEntity extends Entity = Entity> {
}
}
/** Whether to import items at the start or end of the list. */
type ImportPosition = 'start' | 'end'
export {
Entity,
EntityStore,
EntityList,
EntityListState,
EntityCache,
ImportPosition,
};

View File

@ -1,4 +1,4 @@
import type { Entity, EntityStore, EntityList, EntityCache, EntityListState } from './types';
import type { Entity, EntityStore, EntityList, EntityCache, EntityListState, ImportPosition } from './types';
/** Insert the entities into the store. */
const updateStore = (store: EntityStore, entities: Entity[]): EntityStore => {
@ -9,9 +9,10 @@ const updateStore = (store: EntityStore, entities: Entity[]): EntityStore => {
};
/** Update the list with new entity IDs. */
const updateList = (list: EntityList, entities: Entity[]): EntityList => {
const updateList = (list: EntityList, entities: Entity[], pos: ImportPosition = 'end'): EntityList => {
const newIds = entities.map(entity => entity.id);
const ids = new Set([...newIds, ...Array.from(list.ids)]);
const oldIds = Array.from(list.ids);
const ids = new Set(pos === 'start' ? [...newIds, ...oldIds] : [...oldIds, ...newIds]);
if (typeof list.state.totalCount === 'number') {
const sizeDiff = ids.size - list.ids.size;

View File

@ -105,7 +105,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
if (!account) {
return (
<div className='-mx-4 -mt-4'>
<div className='-mx-4 -mt-4 sm:-mx-6 sm:-mt-6'>
<div>
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' />
</div>
@ -608,7 +608,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
const menu = makeMenu();
return (
<div className='-mx-4 -mt-4'>
<div className='-mx-4 -mt-4 sm:-mx-6 sm:-mt-6'>
{(account.moved && typeof account.moved === 'object') && (
<MovedNote from={account} to={account.moved} />
)}

View File

@ -184,7 +184,7 @@ const EventDiscussion: React.FC<IEventDiscussion> = (props) => {
ref={scroller}
hasMore={!!next}
onLoadMore={handleLoadMore}
placeholderComponent={() => <PlaceholderStatus thread />}
placeholderComponent={() => <PlaceholderStatus variant='slim' />}
initialTopMostItemIndex={0}
emptyMessage={<FormattedMessage id='event.discussion.empty' defaultMessage='No one has commented this event yet. When someone does, they will appear here.' />}
>

View File

@ -32,7 +32,7 @@ const GroupHeader: React.FC<IGroupHeader> = ({ group }) => {
if (!group) {
return (
<div className='-mx-4 -mt-4'>
<div className='-mx-4 -mt-4 sm:-mx-6 sm:-mt-6'>
<div>
<div className='relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' />
</div>
@ -105,7 +105,7 @@ const GroupHeader: React.FC<IGroupHeader> = ({ group }) => {
};
return (
<div className='-mx-4 -mt-4'>
<div className='-mx-4 -mt-4 sm:-mx-6 sm:-mt-6'>
<div className='relative'>
{renderHeader()}

View File

@ -56,7 +56,7 @@ const GroupTimeline: React.FC<IGroupTimeline> = (props) => {
return (
<Stack space={2}>
{canComposeGroupStatus && (
<div className='border-b border-solid border-gray-200 px-2 py-4 dark:border-gray-800'>
<div className='border-b border-solid border-gray-200 py-6 dark:border-gray-800'>
<HStack alignItems='start' space={4}>
<Link to={`/@${account.acct}`}>
<Avatar src={account.avatar} size={46} />

View File

@ -8,15 +8,16 @@ import PlaceholderDisplayName from './placeholder-display-name';
import PlaceholderStatusContent from './placeholder-status-content';
interface IPlaceholderStatus {
thread?: boolean
variant?: 'rounded' | 'slim'
}
/** Fake status to display while data is loading. */
const PlaceholderStatus: React.FC<IPlaceholderStatus> = ({ thread = false }) => (
const PlaceholderStatus: React.FC<IPlaceholderStatus> = ({ variant = 'rounded' }) => (
<div
className={clsx({
'status-placeholder bg-white dark:bg-primary-900': true,
'shadow-xl dark:shadow-none sm:rounded-xl px-4 py-6 sm:p-5': !thread,
'shadow-xl dark:shadow-none sm:rounded-xl px-4 py-6 sm:p-5': variant === 'rounded',
'py-4': variant === 'slim',
})}
>
<div className='w-full animate-pulse overflow-hidden'>

View File

@ -46,7 +46,7 @@ const ThreadStatus: React.FC<IThreadStatus> = (props): JSX.Element => {
// @ts-ignore FIXME
<StatusContainer {...props} />
) : (
<PlaceholderStatus thread />
<PlaceholderStatus variant='slim' />
)}
</div>
);

View File

@ -536,7 +536,7 @@ const Thread: React.FC<IThread> = (props) => {
ref={scroller}
hasMore={!!next}
onLoadMore={handleLoadMore}
placeholderComponent={() => <PlaceholderStatus thread />}
placeholderComponent={() => <PlaceholderStatus variant='slim' />}
initialTopMostItemIndex={ancestorsIds.size}
>
{children}

View File

@ -34,6 +34,7 @@ import GroupPage from 'soapbox/pages/group-page';
import GroupsPage from 'soapbox/pages/groups-page';
import GroupsPendingPage from 'soapbox/pages/groups-pending-page';
import HomePage from 'soapbox/pages/home-page';
import ManageGroupsPage from 'soapbox/pages/manage-groups-page';
import ProfilePage from 'soapbox/pages/profile-page';
import RemoteInstancePage from 'soapbox/pages/remote-instance-page';
import StatusPage from 'soapbox/pages/status-page';
@ -299,10 +300,10 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
{features.groups && <WrappedRoute path='/groups/:id' exact page={GroupPage} component={GroupTimeline} content={children} />}
{features.groups && <WrappedRoute path='/groups/:id/members' exact page={GroupPage} component={GroupMembers} content={children} />}
{features.groups && <WrappedRoute path='/groups/:id/media' publicRoute={!authenticatedProfile} component={GroupGallery} page={GroupPage} content={children} />}
{features.groups && <WrappedRoute path='/groups/:id/manage' exact page={DefaultPage} component={ManageGroup} content={children} />}
{features.groups && <WrappedRoute path='/groups/:id/manage/edit' exact page={DefaultPage} component={EditGroup} content={children} />}
{features.groups && <WrappedRoute path='/groups/:id/manage/blocks' exact page={DefaultPage} component={GroupBlockedMembers} content={children} />}
{features.groups && <WrappedRoute path='/groups/:id/manage/requests' exact page={DefaultPage} component={GroupMembershipRequests} content={children} />}
{features.groups && <WrappedRoute path='/groups/:id/manage' exact page={ManageGroupsPage} component={ManageGroup} content={children} />}
{features.groups && <WrappedRoute path='/groups/:id/manage/edit' exact page={ManageGroupsPage} component={EditGroup} content={children} />}
{features.groups && <WrappedRoute path='/groups/:id/manage/blocks' exact page={ManageGroupsPage} component={GroupBlockedMembers} content={children} />}
{features.groups && <WrappedRoute path='/groups/:id/manage/requests' exact page={ManageGroupsPage} component={GroupMembershipRequests} content={children} />}
{features.groups && <WrappedRoute path='/groups/:groupId/posts/:statusId' exact page={StatusPage} component={Status} content={children} />}
<WrappedRoute path='/statuses/new' page={DefaultPage} component={NewStatus} content={children} exact />

View File

@ -779,15 +779,18 @@
"group.group_mod_promote_mod": "ترقية {role} الرتبة",
"group.group_mod_reject.fail": "فشل الرفض @{name}",
"group.group_mod_unblock": "رفع الحظر",
"group.group_mod_unblock.success": "أُلْغِيَّ الحظر على @ {name} من المجموعة",
"group.group_mod_unblock.success": "أُلْغِيَّ الحظر على @{name} من المجموعة",
"group.header.alt": "غلاف المجموعة",
"group.join.private": "طلب الدخول",
"group.join.public": "الإنضمام إلى المجموعة",
"group.join.request_success": "طلب الانضمام للمجموعة",
"group.join.success": "تم الإنضمام إلى المجموعة بنجاح",
"group.leave": "غادر المجموعة",
"group.leave.label": "غادر",
"group.leave.success": "غادر المجموعة",
"group.manage": "إدارة المجموعة",
"group.member.admin.limit.summary": "يمكنك تعيين ما يصل إلى {count} مشرفين للمجموعة في الوقت الحالي.",
"group.member.admin.limit.title": "تم الوصول عدد المسؤولين إلى حد",
"group.popover.action": "عرض المجموعة",
"group.popover.summary": "يجب أن تكون عضوًا في المجموعة للرد على هذه الحالة.",
"group.popover.title": "العضوية مطلوبة",
@ -806,6 +809,7 @@
"group.tabs.all": "الكل",
"group.tabs.members": "الأعضاء",
"group.upload_banner": "رفع الصورة",
"groups.discover.popular.empty": "غير قادر على جلب المجموعات الشعبية في هذا الوقت. يرجى التحقق مرة أخرى في وقت لاحق.",
"groups.discover.popular.show_more": "عرض المزيد",
"groups.discover.popular.title": "مجموعات شعبية",
"groups.discover.search.error.subtitle": "الرجاء إعادة المحاولة في وقت لاحق.",
@ -813,6 +817,7 @@
"groups.discover.search.no_results.subtitle": "حاول البحث عن مجموعة أخرى.",
"groups.discover.search.no_results.title": "لم يتم العثور على نتائج",
"groups.discover.search.placeholder": "بحث",
"groups.discover.search.recent_searches.blankslate.subtitle": "ابحث عن أسماء المجموعات، الموضوعات أو الكلمات الرئيسية",
"groups.discover.search.recent_searches.blankslate.title": "لا توجد عمليات بحث حديثة",
"groups.discover.search.recent_searches.clear_all": "امسح الكل",
"groups.discover.search.recent_searches.title": "عمليات البحث الأخيرة",
@ -942,7 +947,6 @@
"manage_group.delete_group": "حذف المجموعة",
"manage_group.done": "‏‎‏‪إنتهى",
"manage_group.edit_group": "تحرير المجموعة",
"manage_group.edit_success": "تم تحرير المجموعة",
"manage_group.fields.cannot_change_hint": "لا يمكن تغيير هذا بعد إنشاء المجموعة.",
"manage_group.fields.description_label": "الوصف",
"manage_group.fields.description_placeholder": "الوصف",
@ -959,9 +963,7 @@
"manage_group.privacy.private.label": "خاص (مطلوب موافقة المالك)",
"manage_group.privacy.public.hint": "قابل للاكتشاف. يمكن لأي شخص الانضمام.",
"manage_group.privacy.public.label": "عام",
"manage_group.submit_success": "تم إنشاء المجموعة",
"manage_group.tagline": "تربطك المجموعات بالآخرين على أساس الاهتمامات المشتركة.",
"manage_group.update": "تحديث",
"media_panel.empty_message": "لم يُعثر على أيّة وسائط.",
"media_panel.title": "الوسائط",
"mfa.confirm.success_message": "تم تأكيد إعدادات المصادقة المتعددة",

View File

@ -838,7 +838,6 @@
"manage_group.create": "Erstellen",
"manage_group.delete_group": "Gruppe löschen",
"manage_group.edit_group": "Gruppe bearbeiten",
"manage_group.edit_success": "Gruppe wurde bearbeitet",
"manage_group.fields.description_label": "Beschreibung",
"manage_group.fields.description_placeholder": "Beschreibung",
"manage_group.fields.name_label": "Gruppennname (Pflichtfeld)",
@ -852,9 +851,7 @@
"manage_group.privacy.private.label": "Privat (Bestätigung durch Veranstalter erforderlich)",
"manage_group.privacy.public.hint": "Gelistet. Jede:r kann teilnehmen.",
"manage_group.privacy.public.label": "Öffentlich",
"manage_group.submit_success": "Die Gruppe wurde erstellt",
"manage_group.tagline": "Gruppen ermöglichen es dir, neue Leute auf Grundlage gemeinsamer Interessen zu finden.",
"manage_group.update": "Update",
"media_panel.empty_message": "Keine Medien gefunden.",
"media_panel.title": "Media",
"mfa.confirm.success_message": "MFA bestätigt",

View File

@ -935,7 +935,6 @@
"manage_group.delete_group": "Borrar el grupo",
"manage_group.done": "Hecho",
"manage_group.edit_group": "Editar el grupo",
"manage_group.edit_success": "El grupo ha sido editado",
"manage_group.fields.description_label": "Descripción",
"manage_group.fields.description_placeholder": "Descripción",
"manage_group.fields.name_label": "Nombre del grupo (obligatorio)",
@ -949,9 +948,7 @@
"manage_group.privacy.private.label": "Privado (requiere aprobación del propietario)",
"manage_group.privacy.public.hint": "Público. Cualquiera puede participar.",
"manage_group.privacy.public.label": "Público",
"manage_group.submit_success": "El grupo se creó",
"manage_group.tagline": "Los grupos te conectan con otras personas en función de los intereses comunes.",
"manage_group.update": "Actualizar",
"media_panel.empty_message": "No media found.",
"media_panel.title": "Media",
"mfa.confirm.success_message": "MFA confirmed",

View File

@ -883,7 +883,6 @@
"manage_group.create": "Crea",
"manage_group.delete_group": "Elimina gruppo",
"manage_group.edit_group": "Modifica gruppo",
"manage_group.edit_success": "Hai modificato il gruppo",
"manage_group.fields.description_label": "Descrizione",
"manage_group.fields.description_placeholder": "Descrizione",
"manage_group.fields.name_label": "Nome del gruppo (obbligatorio)",
@ -897,9 +896,7 @@
"manage_group.privacy.private.label": "Privato (approvazione richiesta)",
"manage_group.privacy.public.hint": "Esibito, può partecipare chiunque.",
"manage_group.privacy.public.label": "Pubblico",
"manage_group.submit_success": "Hai creato il gruppo",
"manage_group.tagline": "I gruppi ti collegano ad altre persone con interessi in comune.",
"manage_group.update": "Aggiorna",
"media_panel.empty_message": "Nessun media.",
"media_panel.title": "Media",
"mfa.confirm.success_message": "Hai attivato l'autenticazione a due fattori",

View File

@ -7,7 +7,7 @@
"account.direct": "პირდაპირი წერილი @{name}-ს",
"account.edit_profile": "პროფილის ცვლილება",
"account.endorse": "გამორჩევა პროფილზე",
"account.familiar_followers.more": "{count} {count, plural, one {other} other {others}} you follow",
"account.familiar_followers.more": "{რაოდენობა, მრავლობითი, ერთი {# სხვა} სხვა {# სხვა}}-ს მიყვებით",
"account.follow": "გაყოლა",
"account.followers": "მიმდევრები",
"account.follows": "მიდევნებები",
@ -88,7 +88,7 @@
"column.notifications": "შეტყობინებები",
"column.public": "ფედერალური თაიმლაინი",
"compose.character_counter.title": "Used {chars} out of {maxChars} characters",
"compose.submit_success": "Your post was sent",
"compose.submit_success": "თქვენი პოსტი გაიგზავნა!",
"compose_form.direct_message_warning": "ეს ტუტი გაეგზავნება მხოლოდ ნახსენებ მომხმარებლებს.",
"compose_form.hashtag_warning": "ეს ტუტი არ მოექცევა ჰეშტეგების ქვეს, რამეთუ ის არაა მითითებული. მხოლოდ ღია ტუტები მოიძებნება ჰეშტეგით.",
"compose_form.lock_disclaimer": "თქვენი ანგარიში არაა {locked}. ნებისმიერს შეიძლია გამოგყვეთ, რომ იხილოს თქვენი მიმდევრებზე გათვლილი პოსტები.",
@ -150,11 +150,11 @@
"emoji_button.food": "საჭმელი და სასლმელი",
"emoji_button.label": "ემოჯის ჩასმა",
"emoji_button.nature": "ბუმება",
"emoji_button.not_found": "არაა ემოჯი!! (╯°□°)╯︵ ┻━┻",
"emoji_button.not_found": "ემოჯიების გარეშე.",
"emoji_button.objects": "ობიექტები",
"emoji_button.people": "ხალხი",
"emoji_button.recent": "ხშირად გამოყენებული",
"emoji_button.search": "ძებნა...",
"emoji_button.search": "ძებნა",
"emoji_button.search_results": "ძებნის შედეგები",
"emoji_button.symbols": "სიმბოლოები",
"emoji_button.travel": "მოგზაურობა და ადგილები",
@ -216,17 +216,17 @@
"lists.new.title_placeholder": "ახალი სიის სათაური",
"lists.search": "ძებნა ადამიანებს შორის რომელთაც მიჰყვებით",
"lists.subheading": "თქვენი სიები",
"loading_indicator.label": "იტვირთება...",
"loading_indicator.label": "ჩატვირთვა…",
"login.fields.instance_placeholder": "example.com",
"login.fields.password_placeholder": "Password",
"login.log_in": "Log in",
"login.sign_in": "Sign in",
"login_form.header": "Sign In",
"media_panel.title": "Media",
"mfa.mfa_disable_enter_password": "Enter your current password to disable two-factor auth:",
"mfa.mfa_disable_enter_password": "2FA-ის გამოსართავად შეიყვანეთ თქვენი მიმდინარე პაროლი.",
"mfa.mfa_setup.code_placeholder": "Code",
"mfa.mfa_setup.password_placeholder": "Password",
"mfa.mfa_setup_scan_description": "Using your two-factor app, scan this QR code or enter text key:",
"mfa.mfa_setup_scan_description": "თქვენი 2FA აპით დაასკანირეთ ეს QR კოდი, ან ტექსტი ხელით შეიყვანეთ.",
"missing_description_modal.continue": "Post",
"missing_indicator.label": "არაა ნაპოვნი",
"missing_indicator.sublabel": "ამ რესურსის პოვნა ვერ მოხერხდა",
@ -382,7 +382,7 @@
"upload_error.video_duration_limit": "Video exceeds the current duration limit ({limit} seconds)",
"upload_form.description": "აღწერილობა ვიზუალურად უფასურისთვის",
"upload_form.undo": "გაუქმება",
"upload_progress.label": "იტვირთება...",
"upload_progress.label": "ატვირთვა…",
"video.close": "ვიდეოს დახურვა",
"video.download": "Download file",
"video.exit_fullscreen": "სრულ ეკრანზე ჩვენების გათიშვა",

View File

@ -316,6 +316,7 @@
"column.developers.service_worker": "Servicearbeider",
"column.direct": "Direktemeldinger",
"column.directory": "Utforsk profiler",
"column.dislikes": "Mislikt",
"column.domain_blocks": "Skjulte domener",
"column.edit_profile": "Rediger profil",
"column.event_map": "Sted for arrangementet",
@ -338,11 +339,15 @@
"column.filters.edit": "Rediger",
"column.filters.expires": "Utløper etter",
"column.filters.hide_header": "Skjul fullstendig",
"column.filters.hide_hint": "Skjul filtrert innhold helt og holdent, istedenfor visning av advarsel",
"column.filters.home_timeline": "Hjemmetidslinje",
"column.filters.keyword": "Nøkkelord eller frase",
"column.filters.keywords": "Nøkkelord eller begrep",
"column.filters.notifications": "Varslinger",
"column.filters.public_timeline": "Offentlig tidslinje",
"column.filters.subheading_add_new": "Legg til nytt filter",
"column.filters.title": "Navn",
"column.filters.whole_word": "Helt ord",
"column.follow_requests": "Følgeforespørsler",
"column.followers": "Følgere",
"column.following": "Følger",
@ -438,6 +443,7 @@
"compose_form.spoiler_placeholder": "Innholdsadvarsel",
"compose_form.spoiler_remove": "Fjern følsomhet",
"compose_form.spoiler_title": "Følsomt innhold",
"compose_group.share_to_followers": "Del med følgerne mine",
"confirmation_modal.cancel": "Avbryt",
"confirmations.admin.deactivate_user.confirm": "Deaktiver @{name}",
"confirmations.admin.deactivate_user.heading": "Deaktiver @{acct}",
@ -623,6 +629,7 @@
"email_verifilcation.exists": "Denne e-posten er allerede tatt.",
"embed.instructions": "Kopier koden under for å bygge inn denne statusen på hjemmesiden din.",
"emoji_button.activity": "Aktivitet",
"emoji_button.add_custom": "Legg til egendefinert smilefjes",
"emoji_button.custom": "Tilpasset",
"emoji_button.flags": "Flagg",
"emoji_button.food": "Mat og drikke",
@ -630,11 +637,19 @@
"emoji_button.nature": "Natur",
"emoji_button.not_found": "Ingen emojier funnet.",
"emoji_button.objects": "Objekter",
"emoji_button.oh_no": "Oida.",
"emoji_button.people": "Mennesker",
"emoji_button.pick": "Velg et smilefjes …",
"emoji_button.recent": "Hyppig brukt",
"emoji_button.search": "Søk…",
"emoji_button.search_results": "Søkeresultat",
"emoji_button.skins_1": "Forvalg",
"emoji_button.skins_2": "Hvit",
"emoji_button.skins_3": "Lys",
"emoji_button.skins_4": "Middels",
"emoji_button.skins_5": "Mørk",
"emoji_button.skins_6": "Svart",
"emoji_button.skins_choose": "Velg forvalgt hudfarge",
"emoji_button.symbols": "Symboler",
"emoji_button.travel": "Reise & steder",
"empty_column.account_blocked": "Du er blokkert av @{accountUsername}.",
@ -648,6 +663,7 @@
"empty_column.bookmarks": "Du har ingen bokmerker ennå. Når du legger til en, vises den her.",
"empty_column.community": "Den lokale tidslinjen er tom. Skriv noe offentlig for å få snøballen til å rulle!",
"empty_column.direct": "Du har ingen direktemeldinger ennå. Når du sender eller mottar en, vises den her.",
"empty_column.dislikes": "Ingen har mislikt dette innlegget enda. Når noen gjør det vil det vises her.",
"empty_column.domain_blocks": "Det er ingen skjulte domener ennå.",
"empty_column.event_participant_requests": "Det er ingen ventende forespørsler om deltakelse på arrangementer.",
"empty_column.event_participants": "Ingen har blitt med på dette arrangementet ennå. Når noen gjør det, vil de dukke opp her.",
@ -740,6 +756,7 @@
"filters.filters_list_expired": "Utløpt",
"filters.filters_list_hide": "Skjul",
"filters.filters_list_hide_completely": "Skjul innhold",
"filters.filters_list_phrases_label": "Nøkkelord eller begrep:",
"filters.filters_list_warn": "Vis advarsel",
"filters.removed": "Filter slettet.",
"followRecommendations.heading": "Foreslåtte Profiler",
@ -751,12 +768,16 @@
"gdpr.title": "{siteTitle} bruker informasjonskapsler",
"getting_started.open_source_notice": "{code_name} er fri programvare. Du kan bidra eller rapportere problemer på GitLab på {code_link} (v{code_version}).",
"group.cancel_request": "Avbryt forespørsel",
"group.delete.success": "Gruppe slettet",
"group.demote.user.success": "@{name} er nå medlem",
"group.group_mod_authorize.fail": "Klarte ikke å godkjenne @{name}",
"group.group_mod_block": "Blokker @{name} fra gruppe",
"group.group_mod_block.success": "Blokkert @{navn} fra gruppe",
"group.group_mod_demote": "Degradere @{navn}",
"group.group_mod_kick": "Spark ut @{name} fra gruppa",
"group.group_mod_kick.success": "Sparket ut @{name} fra gruppa",
"group.group_mod_promote_mod": "Forfrem @{name} til gruppemoderator",
"group.group_mod_reject.fail": "Klarte ikke å avslå @{name}",
"group.group_mod_unblock": "Opphev Blokkering",
"group.group_mod_unblock.success": "Opphevet blokkeringen av @{navn} fra gruppa",
"group.header.alt": "Gruppeoverskrift",
@ -765,30 +786,52 @@
"group.join.request_success": "Har bedt om å bli med i gruppa",
"group.join.success": "Ble med i gruppa",
"group.leave": "Forlat gruppa",
"group.leave.label": "Forlat",
"group.leave.success": "Forlot gruppa",
"group.manage": "Behandle gruppe",
"group.member.admin.limit.summary": "Du kan tilknytte maks. {count} administratorer for denne gruppen nå.",
"group.member.admin.limit.title": "Administratorgrense nådd",
"group.popover.action": "Vis gruppe",
"group.popover.summary": "Du må være medlem av gruppen for å besvare denne statusen.",
"group.popover.title": "Medlemskap kreves",
"group.privacy.locked": "Privat",
"group.privacy.locked.full": "Privat gruppe",
"group.privacy.locked.info": "Oppdagbar. Brukere kan ta del ved godkjent forespørsel.",
"group.privacy.public": "Offentlig",
"group.privacy.public.full": "Offentlig gruppe",
"group.privacy.public.info": "Oppdagbar. Alle kan ta del.",
"group.promote.admin.confirmation.message": "Tildel @{name} administratorrolle?",
"group.promote.admin.confirmation.title": "Tildel administratorrolle",
"group.promote.admin.success": "@{name} er nå administrator",
"group.report.label": "Rapport",
"group.role.admin": "Administrator",
"group.role.owner": "Eier",
"group.tabs.all": "Alle",
"group.tabs.members": "Medlemmer",
"group.tags.hint": "Legg til maks. 3 nøkkelord som tjener som kjerneemner for diskusjoner i gruppen.",
"group.tags.label": "Etiketter",
"group.upload_banner": "Last opp bilde",
"groups.discover.popular.empty": "Kunne ikke hente populære grupper nå. Sjekk igjen senere.",
"groups.discover.popular.show_more": "Vis mer",
"groups.discover.popular.title": "Populære grupper",
"groups.discover.search.error.subtitle": "Prøv igjen senere.",
"groups.discover.search.error.title": "En feil oppstod",
"groups.discover.search.no_results.subtitle": "Prøv å søke etter en annen gruppe.",
"groups.discover.search.no_results.title": "Ingen samsvarende treff",
"groups.discover.search.placeholder": "Søk",
"groups.discover.search.recent_searches.blankslate.subtitle": "Søk etter gruppenavn, emner, eller nøkkelord",
"groups.discover.search.recent_searches.blankslate.title": "Ingen nylige søk",
"groups.discover.search.recent_searches.clear_all": "Tøm alt",
"groups.discover.search.recent_searches.title": "Nylige søk",
"groups.discover.search.results.groups": "Grupper",
"groups.discover.suggested.empty": "Kunne ikke hente foreslåtte grupper nå. Sjekk igjen senere.",
"groups.discover.suggested.show_more": "Vis mer",
"groups.discover.suggested.title": "Foreslått for deg",
"groups.empty.subtitle": "Begynn å oppdage grupper du kan bli med i, eller opprett din egen.",
"groups.empty.title": "Ingen grupper ennå",
"groups.pending.empty.subtitle": "Du har ingen ventende forespørsler.",
"groups.pending.empty.title": "Ingen ventende forespørsler",
"groups.pending.label": "Ventende forespørsler",
"groups.popular.label": "Foreslåtte grupper",
"groups.search.placeholder": "Søk i mine grupper",
"hashtag.column_header.tag_mode.all": "og {additional}",
@ -895,15 +938,22 @@
"login_form.header": "Sign In",
"manage_group.blocked_members": "Blokkerte medlemmer",
"manage_group.confirmation.copy": "Kopier lenke",
"manage_group.confirmation.info_1": "Som eieren av gruppen kan du endre brukerroller, slette innlegg, med mer.",
"manage_group.confirmation.info_2": "Begynn med det første innlegget i gruppen og få fart på samtalen.",
"manage_group.confirmation.info_3": "Del din nye gruppe med venner, familie og følgere for å øke medlemsmassen.",
"manage_group.confirmation.share": "Del denne gruppen",
"manage_group.confirmation.title": "Du er klar.",
"manage_group.create": "Opprette",
"manage_group.delete_group": "Slett gruppe",
"manage_group.done": "Ferdig",
"manage_group.edit_group": "Rediger gruppe",
"manage_group.edit_success": "Gruppen ble redigert",
"manage_group.fields.cannot_change_hint": "Dette kan ikke endres etter at gruppen er opprettet.",
"manage_group.fields.description_label": "Beskrivelse",
"manage_group.fields.description_placeholder": "Beskrivelse",
"manage_group.fields.hashtag_placeholder": "Legg til et emne",
"manage_group.fields.name_help": "Dette kan ikke endres etter at gruppen er opprettet.",
"manage_group.fields.name_label": "Gruppenavn (påkrevd)",
"manage_group.fields.name_label_optional": "Gruppenavn",
"manage_group.fields.name_placeholder": "Navn på gruppe",
"manage_group.get_started": "La oss komme i gang!",
"manage_group.next": "Neste",
@ -914,9 +964,8 @@
"manage_group.privacy.private.label": "Privat (Eierens godkjenning kreves)",
"manage_group.privacy.public.hint": "Kan oppdages. Alle kan bli med.",
"manage_group.privacy.public.label": "Offentlig",
"manage_group.submit_success": "Gruppa ble opprettet",
"manage_group.success": "Gruppe lagret.",
"manage_group.tagline": "Grupper setter deg i kontakt med andre basert på felles interesser.",
"manage_group.update": "Oppdater",
"media_panel.empty_message": "Ingen medier funnet.",
"media_panel.title": "Media",
"mfa.confirm.success_message": "MFA bekreftet",
@ -1177,6 +1226,8 @@
"remote_instance.pin_host": "Pin {host}",
"remote_instance.unpin_host": "Løsne {host}",
"remote_interaction.account_placeholder": "Skriv inn brukernavn@domene du vil handle fra",
"remote_interaction.dislike": "Gå videre til misliking",
"remote_interaction.dislike_title": "Mislik et innlegg annensteds fra",
"remote_interaction.divider": "or",
"remote_interaction.event_join": "Fortsett for å bli med",
"remote_interaction.event_join_title": "Bli med på et arrangement eksternt",
@ -1360,6 +1411,7 @@
"status.detailed_status": "Detaljert samtalevisning",
"status.direct": "Direktemelding @{name}",
"status.disabled_replies.group_membership": "Bare gruppemedlemmer kan svare",
"status.disfavourite": "Mislik",
"status.edit": "Rediger",
"status.embed": "Bygge inn",
"status.external": "View post on {domain}",

View File

@ -835,7 +835,6 @@
"manage_group.privacy.public.hint": "Widoczna w mechanizmach odkrywania. Każdy może dołączyć.",
"manage_group.privacy.public.label": "Publiczna",
"manage_group.tagline": "Grupy pozwalają łączyć ludzi o podobnych zainteresowaniach.",
"manage_group.update": "Aktualizuj",
"media_panel.empty_message": "Nie znaleziono mediów.",
"media_panel.title": "Media",
"mfa.confirm.success_message": "Potwierdzono MFA",

File diff suppressed because it is too large Load Diff

View File

@ -351,7 +351,7 @@
"column.follow_requests": "关注请求",
"column.followers": "关注者",
"column.following": "正在关注",
"column.group_blocked_members": "已屏蔽成员",
"column.group_blocked_members": "已封禁成员",
"column.group_pending_requests": "待处理的申请",
"column.groups": "群组",
"column.home": "主页",
@ -673,7 +673,7 @@
"empty_column.follow_recommendations": "似乎暂未有推荐信息,您可以尝试搜索用户或者浏览热门标签。",
"empty_column.follow_requests": "您没有收到新的关注请求。收到了之后就会显示在这里。",
"empty_column.group": "此群组还没有帖文。",
"empty_column.group_blocks": "此群组还没有屏蔽任何用户。",
"empty_column.group_blocks": "此群组还没有封禁任何用户。",
"empty_column.group_membership_requests": "此群组没有待处理的成员申请。",
"empty_column.hashtag": "此话题标签下暂时没有内容。",
"empty_column.home": "您还没有关注任何用户。快看看 {public} ,向其他人问个好吧。",
@ -778,16 +778,19 @@
"group.group_mod_kick.success": "已从群组中踢出 @{name}",
"group.group_mod_promote_mod": "分配 {role} 职务",
"group.group_mod_reject.fail": "拒绝 @{name} 失败",
"group.group_mod_unblock": "解除屏蔽",
"group.group_mod_unblock.success": "已从群组中解除屏蔽 @{name}",
"group.group_mod_unblock": "解除封禁",
"group.group_mod_unblock.success": "已从群组中解除封禁 @{name}",
"group.header.alt": "群组标题",
"group.join.private": "申请加入群组",
"group.join.public": "加入群组",
"group.join.request_success": "已申请加入群组",
"group.join.request_success": "申请已发送至群组拥有者",
"group.join.success": "已成功加入群组!",
"group.leave": "离开群组",
"group.leave.label": "离开",
"group.leave.success": "离开了群组",
"group.manage": "管理群组",
"group.member.admin.limit.summary": "目前您可以为群组分配最多 {count} 个管理员。",
"group.member.admin.limit.title": "已达到管理员个数限制",
"group.popover.action": "查看群组",
"group.popover.summary": "您必须是群组成员才能回复此状态。",
"group.popover.title": "需要成员身份",
@ -805,6 +808,8 @@
"group.role.owner": "拥有者",
"group.tabs.all": "全部",
"group.tabs.members": "成员",
"group.tags.hint": "最多添加 3 个关键词,这些关键词将作为群组讨论的核心话题。",
"group.tags.label": "标签",
"group.upload_banner": "已上传照片",
"groups.discover.popular.empty": "目前无法获取热门群组。请稍后再试。",
"groups.discover.popular.show_more": "显示更多",
@ -935,7 +940,7 @@
"login_form.header": "登录",
"manage_group.blocked_members": "已封禁成员",
"manage_group.confirmation.copy": "复制链接",
"manage_group.confirmation.info_1": "作为此群组的拥有者,你可以指派管理员,删除帖文等等。",
"manage_group.confirmation.info_1": "作为此群组的拥有者,你可以分配管理员,删除帖文等等。",
"manage_group.confirmation.info_2": "发布群组的第一条帖文,开始对话。",
"manage_group.confirmation.info_3": "与朋友、家人和关注者分享您的新群组,以增加其成员数量。",
"manage_group.confirmation.share": "分享此群组",
@ -944,10 +949,10 @@
"manage_group.delete_group": "删除群组",
"manage_group.done": "完成",
"manage_group.edit_group": "编辑群组",
"manage_group.edit_success": "群组已编辑",
"manage_group.fields.cannot_change_hint": "创建群组后此设置将无法更改。",
"manage_group.fields.description_label": "描述",
"manage_group.fields.description_placeholder": "描述",
"manage_group.fields.hashtag_placeholder": "添加一个主题",
"manage_group.fields.name_help": "创建群组后此设置将无法更改。",
"manage_group.fields.name_label": "群组名称(必填)",
"manage_group.fields.name_label_optional": "群组名称",
@ -961,9 +966,8 @@
"manage_group.privacy.private.label": "私有(需要群组所有者批准)",
"manage_group.privacy.public.hint": "可发现。任何人都可以加入。",
"manage_group.privacy.public.label": "公开",
"manage_group.submit_success": "群组已创建",
"manage_group.success": "群组已保存!",
"manage_group.tagline": "群组根据共同的兴趣将您与他人联系起来。",
"manage_group.update": "更新",
"media_panel.empty_message": "未找到媒体。",
"media_panel.title": "媒体",
"mfa.confirm.success_message": "多重身份认证MFA已成功启用",
@ -1053,6 +1057,8 @@
"notification.favourite": "{name} 点赞了您的帖文",
"notification.follow": "{name} 开始关注您",
"notification.follow_request": "{name} 请求关注您",
"notification.group_favourite": "{name} 点赞了您的群组帖文",
"notification.group_reblog": "{name} 转发了您的群组帖文",
"notification.mention": "{name} 提及了您",
"notification.mentioned": "{name} 提及了您",
"notification.move": "{name} 移动到了 {targetName}",
@ -1456,8 +1462,9 @@
"status.show_less_all": "减少这类帖文的展示",
"status.show_more_all": "增加这类帖文的展示",
"status.show_original": "显示原文本",
"status.title": "@{username} 的帖文",
"status.title": "帖文详情",
"status.title_direct": "私信",
"status.title_group": "群组帖文详情",
"status.translate": "翻译",
"status.translated_from_with": "使用 {provider} 从 {lang} 翻译而来",
"status.unbookmark": "移除书签",

View File

@ -105,7 +105,7 @@ const GroupPage: React.FC<IGroupPage> = ({ params, children }) => {
return (
<>
<Layout.Main>
<Column label={group ? group.display_name : ''} withHeader={false}>
<Column size='lg' label={group ? group.display_name : ''} withHeader={false}>
<GroupHeader group={group} />
<Tabs

View File

@ -0,0 +1,32 @@
import React from 'react';
import { Layout } from 'soapbox/components/ui';
import LinkFooter from 'soapbox/features/ui/components/link-footer';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { MyGroupsPanel, NewGroupPanel } from 'soapbox/features/ui/util/async-components';
interface IGroupsPage {
children: React.ReactNode
}
/** Page to display groups. */
const ManageGroupsPage: React.FC<IGroupsPage> = ({ children }) => (
<>
<Layout.Main>
{children}
</Layout.Main>
<Layout.Aside>
<BundleContainer fetchComponent={NewGroupPanel}>
{Component => <Component />}
</BundleContainer>
<BundleContainer fetchComponent={MyGroupsPanel}>
{Component => <Component />}
</BundleContainer>
<LinkFooter />
</Layout.Aside>
</>
);
export default ManageGroupsPage;

View File

@ -97,7 +97,7 @@ const ProfilePage: React.FC<IProfilePage> = ({ params, children }) => {
return (
<>
<Layout.Main>
<Column label={account ? `@${getAcct(account, displayFqn)}` : ''} withHeader={false}>
<Column size='lg' label={account ? `@${getAcct(account, displayFqn)}` : ''} withHeader={false}>
<div className='space-y-4'>
<Header account={account} />