Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Accessible Cards in Lesson Resource Selection #13060

Open
wants to merge 26 commits into
base: develop
Choose a base branch
from

Conversation

nucleogenesis
Copy link
Member

@nucleogenesis nucleogenesis commented Feb 8, 2025

Summary

  • Introduces a component MetadataChips in kolibri-common to handle displaying lists of metadata chips
  • Refactors useCoachMetadataTags to return structured data that slots into MetadataChips nicely
  • Updates Accessible*Cards to better align w/ the Figma spec and per notes given by @jtamiace last week
  • Adds bookmark save/remove messages to core strings

Bonus

Updates the api spec export script where it would fail to parse directories that had . in them. (thanks @rtibbles for the help on this!)

DOES NOT INCLUDE

  • The on-hover "view more" pop-up dealy on channel cards

References

Closes #12732

Reviewer guidance

Code review

  • Please give particular focus to MetadataChips and my updates to useCoachMetadata; any suggestions for readability/flexibility?
  • I'd appreciate thoughts re: the use of /deep/ w/ KCard - I wonder if perhaps we should consider an appearanceOverrides prop on them? Personally, I found using /deep/ here to be pleasant as the class hierarchies change as, say, the screen dimensions change - so you can easily override styles for each particular configuration of the KCard (vertical vs horizontal, small vs large thumbs, etc).

Design & QA Review

  • Do things function as expected w/ regard to selecting & deselecting
  • Be aware that I have NOT fixed this fix bookmarks not fetching when changed  #13077 here - so while your bookmark interactions should persist, you may not see the UI reflect reality at times until you reload

@github-actions github-actions bot added APP: Coach Re: Coach App (lessons, quizzes, groups, reports, etc.) DEV: frontend labels Feb 8, 2025
@nucleogenesis
Copy link
Member Author

nucleogenesis commented Feb 11, 2025

@marcellamaki @AlexVelezLl

The Bookmarks count is not updated on the root page of the LessonResourceSelection when I add/remove bookmarks while navigating the tree. So if I have 4 bookmarks, go in and add 4 more, then I go back to the root and see the bookmarks card still has 4.

I tried to hack at it to fix it a bit but couldn't get it to re-fetch correctly. I gave it like 30 mins and gave up on it - should I make a follow-up for issue for this?

FWIW I tried:

  • Put the force: true on the ContentNodeResource.fetch_bookmarks call that happens on that page
  • Call the getBookmarks in SelectionIndex during route update and enter, which didn't work
  • Combination of these two things
  • Get the fetchData method from the fetchBookmarks and call it when the page loads (this resulted in infinite page reloads 🤷‍♂️ )
  • I threw other things at the wall with no luck 😅

It seems like it might be some part of how the fetchBookmarks object works - I expected the fetchData method to be the one that'd work so maybe I'm missing something there.

@AlexVelezLl
Copy link
Member

AlexVelezLl commented Feb 13, 2025

Hey @nucleogenesis! Yes, we will need to call the bookmarksFetch.fetchData right after we save or remove a bookmark or if we dont want to make another api call here to load them, we can also add/remove items from the bookmarksFetch.data ref array and update the bookmarksFetch.count value. Any of them will properly update the bookmarks list.

Get the fetchData method from the fetchBookmarks and call it when the page loads (this resulted in infinite page reloads 🤷‍♂️ )

The reason of the infinite page reload here is because fetching bookmarks triggers this loading computed property to true, and this causes a remount of the router view here. And thats why if we call it inside the setup method it will cause an infinite loop of loading -> fetching -> loading -> fetching, etc. A solution for this could be to replace this v-else with a v-show so the component is not unmounted, but I dont think fetching the bookmarks all the times that we open the select from bookmarks page would be very efficient, and also because we also need the bookmarks updated in the SelectionIndex page because there we also render the bookmarks count, so we would also need to call it inside that subpage.

I think this can be a follow up issue, and we can explore more there the implications of each option :)

});
}

