Skip to content

Commit

Permalink
frontend fixes
Browse files Browse the repository at this point in the history
- fixed colors
- fixed hover states hopefully?
- fixed icons
- fixed note sizes
- fixed sliding + padding between courses with notes on semester
- fixed z-indexes
  • Loading branch information
plumshum committed Dec 4, 2024
1 parent e60241f commit 7e33104
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 56 deletions.
1 change: 1 addition & 0 deletions src/assets/constants/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const reviewColors = {
};

export const coursesColorSet = [
// note: can delete lighterhex now
{
text: 'Red',
hex: '#FF3B30',
Expand Down
2 changes: 1 addition & 1 deletion src/assets/images/notes/arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/images/notes/checkmark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion src/components/BottomBar/BottomBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default defineComponent({
.bottombar {
display: flex;
flex-direction: column;
z-index: 1;
z-index: 2;
position: fixed;
width: calc(100vw - 29.5rem);
margin-left: 29.5rem;
Expand Down
38 changes: 18 additions & 20 deletions src/components/Course/Course.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,27 +80,25 @@
</div>
</div>
</div>
<course-menu
v-if="menuOpen"
:courseObj="courseObj"
:semesterIndex="semesterIndex"
:isCompact="compact"
:courseColor="courseObj.color"
:courseCode="courseObj.code"
@open-note-modal="openNoteModal"
@open-edit-color-modal="openEditColorModal"
@delete-course="deleteCourse"
@edit-course-credit="editCourseCredit"
@open-save-course-modal="openSaveCourseModal"
:getCreditRange="getCreditRange || []"
v-click-outside="closeMenuIfOpen"
/>
</div>
<course-menu
v-if="menuOpen"
:courseObj="courseObj"
:semesterIndex="semesterIndex"
:isCompact="compact"
:courseColor="courseObj.color"
:courseCode="courseObj.code"
@open-note-modal="openNoteModal"
@open-edit-color-modal="openEditColorModal"
@delete-course="deleteCourse"
@edit-course-credit="editCourseCredit"
@open-save-course-modal="openSaveCourseModal"
:getCreditRange="getCreditRange || []"
v-click-outside="closeMenuIfOpen"
/>
<Note
v-if="isNoteVisible"
class="note"
:initialTranslateY="'-67px'"
:expandedTranslateY="'-35px'"
:width="'calc(102.8% - 10px)'"
:color="cssVars['--bg-color']"
:initialNote="courseObj.note || ''"
Expand All @@ -109,6 +107,7 @@
@open-delete-note-modal="openDeleteNoteModal"
ref="note"
v-click-outside="handleClickOutsideNote"
:noteId="`course-${courseObj.uniqueID}`"
/>
</div>
</template>
Expand Down Expand Up @@ -137,7 +136,7 @@ interface MinimalNoteComponent {
isDirty: boolean;
isExpanded: boolean;
collapseNote: () => void;
expandNote: () => void;
expandNote: () => void; // Note: This function does not exist in the Note component, but is used here.
}
export default defineComponent({
Expand Down Expand Up @@ -387,7 +386,6 @@ export default defineComponent({
.course-container {
position: relative;
padding-bottom: 20px;
}
// Emulates a slight side-to-side sway à la Figma micro-interaction.
Expand Down Expand Up @@ -417,14 +415,14 @@ export default defineComponent({
.course {
box-shadow: 0px 0px 10px 4px rgba(0, 0, 0, 0.055);
position: relative;
z-index: 1;
box-sizing: border-box;
border-radius: 0.5rem;
display: flex;
flex-direction: row;
background-color: $white;
height: 5.625rem;
cursor: grab;
z-index: 1;
&:hover {
background: $white;
Expand Down
4 changes: 3 additions & 1 deletion src/components/Modals/CourseMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
class="courseMenu-icon"
src="@/assets/images/noteIconSmall.svg"
alt="note course icon"
width="12"
height="11"
/>
<span class="courseMenu-text">Note</span>
</div>
Expand Down Expand Up @@ -277,7 +279,7 @@ export default defineComponent({
position: absolute;
right: -3rem;
top: 2rem;
z-index: 1;
z-index: 1000;
&-content {
background: $white;
Expand Down
152 changes: 119 additions & 33 deletions src/components/Notes/Note.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
<template>
<div class="note" :class="{ expanded: isExpanded }" :style="noteStyle" @click="handleClick">
<div class="note-content" :class="{ visible: isExpanded, editing: isEditing }">
<div class="note" :style="noteStyle" @click="handleClick">

Check failure on line 2 in src/components/Notes/Note.vue

View workflow job for this annotation

GitHub Actions / check

Type '{ transform: string; height: string; width: string; position: string; botton: string; backgroundColor: string; }' is not assignable to type 'string | CSSProperties | StyleValue[] | undefined'.
<div
class="note-content"
:class="{
visibleEmpty: isExpanded && initialNote === '',
visible: isExpanded,
editing: isEditing,
}"
>
<!-- NOTE: the disabled attribute is used to prevent the user from being able to edit the note
when it is expanded, but the edit icon has not been pressed. This only applies when the note
is not empty (already had something written in it previously and read from the database). -->
Expand All @@ -13,9 +20,20 @@
@input="handleInput"
/>
<img
v-if="isExpanded && initialNote === ''"
src="@/assets/images/notes/arrow.svg"
alt="Arrow icon"
class="note-icon"
:style="{ opacity: isDisabled || note.trim() === '' ? '0.5' : '1' }"
:data-id="noteId"
@click.stop="saveNote"
/>
<img
v-if="isEditing && initialNote !== ''"
src="@/assets/images/notes/checkmark.svg"
alt="Checkmark icon"
class="note-icon"
:data-id="noteId"
@click.stop="saveNote"
/>
</div>
Expand Down Expand Up @@ -43,15 +61,22 @@
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, nextTick } from 'vue';
import { Timestamp } from 'firebase/firestore';
import { coursesColorSet } from '@/assets/constants/colors';
export default defineComponent({
name: 'Note',
props: {
initialTranslateY: { type: String, default: '-50px', required: true },
expandedTranslateY: { type: String, default: '-10px', required: true },
// NOTE: each node has an ID (just the courseID)
// Each note has three types of heights and translateY values: initial, expandedInitial (empty input), and expanded. For now,
// all translateY values are the same, but this can be changed in the future.
noteId: { type: String, required: true },
initialTranslateY: { type: String, default: '-10px' },
expandedInitialTranslateY: { type: String, default: '-10px' },
expandedTranslateY: { type: String, default: '-10px' },
initialHeight: { type: String, default: '20px' },
expandedInitialHeight: { type: String, default: '40px' },
expandedHeight: { type: String, default: '60px' },
width: { type: String, default: '200px' },
color: { type: String, default: '#a8e6cf' },
initialNote: { type: String, default: '' },
Expand All @@ -75,15 +100,41 @@ export default defineComponent({
expand(newVal) {
if (newVal) this.isExpanded = true;
},
isEditing: 'updateSvgState',
isDisabled: 'updateSvgState',
note: 'updateSvgState', // Update SVG whenever note changes
},
computed: {
noteStyle() {
// Parse the heights and translate values
const trueExpandedTranslateY =
this.isExpanded && this.initialNote === '' // note is empty
? this.expandedInitialTranslateY
: this.expandedTranslateY;
const trueExpandedHeight =
this.isExpanded && this.initialNote === '' // note is empty
? this.expandedInitialHeight
: this.expandedHeight;
const translateY = this.isExpanded
? parseInt(trueExpandedTranslateY, 10)
: parseInt(this.initialTranslateY, 10);
const baseHeight = this.isExpanded
? parseInt(trueExpandedHeight, 10)
: parseInt(this.initialHeight, 10);
const visibleHeight = baseHeight + Math.max(0, -translateY); // Add the visible part of the translated note
console.log('visibleHeight', visibleHeight);

Check warning on line 129 in src/components/Notes/Note.vue

View workflow job for this annotation

GitHub Actions / check

Unexpected console statement
return {
transform: `translateX(-50%) translateY(${
this.isExpanded ? this.expandedTranslateY : this.initialTranslateY
})`,
transform: `translateX(-50%) translateY(${translateY}px)`,
height: `${visibleHeight}px`, // The height of the note itself
width: this.width,
backgroundColor: this.getLighterColor(this.color),
position: 'relative',
botton: '0',
backgroundColor: this.getLighterColor(this.color, 0.8),
};
},
// Displays
Expand All @@ -101,6 +152,10 @@ export default defineComponent({
return `${date.getMonth() + 1}/${date.getDate()}`;
},
isDisabled() {
// Disabled when not editing or when input is empty
return (!this.isEditing && this.initialNote !== '') || this.note.trim() === '';
},
},
methods: {
handleClick() {
Expand All @@ -113,6 +168,7 @@ export default defineComponent({
this.isExpanded = true;
},
saveNote() {
if (this.isDisabled) return;
this.$emit('save-note', this.note);
this.isDirty = false;
this.isEditing = false;
Expand All @@ -123,65 +179,93 @@ export default defineComponent({
this.isEditing = false;
}
},
getLighterColor(color: string) {
const colorObj = coursesColorSet.find(c => c.hex.toUpperCase() === color.toUpperCase());
return colorObj ? colorObj.lighterHex : color;
// getLighterColor(color: string) {
// const colorObj = coursesColorSet.find(c => c.hex.toUpperCase() === color.toUpperCase());
// return colorObj ? colorObj.lighterHex : color;
// },
/**
* Lighten a color in hex code by a percentage
* @param {string} unconvertedColor - The color to lighten in hex code
* @param {number} percentage - The percentage to lighten the color by (i.e: light by 80%)
*/
getLighterColor(unconvertedColor: string, percentage: number) {
const hexColor = unconvertedColor.replace('#', '');
// Convert each color channel and lighten it
const lightenedHex = hexColor
.match(/.{2}/g)
?.map(channel => {
// Convert channel from HEX to decimal
const decimal = parseInt(channel, 16);
// Lighten the channel
const lightened = Math.min(255, Math.floor(decimal + (255 - decimal) * percentage));
// Convert back to HEX, ensuring two characters
return lightened.toString(16).padStart(2, '0');
})
.join('');
return `#${lightenedHex}`;
},
updateSvgState() {
this.updateSvgColor(this.noteId);
},
// Note: this is a dynamic style update, so nextTick is used to ensure the SVG element is rendered
updateSvgColor(noteId: string) {
const color = this.isDisabled ? 'grey' : this.color;
const opacity = this.isDisabled ? '0.5' : '1';
nextTick(() => {
const svgElement = document.querySelector(`.note-icon[data-id="${noteId}"]`);
if (!svgElement) return;
(svgElement as HTMLElement).style.setProperty('--svg-filter-color', color);
(svgElement as HTMLElement).style.setProperty('opacity', opacity);
});
},
handleInput() {
this.isDirty = this.note !== this.initialNote;
},
},
});
</script>

<style scoped>
.note {
box-shadow: 0px 0px 10px 4px rgba(0, 0, 0, 0.055);
position: absolute;
box-shadow: -4px -4px 10px 4px rgba(160, 91, 91, 0.055);
left: 50%;
transform: translateX(-50%);
height: 80px;
border-radius: 12.49px;
cursor: pointer;
z-index: 0;
transition: transform 0.3s ease, filter 0.3s ease;
transition: transform 0.3s ease, height 0.3s ease, filter 0.3s ease;
display: flex;
justify-content: center;
align-items: flex-end;
padding-bottom: 10px;
overflow: hidden;
}
.note.expanded {
height: 80px;
}
.note-content {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
padding-top: 15px;
padding-left: 10px;
padding: 5px 0px 10px 10px;
opacity: 0;
transform: translateY(100%);
transition: opacity 0.3s ease, transform 0.3s ease;
}
.note-content.visible {
opacity: 1;
transform: translateY(0);
transform: translateY(-15px);
}
.note-content.visibleEmpty {
opacity: 1;
transform: translateY(0px);
}
.note-input {
flex: 1;
padding: 0;
border: none;
outline: none;
background-color: transparent;
color: #555;
font-size: 14.48px;
font-family: inherit;
padding: 5px 0;
}
.note-icon {
Expand All @@ -194,10 +278,12 @@ export default defineComponent({
cursor: pointer;
transition: filter 0.3s ease;
margin-right: 10px;
}
--svg-filter-color: grey; /* Default color */
filter: drop-shadow(0 0 0 var(--svg-filter-color)) saturate(5);
.note-icon:hover {
filter: brightness(0.7);
&:hover {
filter: opacity(0.5) drop-shadow(0 0 0 var(--svg-filter-color));
}
}
.note-footer {
Expand Down

0 comments on commit 7e33104

Please sign in to comment.