Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
<p align="center">
<img src="images/Logo.png" width="50%">
<img src="images/logo.png" width="50%">
</p>
<h1 align="center">FriendLink</h1>
<p align="center">A Static web social media application</p>
<p align="center">A social media application, where you can effortlessly connect with others through a range of features</p>

## Features

* Profile page
- showing your profile and your posts
* Post managment
- Create, edit, and delete posts to share your thoughts and experiences.

* Reaction System
- Express your feelings with a variety of reaction icons for posts.

* Commenting
- Engage in conversations by leaving comments on posts.

* Search Functionality
- Easily find users and posts by title with our intuitive search feature.

* Profile Customization
- Personalize your profile by updating your image and banner.

* Responsive design
- Desktop, tablet and mobile friendly across most common browsers

## Demo
Figma Prototypes
- [Mobile](https://www.figma.com/proto/HtvWXS4I3o5pnIGFNyv2NY/FriendLink?type=design&node-id=2-37&t=b0oCfkt4D4vnbGkv-1&scaling=scale-down&page-id=2%3A35&starting-point-node-id=2%3A36&mode=design)
- [Desktop](https://www.figma.com/proto/HtvWXS4I3o5pnIGFNyv2NY/FriendLink?type=design&node-id=13-4&t=O8xADYAZgqsdzDGb-1&scaling=scale-down&page-id=13%3A2&starting-point-node-id=13%3A3&mode=design)

[live demo](https://strong-sprinkles-75871e.netlify.app/)

## Project Plan

[trello board](https://trello.com/b/NeKrdf8j/development-tasks)

## Built With
- Bootstrap
- SASS
- Javascript

## How to Use

Expand All @@ -37,12 +54,15 @@ cd css-frameworks-ca
# Install dependencies
npm install

# Compile Sass
npm run build

```
### Development

To run the application in development mode
```bash
npm start
npm run dev
```

## Contact
Expand Down
341 changes: 113 additions & 228 deletions feed/index.html

Large diffs are not rendered by default.

30 changes: 22 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,47 +31,61 @@ <h1>FriendLink</h1>
</div>
<div class="tab-content">
<div id="signinForm" class="tab-pane fade show active" role="tabpanel" tabindex="0">
<form action="/profile/index.html">
<form class="needs-validation" novalidate>
<div class="mb-3">
<label for="signinEmail" class="form-label">Email</label>
<input type="email" class="form-control" id="signinEmail" required>
<input type="email" class="form-control" id="signinEmail" name="email" required>
<div class="invalid-feedback">Email needs to be @noroff.no or @stud.noroff.no</div>
</div>
<div class="mb-3">
<label for="signinPassword" class="form-label">Password</label>
<input type="password" class="form-control" id="signinPassword" minlength="8" maxlength="20" required>
<input type="password" class="form-control" id="signinPassword" name="password" minlength="8" required>
<div class="invalid-feedback">Password needs to be atleast 8 characters</div>
</div>
<div class="d-grid mb-3">
<button class="btn btn-primary">Sign in</button>
</div>
</form>
</div>
<div id="registerForm" class="tab-pane fade" role="tabpanel" tabindex="0">
<form action="/profile/index.html">
<form class="needs-validation" novalidate>
<div class="mb-3">
<label for="registerName" class="form-label">Username</label>
<input type="text" class="form-control" id="registerName" name="name">
<div class="invalid-feedback">Username can not contain punctuation symbols apart from (_)</div>
</div>
<div class="mb-3">
<label for="registerEmail" class="form-label">Email</label>
<input type="email" class="form-control" id="registerEmail" required>
<input type="email" class="form-control" id="registerEmail" name="email" required>
<div class="invalid-feedback">Email needs to be @noroff.no or @stud.noroff.no</div>
</div>
<div class="mb-3">
<label for="registerPassword" class="form-label">Password</label>
<input type="password" class="form-control" id="registerPassword" minlength="8" maxlength="20" required>
<input type="password" class="form-control" id="registerPassword" name="password" minlength="8" required>
<div class="invalid-feedback">Password needs to be atleast 8 characters</div>
</div>
<div class="mb-3">
<label for="registerPasswordRepeat" class="form-label">Repeat Password</label>
<input type="password" class="form-control" id="registerPasswordRepeat" minlength="8" maxlength="20" required>
<input type="password" class="form-control" id="registerPasswordRepeat" name="password" minlength="8" required>
<div class="invalid-feedback">Password does not match</div>
</div>
<div class="d-grid mb-3">
<button class="btn btn-primary">Continue</button>
</div>
</form>
</div>
</div>
<div class="mb-3">
<div id="auth-error" class="invalid-feedback">Something went wrong!</div>
</div>
<div class="d-grid mb-3">
<button class="btn btn-outline-primary">Forgot Password?</button>
</div>
</div>
</div>
</div>
</main>
<script src="../node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="/js/bootstrap.bundle.min.js"></script>
<script type="module" src="js/index.js"></script>
</body>
</html>
7 changes: 7 additions & 0 deletions js/bootstrap.bundle.min.js

Large diffs are not rendered by default.

112 changes: 112 additions & 0 deletions js/components/commentSection.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { timePassed } from "../utils/timeUtils.mjs";
import { apiCall } from "../services/apiServices.mjs";
/**
* @description Creates and returns a container for displaying comments and reactions.
* @param {Array<Object>} comments
* @param {Array<Object>} reactions
* @returns {HTMLDivElement}
*/
export function commentSection(comments, reactions) {
const div = document.createElement("div");
div.className = "comment-container";
const reactionElement = createReactElements(reactions);
const commentElements = createComments(comments);
div.append(reactionElement);
div.append(commentElements);
return div;
}

/**
* @description Creates and returns a container for displaying reaction buttons based on the provided reaction data.
* @param {Array<Object>} reactions
* @returns {HTMLDivElement}
*/
function createReactElements(reactions) {
const div = document.createElement("div");
div.classList.add("bg-primary-subtle");
let hearth = 0;
let smile = 0;
let frown = 0;
reactions.filter((reaction) => {
if (reaction.symbol === "💗") {
hearth += reaction.count;
}
if (reaction.symbol === "😀") {
smile += reaction.count;
}
if (reaction.symbol === "🙁") {
frown += reaction.count;
}
});
div.innerHTML = `
<button class="btn react-btn fs-5 position-relative">💗<span class="position-absolute top-0 end-0 badge bg-secondary">${hearth}</span></button>
<button class="btn react-btn fs-5 position-relative">😀<span class="position-absolute top-0 end-0 badge bg-secondary">${smile}</span></button>
<button class="btn react-btn fs-5 position-relative">🙁<span class="position-absolute top-0 end-0 badge bg-secondary">${frown}</span></button>
<button class="btn toggle-comment-btn">Reply</button>
`;
return div;
}

/**
* @description Creates and returns a container for displaying comments based on the provided comment data.
* @param {Array<Object>} comments
* @returns {HTMLDivElement}
*/
function createComments(comments) {
const div = document.createElement("div");
div.classList.add("bg-body", "p-3");
div.innerHTML = `
<div class="border-bottom border-primary mb-3">
<h3 class="fs-5">Comments (${comments.length})</h3>
</div>
<div class="collapse bg-body mb-3">
<form class="col comment-form d-flex align-items-stretch rounded-pill">
<textarea class="form-control p-1" style="height: 48px;" aria-label="post a comment"></textarea>
<div class="d-grid">
<button class="btn btn-primary comment-btn rounded-end-pill">Comment</button>
</div>
</form>
</div>
`;
Array.from(comments).reverse().forEach(comment => {
const com = document.createElement("div");
com.dataset.commentId = comment.id;
const commentHeader = document.createElement("div");
commentHeader.innerHTML = `
<div class="d-flex gap-2 align-items-center">
<img src="${comment.author.avatar.url}" class="user-icon-sm" alt="${comment.author.avatar.alt}">
<h2 class="fs-5">${comment.author.name}</h2>
</div>`;
const time = timePassed(comment.created);
const body = document.createElement("p");
body.textContent = comment.body;
if (comment.author.name === localStorage["name"]) {
const deleteBtn = document.createElement("button");
deleteBtn.classList.add("btn", "btn-danger", "btn-sm", "delete-comment-btn", "float-end");
deleteBtn.textContent = "delete";
com.append(deleteBtn);
}
com.append(commentHeader);
com.append(time);
com.append(body);
div.append(com);
});
return div;
}

/**
* @description Updates the reaction buttons within a specified container with new reaction data.
* @param {HTMLElement} container
* @param {Array<Object>} reactions
*/
export function updateReactions(container, reactions) {
const item = container.querySelector(".bg-primary-subtle");
const newItem = createReactElements(reactions);
item.replaceWith(newItem);
}
export async function updateComments(container) {
const api = await apiCall(`/social/posts/${container.dataset.id}?_author=true&_reactions=true&_comments=true`);
const item = container.querySelector(".bg-body");
const newItem = createComments(api.data.comments);
item.replaceWith(newItem);
}
Loading