function isBookmarked(contentnode_id) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wonder if it would be better to check the existence of content.bookmark object to verify if the resource has been bookmarked? For example we use this to show the "bookmarked x days ago" in the SelectFromBookmarks subpage here.

With this we avoid needing to load all bookmarks each time this component is mounted. Because this component will be remounted each time we navigate through the folder tree/bookmarks/search results and I think we can save us from making this fetch all these times.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @AlexVelezLl - I'll ping you as I work on it in more detail addressing this issue in another PR

@toggleBookmark="toggleBookmark"
>
<template #belowTitle>
<p v-if="contentCardMessage(content)">{{ contentCardMessage(content) }}</p>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a little regression here. In the SelectFromBookmarks component, the cards now dont show the Bookmarked label:

Before:
Screenshot from 2025-02-13 13-50-49

After:
image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great catch! Fixed

@nucleogenesis nucleogenesis force-pushed the 12732--refactoring-to-use-updated-cards branch 4 times, most recently from 5dd8993 to ee27359 Compare February 25, 2025 21:49
@github-actions github-actions bot added the DEV: backend Python, databases, networking, filesystem... label Feb 25, 2025
@nucleogenesis nucleogenesis requested a review from pcenov February 25, 2025 23:36
Copy link
Member

@AlexVelezLl AlexVelezLl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @nucleogenesis! Nothing blocking, Just some thoughts :)

</li>
</KRadioButtonGroup>
</ul>
<!-- As a fallback, if any contents have checkboxes at all, we'll want to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondering if we can somehow solve this in the scope of KCard/KCardGrid, not now, but if we see more cases like this I think it can be worth trying cc: @MisRob.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, whatever further improvements we can do to KDS card and grid it'd be lovely to have it reported to KDS, even if it'd be for tracking purposes at first

thumbnailAlign="right"
>
<template #thumbnailPlaceholder>
<div class="default-folder-icon">
<KIcon
icon="topic"
:color="$themePalette.grey.v_700"
style="top: 0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have also found myself setting this top value to 0 😅. Its a little annoying imo.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very annoying 😄

@@ -228,4 +284,17 @@
margin-left: $checkbox-offset;
}

.filter-chip {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not finding any node that uses these classes, probably they were left behind after some refactoring 😅

};

const getResourceTags = () => {
return [...getActivityTags(), ...getDurationTag(), ...getCategoryTags()];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that getActivityTags is expected to return an array, but if we have contentNode.learning_activities.length > 1 then we will return a single object instead: https://github.com/learningequality/kolibri/pull/13060/files#diff-485e19c293664fde10e23bc0b3d37eb38fd664f996248cb729a31964d08d5558R55.

@@ -0,0 +1,190 @@
/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a file rename, right? Should we remove the useLearningActivities that exists in Learn and refactor the import references or is not needed for now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for catching this! I just moved it so I could use it in my work but skipped the removal of the one in learn and updating all of the imports for it throughout Learn 😓

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine to not do that refactor in Learn now, but @nucleogenesis can you make a follow up issue for this and tag it into Planned Patch 1? I think this would be good cleanup to do promptly, although not release blocking, to avoid confusion

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made #13197 for this

};

</script>


<style lang="scss" scoped>

