Skip to content

Channel cards to unstable#5696

Open
MisRob wants to merge 33 commits intolearningequality:unstablefrom
MisRob:channel-cards
Open

Channel cards to unstable#5696
MisRob wants to merge 33 commits intolearningequality:unstablefrom
MisRob:channel-cards

Conversation

@MisRob
Copy link
Member

@MisRob MisRob commented Feb 10, 2026

Summary

Replaces Vuetify-based implementation by KCard on My Channels, Starred Channels, View-only Channels, and Content Library pages. On this opportunity introduces a new architecture of the related pages and resolves problems with understanding & maintaining monolithic and condition-heavy ChannelList + ChannelItem.

Before After
my-channels-before my-channels-after
starred-channels-before starred-channels-after
view-channels-before view-channels-after
content-library-before content-library-after

References

Closes #5227
Closes #5524
Closes #5525
Closes #5526

Reviewer guidance

Code review:

  • 80% of work are community contributions that were reviewed by myself and some also by @rtibbles. Then I added a final layer of work: abstractions, cleanup, user experience as well as internal architecture optimizations, fixes for few regressions, ... => I think it'd most meaningful to review affected files as a whole.

Local preview:

  • Run pnpm install first
  • Preview My Channels, Starred Channels, and View-only Channels pages
  • Preview Content Library when logged in and logged out

Notes

Before merging, [TODO REVERT] Temporarily install KDS fork commit needs to be reverted and a newly released KDS version with learningequality/kolibri-design-system#1203 installed.

Fix few regressions, refactor approach
to configuration footer.
@MisRob MisRob force-pushed the channel-cards branch 3 times, most recently from 4176428 to 3a07c26 Compare February 14, 2026 14:07
calculations. The feature is not needed in these
use-cases.
@MisRob MisRob force-pushed the channel-cards branch 2 times, most recently from 3b2e264 to cc563d2 Compare February 15, 2026 17:45
@MisRob MisRob marked this pull request as ready for review February 16, 2026 08:14
@MisRob MisRob changed the title [WIP] Channel cards to unstable Channel cards to unstable Feb 16, 2026
Copy link
Member

@bjester bjester left a comment

Choose a reason for hiding this comment

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

Some review comments

loading.value = true;
store.dispatch('channel/loadChannelList', { listType }).then(() => {
loading.value = false;
});
Copy link
Member

Choose a reason for hiding this comment

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

If this fails to load (like it times out), what happens from the user perspective?

Comment on lines +150 to +173
<KModal
v-if="deleteDialog"
:title="$tr('deleteTitle')"
:submitText="$tr('deleteChannel')"
:cancelText="$tr('cancel')"
data-testid="delete-modal"
appendToOverlay
@submit="handleDelete"
@cancel="deleteDialog = false"
>
{{ $tr('deletePrompt') }}
</KModal>
<KModal
v-if="removeDialog"
:title="$tr('removeTitle')"
:submitText="$tr('removeBtn')"
:cancelText="$tr('cancel')"
data-testid="remove-modal"
appendToOverlay
@submit="handleRemove"
@cancel="removeDialog = false"
>
{{ $tr('removePrompt') }}
</KModal>
Copy link
Member

Choose a reason for hiding this comment

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

Including these modals within the card component is a bit of a monolithic approach. Even though they're conditional under v-if, a large list of cards will still incur more memory usage than if these were broken out separately and used at the list level. Additionally, since these modals are not always necessary (i.e. the view-only list), composing their use alongside the use of the cards does make more sense IMO.

This isn't a blocker but I think it's worthwhile for consideration.

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 @bjester, makes sense. I will address this now.

There was no particular intention in keeping them within the card component ~ I think I just didn't think about this place that much. Moving them out will be well aligned with the aim of this work. And since these are used on some of the most important pages, such as catalog that can be very long, then yes saving some memory will definitely be good too.

Copy link
Member Author

@MisRob MisRob Feb 18, 2026

Choose a reason for hiding this comment

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

I thought about this and technically I think I'd like to:

  • Abstract modals to DeleteChannelModal.vue, RemoveChannelFromList.vue, ...
  • Remove footerButtons and dropdownOptions config props from StudioChannelCard and instead just provide a footer slot
  • Let the 4 pages utilizing StudioChannelCard provide
    • Template for the footer slot
    • A subset of page-level abstracted modals that are needed

I think this will mean a tiny bit more of duplicates in some areas, but I don't expect to be anything concerning. Alternatively, StudioChannelCard could also emit events when buttons or dropdown options clicked, but the resulting API and other implications feel rather convoluted to me.

Makes sense to you too @bjester? It's not complicated, but will be more changes, so if we could confirm the direction beforehand, I'd be grateful.

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 that sounds like a great plan! The reduction of the dropdownOptions in particular should make it pretty clean, and easily make up for any small duplication around the implementation of the cards.

});
},
onCardClick(channel) {
window.location.href = window.Urls.channel(channel.id);
Copy link
Member

Choose a reason for hiding this comment

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

Nitpick: I prefer window.location.assign()

@MisRob
Copy link
Member Author

MisRob commented Feb 18, 2026

I've just noticed on screenshots that I lost the invitations box being a bit wider than cards. Will fix this ~ is good for visual priority.

if (windowBreakpoint.value >= 5) return '50%';
if (windowBreakpoint.value === 4) return '66.66%';
if (windowBreakpoint.value === 3) return '83.33%';
return '100%';
Copy link
Member

Choose a reason for hiding this comment

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

Are the percentages arbitrary?

<h1 class="visuallyhidden">{{ $tr('title') }}</h1>
<!-- minHeight to prevent layout shifts when loading state changes -->
<p
class="mb-2 ml-1 title"
Copy link
Member

Choose a reason for hiding this comment

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

I wonder whether we should continue to use Vuetify's styling classes especially when we want to move away from them (I see other places where its used as well). This is more of a thought than a comment and something to think about long term?

},
onCardClick(channel) {
if (this.loggedIn) {
window.location.href = window.Urls.channel(channel.id);
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

@akolson akolson left a comment

Choose a reason for hiding this comment

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

I think code is clear and understandable. Thanks Misha for this refactor!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

6 participants

Comments