Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
NoelDeMartin committed Aug 9, 2024
1 parent dfa52f3 commit fc3980b
Show file tree
Hide file tree
Showing 46 changed files with 729 additions and 366 deletions.
1 change: 1 addition & 0 deletions cypress/e2e/all.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// See https://github.com/cypress-io/cypress/discussions/21628

// If you want to use it, just uncomment these lines:
import './animations.cy';
import './cloud.cy';
import './navigation.cy';
import './onboarding.cy';
Expand Down
66 changes: 66 additions & 0 deletions cypress/e2e/animations.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
describe('Cloud', () => {

beforeEach(() => {
cy.visit('/');
cy.createStubs();
});

it('Tasks collapse/expand (long)', () => {
cy.visit('/household/groceries');

cy.press('Completed');
cy.wait(1000);

cy.press('Completed');
cy.wait(1000);

cy.contains('li', 'Bananas').within(() => cy.get('input[type="checkbox"]').click());
cy.contains('li', 'Orange juice').within(() => cy.get('input[type="checkbox"]').click());
cy.wait(1000);

cy.press('Completed');
cy.wait(1000);

cy.press('Completed');
cy.wait(1000);
});

it('Tasks collapse/expand (short)', () => {
cy.visit('/household');

cy.press('Completed');
cy.wait(1000);

cy.press('Completed');
cy.wait(1000);

cy.contains('li', 'Clean room').within(() => cy.get('input[type="checkbox"]').click());
cy.wait(1000);

cy.press('Completed');
cy.wait(1000);

cy.press('Completed');
cy.wait(1000);
});

it('Tasks toggle', () => {
cy.visit('/household/groceries');

cy.press('Completed');
cy.wait(1000);

cy.contains('li', 'Bananas').within(() => cy.get('input[type="checkbox"]').click());
cy.wait(1000);

cy.contains('li', 'Orange juice').within(() => cy.get('input[type="checkbox"]').click());
cy.wait(1000);

cy.press('Completed');
cy.wait(1000);

cy.contains('li', 'Orange juice').within(() => cy.get('input[type="checkbox"]').click());
cy.wait(1000);
});

});
2 changes: 1 addition & 1 deletion cypress/e2e/cloud.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ describe('Cloud', () => {
cy.get('@createMangaContainer.all').should('have.length', 1);
cy.get('@createMainTask.all').should('have.length', 4);
cy.get('@createHouseholdTask.all').should('have.length', 2);
cy.get('@createGroceriesTask.all').should('have.length', 3);
cy.get('@createGroceriesTask.all').should('have.length', 30);
cy.get('@createRecipesTask.all').should('have.length', 3);
cy.get('@createJapaneseTask.all').should('have.length', 3);
cy.get('@createMangaTask.all').should('have.length', 2);
Expand Down
5 changes: 2 additions & 3 deletions cypress/e2e/navigation.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,8 @@ describe('Navigation', () => {
cy.press('Groceries');
cy.seeActiveWorkspace('Household');
cy.seeActiveList('Groceries');
cy.see('Nuts');
cy.see('Chickpeas');
cy.see('Tomatoes');
cy.see('Bananas');
cy.see('Orange juice');

cy.press('Recipes');
cy.seeActiveWorkspace('Household');
Expand Down
35 changes: 32 additions & 3 deletions cypress/support/commands/stubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,38 @@ export function createStubs(open: boolean = true): void {
await household.relatedTasks.create({ name: 'Clean room' });
await household.relatedTasks.create({ name: 'Clean Neko\'s litter box' }).then((task) => task.toggle());

await groceries.relatedTasks.create({ name: 'Chickpeas' });
await groceries.relatedTasks.create({ name: 'Tomatoes' });
await groceries.relatedTasks.create({ name: 'Nuts' });
await groceries.relatedTasks.create({ name: 'Bananas' });
await groceries.relatedTasks.create({ name: 'Orange juice' });
await groceries.relatedTasks.create({ name: 'Whole grain bread' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Fresh apples and pears' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Baby carrots' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Red and green grapes' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Peanut butter' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Cucumber' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Fresh strawberries' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Almond milk' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Romaine lettuce' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Mixed berries (frozen)' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Broccoli florets' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Whole grain pasta' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Fresh tomatoes' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Rolled oats' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Bell peppers (variety pack)' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Fresh basil leaves' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Canned black beans' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Brown rice' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Fresh oranges and lemons' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Canned tomatoes' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Baby spinach' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Mixed nuts' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Fresh garlic and onions' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Avocado' }).then((task) => task.toggle());
await groceries.relatedTasks
.create({ name: 'Fresh blueberries and raspberries' })
.then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Zucchini and squash' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Whole wheat tortillas' }).then((task) => task.toggle());
await groceries.relatedTasks.create({ name: 'Applesauce (unsweetened)' }).then((task) => task.toggle());

await recipes.relatedTasks.create({ name: 'Ramen' });
await recipes.relatedTasks.create({ name: 'Pizza' }).then((task) => task.toggle());
Expand Down
5 changes: 5 additions & 0 deletions src/assets/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

body {
/* TODO review Josh Comeau's take */
scrollbar-gutter: stable both-edges;
}
10 changes: 8 additions & 2 deletions src/components/AppFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
<div class="flex-1">
<div :style="`width: ${$focus.footerLeftPadding ?? 0}px`" />
</div>
<footer class="flex w-full max-w-screen-xl items-center justify-center gap-1 p-3 text-sm text-gray-500">
<AnimatedElement
as="footer"
class="flex w-full max-w-screen-xl items-center justify-center gap-1 p-3 text-sm text-gray-500"
:group="$focus.footerAnimation?.group"
:animation="$focus.footerAnimation?.animation"
@animate="$focus.footerAnimation?.animate"
>
<TextLink @click="$ui.openModal(AboutModal)">
{{ $t('footer.about') }}
</TextLink>
Expand All @@ -15,7 +21,7 @@
<TextLink :url="$app.versionUrl">
{{ $app.versionName }}
</TextLink>
</footer>
</AnimatedElement>
<div class="flex-1">
<div :style="`width: ${$focus.footerRightPadding ?? 0}px`" />
</div>
Expand Down
39 changes: 25 additions & 14 deletions src/pages/workspace/WorkspaceContentBody.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<AnimatedGroup class="flex flex-col px-4">
<AnimatedGroup ref="$group" class="flex flex-col px-4" :duration="allPendingCompleted ? 500 : 300">
<TasksForm v-if="$tasksList.tasks?.length" ref="$tasksForm" @submit="createTask($event)" />

<div class="relative flex flex-grow flex-col">
Expand All @@ -19,7 +19,7 @@
leave-active-class="transition-[opacity,transform] duration-500"
leave-from-class="opacity-100 translate-y-0"
leave-to-class="absolute top-0 opacity-0 -translate-y-52"
@leave="freeze"
leave-animation="freeze"
>
<TasksEmpty v-if="allPendingCompleted && !$focus.showCompleted" />
</AnimatedTransition>
Expand Down Expand Up @@ -47,10 +47,14 @@
<span>{{ $t('tasks.completed') }}</span>
</TextButton>
<AnimatedTransition
:leave-to-class="allPendingCompleted && 'absolute bottom-0 h-0'"
:enter-from-class="allPendingCompleted && 'absolute bottom-0 h-0'"
@enter="allPendingCompleted ? showCompletedTasks($event) : grow($event)"
@leave="allPendingCompleted ? hideCompletedTasks($event) : shrink($event)"
:enter-from-class="allPendingCompleted ? 'absolute bottom-0 h-0' : 'h-0'"
:leave-to-class="allPendingCompleted ? 'absolute bottom-0 h-0' : 'h-0'"
@enter="allPendingCompleted ? toggleCompletedTasks($event) : slideDown($event.firstElementChild)"
@leave="
allPendingCompleted
? toggleCompletedTasks($event)
: ($event.classList.remove('h-0'), slideUp($event.firstElementChild))
"
>
<div v-if="$focus.showCompleted" class="list-wrapper overflow-hidden">
<TasksList :tasks="tasks.completed" :disable-editing="disableEditing" class="mt-4" />
Expand All @@ -64,25 +68,22 @@
<script setup lang="ts">
import { arrayGroupBy, arraySorted, compare } from '@noeldemartin/utils';
import { Cloud } from '@aerogel/plugin-offline-first';
import { computed, ref, watch } from 'vue';
import { computed, onUnmounted, ref, watch, watchEffect } from 'vue';
import { computedModels } from '@aerogel/plugin-soukai';
import { slideDown, slideUp } from '@/vivant/core';
import { UI } from '@aerogel/core';
import type { IAnimatedGroup } from '@/vivant/vue';
import Focus from '@/services/Focus';
import Task from '@/models/Task';
import TasksLists from '@/services/TasksLists';
import Workspaces from '@/services/Workspaces';
import { watchKeyboardShortcut } from '@/utils/composables';
import { toggleCompletedTasks, toggleFooter } from './animations/tasks';
import type { ITasksForm } from './components/tasks/TasksForm';
import { freeze, grow, hideCompletedTasks, showCompletedTasks, shrink } from './animations';
// TODOs:
// - review all screen animations (complete/undo last pending task, with completed collapsed and not, etc.)
// - could you achieve the same without custom <AnimatedTransition>? what does it add?
// ...Think about doing it framer motion style... saying "scale" somewhere
const $group = ref<IAnimatedGroup>();
const $tasksForm = ref<ITasksForm>();
const disableEditingWithKeyboard = ref(false);
const disableEditing = computed(() => UI.mobile || disableEditingWithKeyboard.value);
Expand Down Expand Up @@ -142,6 +143,14 @@ watch(
() => showPending.value,
(value) => (Focus.showCompleted &&= value),
);
watchEffect(
() =>
$group.value &&
Focus.setFooterAnimation({
group: $group.value.group,
animate: toggleFooter,
}),
);
watchKeyboardShortcut('Control', {
start: () => (disableEditingWithKeyboard.value = true),
end: () => (disableEditingWithKeyboard.value = false),
Expand All @@ -151,4 +160,6 @@ watchKeyboardShortcut('c', () => Focus.toggleCompleted());
watchKeyboardShortcut('ArrowUp', () => changeTask(-1));
watchKeyboardShortcut('ArrowDown', () => changeTask(1));
watchKeyboardShortcut('Escape', () => Workspaces.select(null));
onUnmounted(() => Focus.setFooterAnimation(null));
</script>
Loading

0 comments on commit fc3980b

Please sign in to comment.