diff --git a/view-samples/music-cards-view/README.md b/view-samples/music-cards-view/README.md new file mode 100644 index 000000000..9eb178f10 --- /dev/null +++ b/view-samples/music-cards-view/README.md @@ -0,0 +1,124 @@ +# 🎵 Music Cards + +This view formatting transforms your SharePoint list into a vibrant music discovery board. Employees can recommend songs via YouTube, listen to each other's picks, and vote on their favorites. It's a fun and engaging way to share musical tastes across the organization. + +Overview of Music Cards +![screenshot of the sample](./assets/music-cards-view.png) + +Playing video +![screenshot of the sample](./assets/music-cards-view2.png) + +## ✨ Features + +- **Embedded YouTube previews** – Click the thumbnail to play the song directly in the card. +- **Artist and Title display** – Clear and stylish presentation of song details. +- **Contributor info** – See who tipped the track. +- **Star rating system** – Vote on songs with a simple 1–5 star interface. +- **Responsive design** – Cards adapt well to different screen sizes. + +## 📋 Required Settings +- Go to the settings of the list +- Click **Rating Settings** +- Switch **Rating Settings** +- Optionally choose **voting/rating experience**. +In the Music Cards View only stars are shown. You can adjust the icon to any icon you want in the code. + +Playing video +![screenshot of the settings](./assets/music-cards-view-settings.png) + +## 📋 Required Columns + +To use this View formatting, your list should include the following columns: + +| Internal Name | Display Name | Type | Description | +|-------------------|------------------|------------|----------------------------------------------| +| `Title` | Title | Single line of text | The name of the song. | +| `Artist` | Artist | Single line of text | The performing artist. | +| `YouTubeCode` | YouTube Code | Single line of text | The unique video ID from the YouTube URL. | +| `Author` | Created By | Person | Automatically filled when the item is created. | + +Beware that you don't use the full url of a YouTube video. You only need the unique ID. +The reason for that is that the script automatically will show a correct still of the video. + +## 📋 Required Columns in view +The following columns are necessary inside your view. If you do not add them, the data will not show within the Music Cards. + +| Internal Name | Display Name | +|-------------------|------------------| +| `Title` | Title | +| `Artist` | Artist | +| `Author` | Created By | +| `YouTubeCode` | YouTube Code | +| `AverageRating` | Average Rating | +| `RatingCount` | Rating Count | +| `Ratings` | Ratings | +| `RatedBy` | Rated By | + +![screenshot of the settings](./assets/music-cards-view-settings2.png) + +## 🧩 Column Formatting: YouTubeCode + +Add the following column formatting to the **YouTubeCode** column to enable embedded previews: + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json", + "elmType": "div", + "children": [ + { + "elmType": "div", + "style": { + "cursor": "pointer", + "display": "=if(@currentField,'flex','none')", + "align-items": "center" + }, + "attributes": { + "class": "ms-fontSize-s ms-fontColor-white ms-bgColor-themePrimary ms-bgColor-themeTertiary--hover" + }, + "customRowAction": { + "action": "embed", + "actionInput": { + "src": "='https://www.youtube.com/embed/' + @currentField", + "width": "640", + "height": "360" + } + }, + "children": [ + { + "elmType": "img", + "attributes": { + "src": "='https://img.youtube.com/vi/' + @currentField + '/mqdefault.jpg'" + }, + "style": { + "width": "240px", + "padding": "0px" + } + } + ] + } + ] +} +``` + +## Sample + +Solution|Author(s) +--------|--------- +music_cards_view.json | [Ron Ackermans](https://github.com/RonDZV) ([@Ron Ackermans](https://www.linkedin.com/in/ronackermans/)) + +## Version history + +Version|Date|Comments +-------|----|-------- +1.0|March 18, 2025 |Initial release + +## Disclaimer +**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.** + + +--- + + + + + diff --git a/view-samples/music-cards-view/assets/music-cards-view-settings.png b/view-samples/music-cards-view/assets/music-cards-view-settings.png new file mode 100644 index 000000000..a527afa48 Binary files /dev/null and b/view-samples/music-cards-view/assets/music-cards-view-settings.png differ diff --git a/view-samples/music-cards-view/assets/music-cards-view-settings2.png b/view-samples/music-cards-view/assets/music-cards-view-settings2.png new file mode 100644 index 000000000..89a78e38e Binary files /dev/null and b/view-samples/music-cards-view/assets/music-cards-view-settings2.png differ diff --git a/view-samples/music-cards-view/assets/music-cards-view.png b/view-samples/music-cards-view/assets/music-cards-view.png new file mode 100644 index 000000000..9d36d7b90 Binary files /dev/null and b/view-samples/music-cards-view/assets/music-cards-view.png differ diff --git a/view-samples/music-cards-view/assets/music-cards-view2.png b/view-samples/music-cards-view/assets/music-cards-view2.png new file mode 100644 index 000000000..fe01e2586 Binary files /dev/null and b/view-samples/music-cards-view/assets/music-cards-view2.png differ diff --git a/view-samples/music-cards-view/assets/sample.json b/view-samples/music-cards-view/assets/sample.json new file mode 100644 index 000000000..4cc55a0b8 --- /dev/null +++ b/view-samples/music-cards-view/assets/sample.json @@ -0,0 +1,44 @@ +[ + { + "Title": "Bohemian Rhapsody", + "Artist": "Queen", + "Author": { + "title": "Ron Ackermans" + }, + "YouTubeCode": "fJ9rUzIMcZQ", + "AverageRating": 4.8, + "RatingCount": 120, + "Ratings": "5,5,4,5,5", + "RatedBy": { + "email": "user1@example.com;user2@example.com;user3@example.com" + } + }, + { + "Title": "Imagine", + "Artist": "John Lennon", + "Author": { + "title": "Ron Ackermans" + }, + "YouTubeCode": "YkgkThdzX-8", + "AverageRating": 4.5, + "RatingCount": 85, + "Ratings": "5,4,4,5,4", + "RatedBy": { + "email": "user4@example.com;user5@example.com" + } + }, + { + "Title": "Billie Jean", + "Artist": "Michael Jackson", + "Author": { + "title": "Ron Ackermans" + }, + "YouTubeCode": "Zi_XLOBDo_Y", + "AverageRating": 4.9, + "RatingCount": 200, + "Ratings": "5,5,5,5,5", + "RatedBy": { + "email": "user6@example.com;user7@example.com" + } + } +] diff --git a/view-samples/music-cards-view/music-cards-view.json b/view-samples/music-cards-view/music-cards-view.json new file mode 100644 index 000000000..55c9e55d8 --- /dev/null +++ b/view-samples/music-cards-view/music-cards-view.json @@ -0,0 +1,278 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/tile-formatting.schema.json", + "height": 300, + "width": 250, + "hideSelection": true, + "formatter": { + "elmType": "div", + "style": { + "display": "flex", + "flex-direction": "column", + "border-radius": "12px", + "overflow": "hidden", + "xxbox-shadow": "0 8px 6px -6px black", + "background-color": "#1c1c1c", + "margin": "4px", + "border": "4px solid #fff" + }, + "children": [ + { + "elmType": "div", + "style": { + "position": "relative", + "width": "100%", + "height": "140px", + "overflow": "hidden" + }, + "children": [ + { + "elmType": "img", + "attributes": { + "src": "='https://img.youtube.com/vi/' + [$YouTubeCode] + '/mqdefault.jpg'", + "alt": "Album cover" + }, + "style": { + "width": "100%", + "height": "100%", + "object-fit": "cover" + } + }, + { + "elmType": "div", + "style": { + "position": "absolute", + "top": "0", + "left": "0", + "width": "100%", + "height": "100%", + "display": "flex", + "align-items": "center", + "justify-content": "center", + "background-color": "#00000066", + "cursor": "pointer" + }, + "customRowAction": { + "action": "embed", + "actionInput": { + "src": "='https://www.youtube.com/embed/' + [$YouTubeCode]", + "width": "640", + "height": "360" + } + }, + "children": [ + { + "elmType": "span", + "style": { + "font-size": "32px", + "color": "#ffffff" + }, + "attributes": { + "iconName": "Play" + } + } + ] + } + ] + }, + { + "elmType": "div", + "style": { + "margin-top": "0px", + "display": "inline-block", + "clear": "both" + }, + "children": [ + { + "elmType": "div", + "style": { + "padding": "0px", + "margin-top": "20px", + "display": "inline-block", + "clear": "both" + }, + "children": [ + { + "elmType": "div", + "style": { + "font-size": "18px", + "float": "left", + "width": "25px", + "color": "white", + "padding-left": "10px", + "padding-right": "8px" + }, + "attributes": { + "iconName": "MusicInCollectionFill" + } + }, + { + "elmType": "p", + "style": { + "font-size": "18px", + "float": "left", + "color": "white", + "text-transform": "Uppercase", + "margin": "0px", + "margin-top": "-6px" + }, + "attributes": { + "title": "[$Title]", + "class": "ms-fontColor-neutralPrimary sp-card-content " + }, + "txtContent": "=if ([$Title] == '', '–', [$Title])" + } + ] + }, + { + "elmType": "div", + "style": { + "padding-left": "14px", + "margin-top": "4px", + "float": "left", + "display": "flex" + }, + "children": [ + { + "elmType": "div", + "style": { + "font-size": "14px", + "float": "left", + "width": "25px", + "color": "white", + "padding-right": "4px" + }, + "attributes": { + "iconName": "Microphone" + } + }, + { + "elmType": "p", + "style": { + "font-size": "14px", + "float": "left", + "color": "white", + "text-transform": "Uppercase", + "margin": "0px", + "margin-top": "-4px" + }, + "attributes": { + "title": "[$Artist]", + "class": "ms-fontColor-neutralPrimary sp-card-content sp-card-highlightedContent", + "role": "heading", + "aria-level": "3" + }, + "txtContent": "=if ([$Artist] == '', '–', [$Artist])" + } + ] + }, + { + "elmType": "div", + "style": { + "padding-left": "14px", + "margin-top": "10px", + "float": "left", + "display": "flex", + "clear": "both" + }, + "children": [ + { + "elmType": "div", + "style": { + "font-size": "14px", + "float": "left", + "width": "25px", + "color": "#ccc", + "padding-right": "4px" + }, + "attributes": { + "iconName": "D365TalentInsight" + } + }, + { + "elmType": "p", + "style": { + "font-size": "14px", + "float": "left", + "color": "#ccc", + "margin": "0px", + "margin-top": "-4px" + }, + "attributes": { + "title": "[$Author.title]", + "class": "ms-fontColor-neutralPrimary sp-card-content sp-card-highlightedContent", + "role": "heading", + "aria-level": "3" + }, + "txtContent": "=if ([$Author.title] == '', '–', [$Author.title])" + } + ] + }, + { + "elmType": "div", + "attributes": { + "class": "sp-card-displayColumnContainer" + }, + "style": { + "display": "block", + "clear": "both", + "padding-top": "24px", + "width": "100%", + "text-align": "center", + "font-size": "18px" + }, + "children": [ + { + "elmType": "div", + "attributes": { + "class": "ms-fontColor-neutralPrimary sp-card-content " + }, + "children": [ + { + "elmType": "div", + "attributes": { + "class": "ms-fontColor-neutralPrimary sp-card-content " + }, + "children": [ + { + "elmType": "span", + "forEach": "rating in split('1,2,3,4,5',',')", + "children": [ + { + "elmType": "span", + "attributes": { + "class": "=if([$AverageRating] >= [$rating] , 'sp-card-starRating ms-fontColor-yellow', if([$AverageRating] > [$rating] -1 && [$AverageRating] < [$rating], 'sp-card-starRating sp-card-halfFillStar ms-fontColor-yellow ms-fontColor-yellow--hover', 'sp-card-starRating sp-card-emptyFillStar ms-fontColor-yellow--hover'))", + "iconName": "FavoriteStarFill" + }, + "style": { + "padding-right": "4px" + }, + "customRowAction": { + "action": "setValue", + "actionInput": { + "RatingCount": "=if(indexOf([$RatedBy.email], @me) == -1, Number([$RatingCount]) + 1, Number([$RatingCount]))", + "Ratings": "=if(indexOf([$RatedBy.email], @me) == -1, ([$Ratings] + [$rating] + ','), substring([$Ratings], 0,indexOf(split(replaceAll([$RatedBy.email],' ',''), ';'), @me)*2) + [$rating] + substring([$Ratings], indexOf(split(replaceAll([$RatedBy.email],' ',''), ';'), @me)*2+1, indexOf([$Ratings] + '^', '^')))", + "RatedBy": "=if(indexOf([$RatedBy.email], @me) == -1, appendTo([$RatedBy.email], @me),[$RatedBy])", + "AverageRating": "=if(indexOf([$RatedBy.email], @me) == -1, ((Number([$AverageRating])*Number([$RatingCount])) + Number([$rating]))/(Number([$RatingCount]) + 1),((Number([$AverageRating])*Number([$RatingCount]) + Number([$rating]) - Number(substring([$Ratings],indexOf(split(replaceAll([$RatedBy.email],' ',''), ';'), @me)*2,indexOf(split(replaceAll([$RatedBy.email],' ',''), ';'), @me)*2+1)))/Number([$RatingCount])))" + } + } + } + ] + }, + { + "elmType": "span", + "attributes": { + "class": "sp-card-ratingCount ms-fontColor-yellow" + }, + "txtContent": "= ' (' + length([$RatedBy]) + ')'" + } + ] + } + ] + } + ] + } + ] + } + ] + } +} \ No newline at end of file