diff --git a/services/web/app/src/Features/Project/ProjectListController.mjs b/services/web/app/src/Features/Project/ProjectListController.mjs index ee9dd7e9bc..6b42b9fc7c 100644 --- a/services/web/app/src/Features/Project/ProjectListController.mjs +++ b/services/web/app/src/Features/Project/ProjectListController.mjs @@ -577,6 +577,7 @@ async function projectListPage(req, res, next) { 'overleaf-library', 'import-markdown', 'themed-modals', + 'shared-workspace', ].filter(Boolean) await Promise.all( diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index c4b747df09..dc1f435fe9 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -1344,6 +1344,7 @@ "no_actions": "", "no_add_on_purchase_while_paused": "", "no_ai_assistant": "", + "no_archived_projects": "", "no_audit_logs_found": "", "no_borders": "", "no_caption": "", @@ -1370,6 +1371,8 @@ "no_preview_available": "", "no_project_notifications_description": "", "no_projects": "", + "no_projects_match_query": "", + "no_projects_yet": "", "no_references_found": "", "no_references_found_in_this_file": "", "no_resolved_comments": "", @@ -1379,6 +1382,7 @@ "no_selection_select_file": "", "no_symbols_found": "", "no_thanks_cancel_now": "", + "no_trashed_projects": "", "no_trashed_references": "", "non_blinking_cursor": "", "normal": "", @@ -1386,6 +1390,7 @@ "normally_x_price_per_year": "", "not_managed": "", "not_now": "", + "nothing_shared_with_you_yet": "", "notification": "", "notification_personal_and_group_subscriptions": "", "notification_project_invite_accepted_message": "", @@ -1608,6 +1613,13 @@ "projects": "", "projects_count": "", "projects_list": "", + "projects_shared_with_you_directly_or_in_shared_workspaces_will_appear_here": "", + "projects_shared_with_you_directly_will_appear_here": "", + "projects_you_archive_will_appear_here": "", + "projects_you_create_across_all_your_workspaces_will_appear_here": "", + "projects_you_create_will_appear_here": "", + "projects_you_own_or_have_access_to_will_appear_here": "", + "projects_you_trash_will_appear_here": "", "provide_details_of_your_sso_configuration": "", "provider_rate_limited": "", "public": "", @@ -2573,6 +2585,7 @@ "you_can_now_log_in_sso": "", "you_can_now_search_and_add_references_from_your_rm_library_without_needing_to_import_files": "", "you_can_only_be_affiliated_with_one_group": "", + "you_can_restore_or_permanently_delete_them_at_any_time": "", "you_can_select_or_invite_collaborator": "", "you_can_select_or_invite_collaborator_plural": "", "you_can_still_use_your_premium_features": "", @@ -2639,6 +2652,7 @@ "your_subscription_will_pause_on": "", "your_subscription_will_pause_on_short": "", "your_subscriptions": "", + "your_tags": "", "youre_a_member_of_overleaf_labs": "", "youre_about_to_enable_single_sign_on": "", "youre_about_to_enable_single_sign_on_sso_only": "", diff --git a/services/web/frontend/fonts/material-symbols/MaterialSymbolsRoundedUnfilledPartialSlice.woff2 b/services/web/frontend/fonts/material-symbols/MaterialSymbolsRoundedUnfilledPartialSlice.woff2 index 0c1bed5eb3..379bf3bb7b 100644 Binary files a/services/web/frontend/fonts/material-symbols/MaterialSymbolsRoundedUnfilledPartialSlice.woff2 and b/services/web/frontend/fonts/material-symbols/MaterialSymbolsRoundedUnfilledPartialSlice.woff2 differ diff --git a/services/web/frontend/fonts/material-symbols/unfilled-symbols.mjs b/services/web/frontend/fonts/material-symbols/unfilled-symbols.mjs index cd75514c59..2aef7d579c 100644 --- a/services/web/frontend/fonts/material-symbols/unfilled-symbols.mjs +++ b/services/web/frontend/fonts/material-symbols/unfilled-symbols.mjs @@ -5,6 +5,7 @@ export default /** @type {const} */ ([ 'account_balance', + 'archive', 'arrow_back_ios_new', 'arrow_circle_up', 'auto_delete', @@ -30,6 +31,7 @@ export default /** @type {const} */ ([ 'edit_square', 'error', 'experiment', + 'find_in_page', 'find_replace', 'format_strikethrough', 'forum', diff --git a/services/web/frontend/js/features/project-list/components/no-projects.tsx b/services/web/frontend/js/features/project-list/components/no-projects.tsx new file mode 100644 index 0000000000..f9ea0addef --- /dev/null +++ b/services/web/frontend/js/features/project-list/components/no-projects.tsx @@ -0,0 +1,83 @@ +import { useTranslation } from 'react-i18next' +import MaterialIcon from '@/shared/components/material-icon' +import { Filter } from '@/features/project-list/context/project-list-context' +import NewProjectButton from '@/features/project-list/components/new-project-button' +import getMeta from '@/utils/meta' + +type NoProjectsCommonProps = { + showNewProjectButton?: boolean +} + +type NoProjectsProps = NoProjectsCommonProps & { + activeSection: Filter +} + +function NoProjects({ activeSection, showNewProjectButton }: NoProjectsProps) { + const { t } = useTranslation() + const usersBestSubscription = getMeta('ol-usersBestSubscription') + const isGroupPlan = usersBestSubscription?.type === 'group' + + return ( +
+
+
+ {activeSection === 'all' && ( + + )} + {activeSection === 'owned' && } + {activeSection === 'shared' && } + {activeSection === 'archived' && ( + + )} + {activeSection === 'trashed' && ( + + )} +
+
+
+ {(activeSection === 'all' || activeSection === 'owned') && + t('no_projects_yet')} + {activeSection === 'shared' && t('nothing_shared_with_you_yet')} + {activeSection === 'archived' && t('no_archived_projects')} + {activeSection === 'trashed' && t('no_trashed_projects')} +
+
+ {activeSection === 'all' && + t('projects_you_own_or_have_access_to_will_appear_here')} + {activeSection === 'owned' && + (isGroupPlan + ? t( + 'projects_you_create_across_all_your_workspaces_will_appear_here' + ) + : t('projects_you_create_will_appear_here'))} + {activeSection === 'shared' && + (isGroupPlan + ? t( + 'projects_shared_with_you_directly_or_in_shared_workspaces_will_appear_here' + ) + : t('projects_shared_with_you_directly_will_appear_here'))} + {activeSection === 'archived' && + t('projects_you_archive_will_appear_here')} + {activeSection === 'trashed' && ( + <> + {t('projects_you_trash_will_appear_here')} +
+ {t('you_can_restore_or_permanently_delete_them_at_any_time')} + + )} +
+
+ {showNewProjectButton && ( +
+ +
+ )} +
+
+ ) +} + +export default NoProjects diff --git a/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx b/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx index fc8d715a4b..c043246381 100644 --- a/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx +++ b/services/web/frontend/js/features/project-list/components/project-list-ds-nav.tsx @@ -24,8 +24,10 @@ import SystemMessages from '@/shared/components/system-messages' import overleafLogo from '@/shared/svgs/overleaf-a-ds-solution-mallard.svg' import overleafLogoDark from '@/shared/svgs/overleaf-a-ds-solution-mallard-dark.svg' import CookieBanner from '@/shared/components/cookie-banner' +import NoProjects from '@/features/project-list/components/no-projects' import { useActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme' import { isSplitTestEnabled } from '@/utils/splitTestUtils' +import { useFeatureFlag } from '@/shared/context/split-test-context' export function ProjectListDsNav() { const navbarProps = getMeta('ol-navbar') @@ -39,9 +41,11 @@ export function ProjectListDsNav() { filter, tags, selectedTagId, + currentFilterProjectsCount, } = useProjectListContext() const activeOverallTheme = useActiveOverallTheme() const isLibraryEnabled = isSplitTestEnabled('overleaf-library') + const isSharedWorkspaceEnabled = useFeatureFlag('shared-workspace') const selectedTag = tags.find(tag => tag._id === selectedTagId) const showTrashHeader = isLibraryEnabled && filter === 'trashed' @@ -142,49 +146,52 @@ export function ProjectListDsNav() { {showTrashHeader && } -
- - - - - {isLibraryEnabled && showNewProjectButton && ( - - + + + + ) : ( +
+ + + - )} - -
- {/* Omit the survey card in mobile view for now */} -
-
-
- - + {isLibraryEnabled && showNewProjectButton && ( + + + + )} + +
+ {/* Omit the survey card in mobile view for now */} +
+ +
+ + {tableTopArea} + + +
+
+
-
- - {tableTopArea} - - -
-
- -
-
+ )}
@@ -195,3 +202,20 @@ export function ProjectListDsNav() {
) } + +function ProjectsToolbarMobile() { + const { t } = useTranslation() + + return ( +
+
+ + +
+
+ ) +} diff --git a/services/web/frontend/js/features/project-list/components/sidebar/tags-list.tsx b/services/web/frontend/js/features/project-list/components/sidebar/tags-list.tsx index bd101e322a..3d0e730e9a 100644 --- a/services/web/frontend/js/features/project-list/components/sidebar/tags-list.tsx +++ b/services/web/frontend/js/features/project-list/components/sidebar/tags-list.tsx @@ -13,9 +13,11 @@ import { OLDropdownMenu, OLDropdownToggle, } from '@/shared/components/ol/ol-dropdown-menu' +import { useFeatureFlag } from '@/shared/context/split-test-context' export default function TagsList() { const { t } = useTranslation() + const isSharedWorkspaceEnabled = useFeatureFlag('shared-workspace') const { tags, projectsPerTag, @@ -40,7 +42,7 @@ export default function TagsList() { aria-hidden="true" data-testid="organize-projects" > - {t('organize_tags')} + {isSharedWorkspaceEnabled ? t('your_tags') : t('organize_tags')}