.header-bar {
/deep/ .k-horizontal-with-small-thumbnail.k-thumbnail-align-right .k-thumbnail {
margin: 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be fixed in KCard, its a little inconsistent that when we have thumbnailDisplay=small the thumbnail is bigger than when we have thumbnailDisplay=large 😅.

thumbnailDisplay small (+margin: 0) thumbnailDisplay large
image image

If we want to keep the combination of small thumbnailDisplay + margin 0 to accomodate better the thumbnail for now, we will also need to set the border radius of top-left and bottom-left corners to 0.

image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AlexVelezLl I'd love to apply these updates (where appropriate) to KCard but I hesitated to get into changing KDS if I could avoid it for now.

That said, @MisRob if you could give a look here to some of the /deep/ styles I used that'd be really great.

The issue I ran into was that when I used small then the footer extended to the right, underneath the thumbnail. We want the footer to stop at the thumbnail (ie, it's the same width as title & description) -- but also for the thumbnail to be smaller.

The changes I've used kind of resize everything to accommodate the specs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the border-radius, great catch thanks Alex!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue I ran into was that when I used small then the footer extended to the right, underneath the thumbnail. We want the footer to stop at the thumbnail (ie, it's the same width as title & description) -- but also for the thumbnail to be smaller.

This sounds to me as possible inconsistency between designs and KCard implementation, or between the many designs, we may need to talk about. Let's chat on Slack so I can understand this better first.

@jtamiace
Copy link
Member

Looking great @nucleogenesis 👏🏼
Only have a few notes on polishing the layout

  • Could you make the distance between the title and labels on resource cards match the distance that it is on folder cards?
  • I'm not sure how much margin is in between each of the cards, but I think that can also do with being reduced a bit. In Figma I have that set to 24px.
  • The activity label on resource cards could use a little more left padding so that it matches the right - a bit squeezed right now.
  • The hover state of the bookmark icon looks squished vertically, and I notice that the tooltip label for the empty bookmark said "Saved from bookmarks" while in the channel folder

@MisRob
Copy link
Member

MisRob commented Feb 28, 2025

Hi @nucleogenesis, this is wonderful overall. Regarding the overrides where you mentioned me, I posted to Slack to clarify few things at first, before I dive into details.

Regarding @jtamiace:

I'm not sure how much margin is in between each of the cards, but I think that can also do with being reduced a bit. In Figma I have that set to 24px.

This should be possible to configure by rowGap/columnGap https://design-system.learningequality.org/kcardgrid#layout-customization :)

By the way, @jtamiace , would you say that 24px is the best general value that we should use as default on all KCardGrids? Default is 30px now, can be seen on live examples.

@MisRob
Copy link
Member

MisRob commented Feb 28, 2025

I think it's important to clarify styles overrides, but I'd be fine if actual changes, if needed, be done as follow-up.

Besides that, I gave the card components very brief skim and didn't notice anything major. So nothing blocking from me. Lovely to see it coming together :)

@jtamiace
Copy link
Member

@MisRob thanks, nice to know that's built in and yes I think 24px feels pretty balanced

@pcenov
Copy link
Member

pcenov commented Mar 4, 2025

Hi @nucleogenesis, looks great, I just have the following questions:

  1. For all of my folders the description text is not shown on the card under the title as specified in Figma, is this intentional or an oversight:
no-folder-description.mp4
  1. In Figma I can see an info icon displayed next to the bookmark icon but it's not implemented yet here or perhaps it was decided that it shouldn't be added?
  2. When I search for a resource, if there are more than 25 results then the "View more" button is not positioned correctly - probably not caused by your changes here?

view-more

  1. In the search results I see a mixture of folders and cards - is this the expected behavior? Also some cards are wider than others - shouldn't the cards be of the same size:

cards

@radinamatic
Copy link
Member

radinamatic commented Mar 4, 2025

Did not find any glaring issues in functional and visual aspects of the lesson resource selection, but navigating by keyboard was somewhat frustrating... 😞

I realize that some of these may be out of the scope of the present PR, but I thought that we would have adopted the proper coding strategies by now, and encountering them again just added to the frustration:

  1. Sidebars MUST behave as full page modals (in mobile views they really are) and trap the focus within the sidebar until the user closes it.
  2. If the user workflow contains several views within the sidebar (for example while navigating back and forth through the folders), focus order should be logical: when user selects one folder and presses Enter to open and navigate within, the focus in the next step (view) should be placed on top of the sidebar (maybe the Search button), and not at the bottom (the Save & finish button).
    https://github.com/user-attachments/assets/f430fc29-220b-4733-a92e-bc721dcb4246

Now for the issues that do need to be fixed for this feature to be considered accessible:

  1. Top left back button (left arrow icon) is missing the label (Go back should suffice).

  2. Select all checkbox is missing the visual focus outline when the state is half/partially checked.
    https://github.com/user-attachments/assets/8032b5e8-41e8-4cb7-82a9-f68d4ec7e223

  3. When one or more resources are selected, the link that appears at the bottom of the sidebar (N resources selected (...KB)) must be announced through the aria-live="polite" region.

  4. Bookmark button still needs some a11y TLC:

    • when the resource is NOT bookmarked, button should have the label Save to bookmarks, instead of the Saved from bookmarks (string I'm not sure what does it even mean)
    • when user clicks the button to bookmark the resource, that change of state is displayed visually by different icon, but those who cannot see are missing the action. We need to add the message/string Saved to bookmarks (can be visually hidden) that must also be announced through the aria-live="polite" region
    • when the user has bookmarked the resource, the label for the button must change to Remove from bookmarks
    • if/when the user decides to un-bookmark it, that change of state must also be announced by passing the Removed from bookmarks message through the aria-live="polite" region, alongside the icon change (string should probably need to be added to commonCoreStrings)

    Maybe changing the Saved from bookmarks string that is not being used anywhere (and I have had it hidden on Crowdin for the last 2 releases) into Saved to bookmarks would help with this last point 🙂

@nucleogenesis nucleogenesis force-pushed the 12732--refactoring-to-use-updated-cards branch from 6c60ab4 to 1b8d71b Compare March 10, 2025 18:49
@nucleogenesis
Copy link
Member Author

@pcenov thank you for the notes

  • My apologies for the View More remaining - I had stashed the changes and thought I'd merged them. I've applied the changes now
  • I've fixed the folder icon size issue
  • I'll ping @jtamiace to give your image a look re: the spacing/height

@nucleogenesis
Copy link
Member Author

I've found this bug where some files are way too wide. I can't figure out why exactly this is happening, but it seems related to how the thumbnails are sized somehow (although they all just are 100% width/height). I played w/ flex properties and some /deep/ styles and nothing came to me that resolved it well.

I'll come back to it again later on - but perhaps this is something that needs to be addressed in KDS or in a follow-up? (cc @marcellamaki)

image

@radinamatic
Copy link
Member

Results of the latest round of testing with today's asset (I'm adding the feedback to #13145 so anything still pending can be worked on there, and not blocking the merge of this PR):

  • The bookmark icons' strings are corrected ✔️ ❤️

  • The polite live message is set for bookmarks toggling ✔️ ❤️

  • The polite live message is set for when a user toggles a resource's selection ❌

  • Go back button now has proper tooltip & aria label applied ❌

  • I fixed the fact that focus wasn't being trapped into the side panel altogether before seeing the message above where Marcella made an issue for a11y follow-up stuff ✔️ 👏🏽

  • I could not replicate the select-all outline - I wonder if some of my recent changes have impacted this.

    Outline to indicate that the Select all checkbox is in focus appears correctly for both the unchecked and fully checked states, and is missing ONLY if the state is partially checked. So to replicate it you will need to activate the checkbox for at least one of the resources and navigate back to the Select all checkbox. It is functional, and correctly announced by the screen reader, it just misses the outline (which is a barrier for sighted users who navigate by keyboard, if not for those who use the screen reader 🙂)

@jtamiace
Copy link
Member

Agreed with @MisRob on setting limits on card sections to manage the total height of the card. I actually think that as long as there are the maximum limits for those sections, it's okay that there's a little bit of height variability when the cards are stacked vertically. Making the heights match seems more relevant for when there is >1 card in the same row?

Although, I can foresee needing to introduce limits to the number / rows of labels in the future since I don't think there is one at the moment. I think we should do this eventually since it's possible for the user to add multiple labels for categories, activity, etc. on the Studio side.

@nucleogenesis also, would you be able to make the folder label appear closer to the title? Similar to the change that you made for the resource card labels earlier.
Screenshot 2025-03-10 at 2 40 12 PM

@nucleogenesis
Copy link
Member Author

@AlexVelezLl I tried putting the fetchBookmarks.fetchData() in a beforeRouteEnter in SelectionIndex for now. So whenever you land on the index (channels list) we refetch it.

Perhaps a future enhancement could be to provide methods for adding/removing bookmarks that do the client-side data updating for us to avoid the API request. However, it's not a very heavy request so hopefully we don't see that it adds much overhead.

878189f should close #13077 in the meantime

@nucleogenesis
Copy link
Member Author

@jtamiace how's this?

image


@radinamatic

  • Go back should be fixed - am I missing which go-back you're referring to? I checked all of the kinds of page in the resource selection I could
Screencast_20250311_152700.webm
  • Polite message should now send when resource selection toggles w/ message "n resources selected"

@radinamatic @marcellamaki

I tried to work out why the select all isn't showing the outline but I couldn't figure it out. The CSS styles are being applied to the element as expected... but just for some reason it isn't visible that very particular case 😞

Should make that a follow-up bug - hopefully someone w/ fresh eyes on it can find a solution in the next couple weeks.

@radinamatic
Copy link
Member

  • Yes, I can now see the the label for the ⬅️ in all the steps of the workflow, it definitely was not there in the last asset I tested... The only remaining thing I would suggest as a follow-up is to use the Go back instead of just Back.

  • I can now also see the N resources selected message being passed (and properly updated when unchecked) to the aria-live! 👏🏽👏🏽👏🏽

    aria-live

    Point for improvement I would suggest as a follow-up is to include the size of added resources in that message (apologies if I did not specify that clearly enough previously), given that it is available for sighted users, and the idea is to offer the same experience for all 🙂

  • Select all-half-checked-missing-focus-outline conundrum remains to be further investigated in the follow-ups too 🔍

Copy link
Member

@radinamatic radinamatic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving this as we'll deal with the remaining issues in the follow-ups! :shipit:

Copy link
Member

@marcellamaki marcellamaki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of for-future-us comments for follow up discussion, and two tiny commented-out-code-cleanup requests

@@ -0,0 +1,190 @@
/**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine to not do that refactor in Learn now, but @nucleogenesis can you make a follow up issue for this and tag it into Planned Patch 1? I think this would be good cleanup to do promptly, although not release blocking, to avoid confusion

const { windowBreakpoint } = useKResponsiveWindow();
// A little data massaging to make the metadata passable to useCoachMetadataTags
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, I'm wondering if (in follow up), it might be appropriate to update useCoachMetadataTags to manage this there, rather than within the component. We can discuss and perhaps create a follow up issue, but it seems like it might make sense to move this over.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah could probably do this stuff in the getChannelTags func

@@ -1,66 +1,126 @@
//import { availableLanguages } from 'kolibri/utils/i18n';
//import uniq from 'lodash/uniq';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tiny cleanup if unused ^

...getActivityTag(),
...getDurationTag(),
...getActivityTags(),
//getDurationTag(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we not using the duration anywhere?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oof I meant to remove all of this stuff altogether as I replaced it w/ the get*Metadata functions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcellamaki I've cleaned up unused stuff here.

When I spoke w/ @jtamiace the tags that are returned by the get*Metadata functions are the ones she said we should be returning. I left a couple internal functions in comments as they may be useful in the future if we make design changes.

@jtamiace
Copy link
Member

@jtamiace how's this?

Thanks, it looks good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
APP: Coach Re: Coach App (lessons, quizzes, groups, reports, etc.) DEV: backend Python, databases, networking, filesystem... DEV: frontend DEV: tools Internal tooling for development
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Refactor ContentCardList to use the new KCardGrid and the AccessibleResourceCard and AccessibleFolderCard
7 participants