(null);
filteredProjects = computed(() => {
const search = this.searchValue().toLowerCase();
@@ -104,6 +108,11 @@ export class MyProjectsComponent implements OnInit {
});
}
+ navigateToProject(project: Project): void {
+ this.activeProject.set(project);
+ this.#router.navigate(['/my-projects', project.id]);
+ }
+
ngOnInit() {
this.#store.dispatch(GetProjects);
}
diff --git a/src/app/features/my-projects/project/files/file-detail/file-detail.component.html b/src/app/features/my-projects/project/files/file-detail/file-detail.component.html
new file mode 100644
index 000000000..a800862fd
--- /dev/null
+++ b/src/app/features/my-projects/project/files/file-detail/file-detail.component.html
@@ -0,0 +1,76 @@
+
+
+
diff --git a/src/app/features/my-projects/project/files/file-detail/file-detail.component.scss b/src/app/features/my-projects/project/files/file-detail/file-detail.component.scss
new file mode 100644
index 000000000..ff6435464
--- /dev/null
+++ b/src/app/features/my-projects/project/files/file-detail/file-detail.component.scss
@@ -0,0 +1,11 @@
+@use "assets/styles/variables" as var;
+
+.back-navigation {
+ color: var(--blue-2);
+}
+
+.metadata {
+ color: var(--dark-blue-1);
+ border: 1px solid var(--grey-2);
+ border-radius: 12px;
+}
diff --git a/src/app/features/my-projects/project/files/file-detail/file-detail.component.ts b/src/app/features/my-projects/project/files/file-detail/file-detail.component.ts
new file mode 100644
index 000000000..9f167c124
--- /dev/null
+++ b/src/app/features/my-projects/project/files/file-detail/file-detail.component.ts
@@ -0,0 +1,15 @@
+import { ChangeDetectionStrategy, Component, HostBinding } from '@angular/core';
+import { SubHeaderComponent } from '@shared/components/sub-header/sub-header.component';
+import { RouterLink } from '@angular/router';
+import { Button } from 'primeng/button';
+
+@Component({
+ selector: 'osf-file-detail',
+ imports: [SubHeaderComponent, RouterLink, Button],
+ templateUrl: './file-detail.component.html',
+ styleUrl: './file-detail.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class FileDetailComponent {
+ @HostBinding('class') classes = 'flex flex-column flex-1 gap-4 w-full h-full';
+}
diff --git a/src/app/features/my-projects/project/files/project-files.component.html b/src/app/features/my-projects/project/files/project-files.component.html
new file mode 100644
index 000000000..3e05b4369
--- /dev/null
+++ b/src/app/features/my-projects/project/files/project-files.component.html
@@ -0,0 +1,128 @@
+
+
+
+
+
+@if (!selectFile()) {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Download As Zip
+
+
+
+
+
+ Create Folder
+
+
+
+
+
+ Upload File
+
+
+
+
+
+ @for (file of files(); track file.downloads) {
+
+
+ @if (file.downloadType && file.type !== "folder") {
+ @if (file.downloadType === "doc") {
+
+ } @else {
+
+ }
+ } @else {
+
+ }
+
+
+ {{ file.name }}
+
+
+
{{ file.downloads }} Downloads
+
+
+ {{ file.size }}
+
+
+ {{ file.modifiedAt | date: "MMM d, y hh:mm a" }}
+
+
+
+ }
+
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/features/my-projects/project/files/project-files.component.scss b/src/app/features/my-projects/project/files/project-files.component.scss
new file mode 100644
index 000000000..6e08ec152
--- /dev/null
+++ b/src/app/features/my-projects/project/files/project-files.component.scss
@@ -0,0 +1,49 @@
+@use "assets/styles/variables" as var;
+
+.files-table {
+ display: flex;
+ flex-direction: column;
+ border: 1px solid var.$grey-2;
+ border-radius: 8px;
+ padding: 0 12px;
+
+ &-row {
+ color: var.$dark-blue-1;
+ display: grid;
+ align-items: center;
+ grid-template-columns: 3fr 1fr 1fr 1fr 0.5fr;
+ grid-template-rows: 38px;
+ border-bottom: 1px solid var.$grey-2;
+ }
+
+ &-row:last-child {
+ border-bottom: none;
+ }
+}
+
+.sorting-container {
+ display: flex;
+ align-items: center;
+ border: 1px solid var.$grey-2;
+ border-radius: 8px;
+ padding: 12px;
+ height: 44px;
+}
+
+.outline-button {
+ font-weight: 600;
+ display: flex;
+ gap: 8px;
+ border: 1px solid var.$grey-2;
+ padding: 12px;
+ border-radius: 8px;
+ height: 44px;
+
+ &.blue {
+ color: var.$pr-blue-1;
+ }
+
+ &.green {
+ color: var.$green-1;
+ }
+}
diff --git a/src/app/features/my-projects/project/files/project-files.component.ts b/src/app/features/my-projects/project/files/project-files.component.ts
new file mode 100644
index 000000000..03430ad36
--- /dev/null
+++ b/src/app/features/my-projects/project/files/project-files.component.ts
@@ -0,0 +1,66 @@
+import {
+ ChangeDetectionStrategy,
+ Component,
+ HostBinding,
+ inject,
+ signal,
+} from '@angular/core';
+import { SubHeaderComponent } from '@shared/components/sub-header/sub-header.component';
+import { TableModule } from 'primeng/table';
+import {
+ FileItem,
+ FILES,
+} from '@osf/features/my-projects/project/files/project-files.entities';
+import { Router } from '@angular/router';
+import { Select } from 'primeng/select';
+import { FloatLabel } from 'primeng/floatlabel';
+import { SearchInputComponent } from '@shared/components/search-input/search-input.component';
+import { DropdownModule } from 'primeng/dropdown';
+import { Button } from 'primeng/button';
+import { DatePipe } from '@angular/common';
+import { Menu } from 'primeng/menu';
+
+@Component({
+ selector: 'osf-project-files',
+ imports: [
+ SubHeaderComponent,
+ TableModule,
+ Select,
+ FloatLabel,
+ SearchInputComponent,
+ DropdownModule,
+ Button,
+ DatePipe,
+ Menu,
+ ],
+ templateUrl: './project-files.component.html',
+ styleUrl: './project-files.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ProjectFilesComponent {
+ @HostBinding('class') classes = 'flex flex-column flex-1 gap-4 w-full h-full';
+ protected readonly files = signal(FILES);
+ protected readonly folderOpened = signal(false);
+ protected readonly selectFile = signal(null);
+ readonly #router = inject(Router);
+
+ selectFolder(folder: FileItem): void {
+ if (this.folderOpened()) {
+ this.folderOpened.set(false);
+ this.files.set(FILES);
+
+ return;
+ }
+
+ if (folder.children && folder.children.length > 0) {
+ this.folderOpened.set(true);
+ this.files.set([folder, ...folder.children]);
+ }
+ }
+
+ navigateToFile(file: FileItem): void {
+ if (file.type === 'file') {
+ this.#router.navigate(['/my-projects', 'project', 'files', file.id]);
+ }
+ }
+}
diff --git a/src/app/features/my-projects/project/files/project-files.entities.ts b/src/app/features/my-projects/project/files/project-files.entities.ts
new file mode 100644
index 000000000..8ba92723e
--- /dev/null
+++ b/src/app/features/my-projects/project/files/project-files.entities.ts
@@ -0,0 +1,50 @@
+export type FolderType = 'file' | 'folder';
+
+export type FileType = 'pdf' | 'doc';
+
+export interface FileItem {
+ id?: number;
+ name: string;
+ type: FolderType;
+ downloadType?: FileType;
+ downloads?: number;
+ size?: string;
+ modifiedAt?: Date;
+ children?: FileItem[];
+}
+
+export const FILES: FileItem[] = [
+ {
+ name: 'folder name example',
+ type: 'folder',
+ children: [
+ {
+ id: 0,
+ name: 'filerandomname.doc',
+ type: 'file',
+ downloadType: 'doc',
+ downloads: 12,
+ size: '1.2 MB',
+ modifiedAt: new Date('2023-10-01T12:00:00'),
+ },
+ {
+ id: 1,
+ name: 'filerandomname.pdf',
+ type: 'file',
+ downloadType: 'pdf',
+ downloads: 12,
+ size: '1.2 MB',
+ modifiedAt: new Date('2023-10-01T12:00:00'),
+ },
+ ],
+ },
+ {
+ id: 3,
+ name: 'filerandomname.doc',
+ type: 'file',
+ downloadType: 'doc',
+ downloads: 12,
+ size: '1.2 MB',
+ modifiedAt: new Date('2023-10-01T12:00:00'),
+ },
+];
diff --git a/src/app/features/my-projects/project/metadata/metadata.ts b/src/app/features/my-projects/project/metadata/metadata.ts
new file mode 100644
index 000000000..3caf33f60
--- /dev/null
+++ b/src/app/features/my-projects/project/metadata/metadata.ts
@@ -0,0 +1,32 @@
+export interface MetadataTemplate {
+ title: string;
+ description: string;
+}
+
+export const metadataTemplates: MetadataTemplate[] = [
+ {
+ title: 'OSF Enhanced Metadata',
+ description:
+ 'Additional metadata for OSF records, derived from the DataCite 4.4 Schema',
+ },
+ {
+ title: 'Human Cognitive Neuroscience Data',
+ description:
+ 'This is a template to describe human cognitive neuroscience data.',
+ },
+ {
+ title: 'Psych-DS Official Template',
+ description:
+ 'A community standard providing a systematic way of formatting and documenting datasets',
+ },
+ {
+ title: 'mateBUS',
+ description:
+ 'A metadata template for applied psychology and organizational research
',
+ },
+ {
+ title: 'LDbase Project Metadata Form ver. 2',
+ description:
+ 'The LDbase template is for projects in the fields of education, learning, and human development.',
+ },
+];
diff --git a/src/app/features/my-projects/project/metadata/project-metadata.component.html b/src/app/features/my-projects/project/metadata/project-metadata.component.html
new file mode 100644
index 000000000..ea547b7c3
--- /dev/null
+++ b/src/app/features/my-projects/project/metadata/project-metadata.component.html
@@ -0,0 +1,40 @@
+
+
+
+
+ Select a Metadata Template
+
+
+ OSF has partnered with
CEDAR to provide more ways
+ to annotate your research with domain or community-specific metadata
+ records. If you would like to request the addition of a new metadata
+ template, contact us at
support@osf.io.
+
+
+
+
+ @for (meta of metadataTemplates; track meta.title) {
+
+ }
+
+
+
+
diff --git a/src/app/features/my-projects/project/metadata/project-metadata.component.scss b/src/app/features/my-projects/project/metadata/project-metadata.component.scss
new file mode 100644
index 000000000..cad8088a3
--- /dev/null
+++ b/src/app/features/my-projects/project/metadata/project-metadata.component.scss
@@ -0,0 +1,8 @@
+@use "assets/styles/variables" as var;
+
+.metadata {
+ border: 1px solid var(--grey-2);
+ border-radius: 12px;
+ flex-basis: 550px;
+ height: 188px;
+}
diff --git a/src/app/features/my-projects/project/metadata/project-metadata.component.ts b/src/app/features/my-projects/project/metadata/project-metadata.component.ts
new file mode 100644
index 000000000..18fca27f9
--- /dev/null
+++ b/src/app/features/my-projects/project/metadata/project-metadata.component.ts
@@ -0,0 +1,17 @@
+import { ChangeDetectionStrategy, Component, HostBinding } from '@angular/core';
+import { SubHeaderComponent } from '@shared/components/sub-header/sub-header.component';
+import { metadataTemplates } from '@osf/features/my-projects/project/metadata/metadata';
+import { Button } from 'primeng/button';
+import { RouterLink } from '@angular/router';
+
+@Component({
+ selector: 'osf-project-metadata',
+ imports: [SubHeaderComponent, Button, RouterLink],
+ templateUrl: './project-metadata.component.html',
+ styleUrl: './project-metadata.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ProjectMetadataComponent {
+ @HostBinding('class') classes = 'flex flex-1 flex-column gap-4 w-full h-full';
+ protected readonly metadataTemplates = metadataTemplates;
+}
diff --git a/src/app/features/my-projects/project/overview/project-overview.component.html b/src/app/features/my-projects/project/overview/project-overview.component.html
new file mode 100644
index 000000000..02a720b53
--- /dev/null
+++ b/src/app/features/my-projects/project/overview/project-overview.component.html
@@ -0,0 +1,241 @@
+
+
+
+
+
+
+
+
Wiki
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
+ veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
+ commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
+ velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
+ occaecat cupidatat non proident, sunt in culpa qui officia deserunt ....
+
+
+
Read more
+
+
+
+
Components
+
+
+
+
+
+ Component Name Example
+
+
+
+
Michael Pasek
+
+
+ Description: Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+ aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+ laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in eprehenderit i...
+
+
+
+
+
+
+
+ Component Name Example
+
+
+
+
Michael Pasek
+
+
+ Description: Lorem ipsum dolor sit amet, consectetur adipiscing
+ elit, sed do eiusmod tempor incididunt ut labore et dolore magna
+ aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+ laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
+ dolor in eprehenderit i...
+
+
+
+
+
+
+
+
Linked Projects
+
+
+
Name Example
+
+
+
+ Description: Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
+ enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
+ ut aliquip ex ea commodo consequat. Duis aute irure dolor in
+ eprehenderit i...
+
+
+
+
+
+
Recent Activity
+
+
+
+
+
Feb 5, 2025 04:37 AM
+
+
+
+
+
+
Feb 5, 2025 04:37 AM
+
+
+
+
+
+
Feb 5, 2025 04:37 AM
+
+
+
+
+
+
diff --git a/src/app/features/my-projects/project/overview/project-overview.component.scss b/src/app/features/my-projects/project/overview/project-overview.component.scss
new file mode 100644
index 000000000..2fd8d2045
--- /dev/null
+++ b/src/app/features/my-projects/project/overview/project-overview.component.scss
@@ -0,0 +1,56 @@
+@use "assets/styles/variables" as var;
+
+.wiki,
+.component,
+.linked-projects,
+.activities {
+ border: 1px solid var(--grey-2);
+ border-radius: 12px;
+ color: var(--dark-blue-1);
+
+ &-description {
+ line-height: 24px;
+ }
+}
+
+.component {
+ &-title {
+ border: 1px solid var(--grey-2);
+ border-radius: 12px;
+ }
+}
+
+.linked-projects {
+ &-project {
+ border: 1px solid var(--grey-2);
+ border-radius: 12px;
+ }
+}
+
+.activities {
+ &-activity {
+ height: 35px;
+ border-bottom: 1px solid var(--grey-2);
+ }
+}
+
+.left-section {
+ flex: 3;
+}
+
+.right-section {
+ flex: 1;
+ border: 1px solid var(--grey-2);
+ border-radius: 12px;
+}
+
+.subject {
+ background: var(--bg-blue-3);
+ border-radius: 4px;
+ padding: 4px 12px;
+ line-height: 24px;
+}
+
+.metadata {
+ color: var.$dark-blue-1;
+}
diff --git a/src/app/features/my-projects/project/overview/project-overview.component.ts b/src/app/features/my-projects/project/overview/project-overview.component.ts
new file mode 100644
index 000000000..5424e83a9
--- /dev/null
+++ b/src/app/features/my-projects/project/overview/project-overview.component.ts
@@ -0,0 +1,15 @@
+import { ChangeDetectionStrategy, Component, HostBinding } from '@angular/core';
+import { SubHeaderComponent } from '@shared/components/sub-header/sub-header.component';
+import { Button } from 'primeng/button';
+import { NgOptimizedImage } from '@angular/common';
+
+@Component({
+ selector: 'osf-project-overview',
+ imports: [SubHeaderComponent, Button, NgOptimizedImage],
+ templateUrl: './project-overview.component.html',
+ styleUrl: './project-overview.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ProjectOverviewComponent {
+ @HostBinding('class') classes = 'flex flex-column gap-4 w-full h-full';
+}
diff --git a/src/app/features/my-projects/project/project.component.html b/src/app/features/my-projects/project/project.component.html
new file mode 100644
index 000000000..67e7bd4cd
--- /dev/null
+++ b/src/app/features/my-projects/project/project.component.html
@@ -0,0 +1 @@
+
diff --git a/src/app/features/my-projects/project/project.component.scss b/src/app/features/my-projects/project/project.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/features/my-projects/project/project.component.ts b/src/app/features/my-projects/project/project.component.ts
new file mode 100644
index 000000000..1fd54372e
--- /dev/null
+++ b/src/app/features/my-projects/project/project.component.ts
@@ -0,0 +1,14 @@
+import { ChangeDetectionStrategy, Component, HostBinding } from '@angular/core';
+import { RouterOutlet } from '@angular/router';
+import { CommonModule } from '@angular/common';
+
+@Component({
+ selector: 'osf-project',
+ imports: [RouterOutlet, CommonModule],
+ templateUrl: './project.component.html',
+ styleUrl: './project.component.scss',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ProjectComponent {
+ @HostBinding('class') classes = 'flex flex-1 flex-column gap-4 w-full h-full';
+}
diff --git a/src/app/shared/components/search-input/search-input.component.ts b/src/app/shared/components/search-input/search-input.component.ts
index ba50cde32..2b21af88c 100644
--- a/src/app/shared/components/search-input/search-input.component.ts
+++ b/src/app/shared/components/search-input/search-input.component.ts
@@ -17,7 +17,7 @@ import { FormsModule } from '@angular/forms';
})
export class SearchInputComponent {
placeholder = input('');
- searchValue = model.required();
+ searchValue = model();
onSearchChange(value: string): void {
this.searchValue.set(value);
diff --git a/src/assets/images/files/doc.svg b/src/assets/images/files/doc.svg
new file mode 100644
index 000000000..0755bd04a
--- /dev/null
+++ b/src/assets/images/files/doc.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/assets/images/files/pdf.svg b/src/assets/images/files/pdf.svg
new file mode 100644
index 000000000..f2bd18821
--- /dev/null
+++ b/src/assets/images/files/pdf.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/src/assets/images/project/arnold-ven.png b/src/assets/images/project/arnold-ven.png
new file mode 100644
index 000000000..fbe982d02
Binary files /dev/null and b/src/assets/images/project/arnold-ven.png differ
diff --git a/src/assets/images/project/center-for-os.png b/src/assets/images/project/center-for-os.png
new file mode 100644
index 000000000..64955a25a
Binary files /dev/null and b/src/assets/images/project/center-for-os.png differ
diff --git a/src/assets/styles/styles.scss b/src/assets/styles/styles.scss
index 6d985814c..55e893e42 100644
--- a/src/assets/styles/styles.scss
+++ b/src/assets/styles/styles.scss
@@ -1,3 +1,4 @@
+@use "primeicons/primeicons.css";
@use "fonts";
@use "variables" as var;
@use "mixins" as mix;