diff --git a/src/presentation/components/Scripts/View/Cards/CardExpansionPanel.vue b/src/presentation/components/Scripts/View/Cards/CardExpansionPanel.vue
new file mode 100644
index 00000000..0eca3dc7
--- /dev/null
+++ b/src/presentation/components/Scripts/View/Cards/CardExpansionPanel.vue
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
diff --git a/src/presentation/components/Scripts/View/Cards/CardExpansionPanelArrow.vue b/src/presentation/components/Scripts/View/Cards/CardExpansionPanelArrow.vue
new file mode 100644
index 00000000..1e4d89b3
--- /dev/null
+++ b/src/presentation/components/Scripts/View/Cards/CardExpansionPanelArrow.vue
@@ -0,0 +1,24 @@
+
+
+
+
+
diff --git a/src/presentation/components/Scripts/View/Cards/CardList.vue b/src/presentation/components/Scripts/View/Cards/CardList.vue
index faeefe25..c3bce298 100644
--- a/src/presentation/components/Scripts/View/Cards/CardList.vue
+++ b/src/presentation/components/Scripts/View/Cards/CardList.vue
@@ -19,6 +19,7 @@
v-for="categoryId of categoryIds"
:key="categoryId"
class="card"
+ :total-cards-per-row="cardsPerRow"
:class="{
'small-screen': width <= 500,
'medium-screen': width > 500 && width < 750,
@@ -62,6 +63,19 @@ export default defineComponent({
);
const activeCategoryId = ref(undefined);
+ const cardsPerRow = computed(() => {
+ if (width.value === undefined) {
+ throw new Error('Unknown width, total cards should not be calculated');
+ }
+ if (width.value <= 500) {
+ return 1;
+ }
+ if (width.value < 750) {
+ return 2;
+ }
+ return 3;
+ });
+
function onSelected(categoryId: number, isExpanded: boolean) {
activeCategoryId.value = isExpanded ? categoryId : undefined;
}
@@ -108,6 +122,7 @@ export default defineComponent({
width,
categoryIds,
activeCategoryId,
+ cardsPerRow,
onSelected,
};
},
diff --git a/src/presentation/components/Scripts/View/Cards/CardListItem.vue b/src/presentation/components/Scripts/View/Cards/CardListItem.vue
index f6a99c68..e75c0983 100644
--- a/src/presentation/components/Scripts/View/Cards/CardListItem.vue
+++ b/src/presentation/components/Scripts/View/Cards/CardListItem.vue
@@ -29,20 +29,15 @@
:category-id="categoryId"
/>
-
+
+
+
+
@@ -51,24 +46,30 @@ import {
defineComponent, computed, shallowRef,
} from 'vue';
import AppIcon from '@/presentation/components/Shared/Icon/AppIcon.vue';
-import FlatButton from '@/presentation/components/Shared/FlatButton.vue';
+import ExpandCollapseTransition from '@/presentation/components/Shared/ExpandCollapse/ExpandCollapseTransition.vue';
import { injectKey } from '@/presentation/injectionSymbols';
-import ScriptsTree from '@/presentation/components/Scripts/View/Tree/ScriptsTree.vue';
import { sleep } from '@/infrastructure/Threading/AsyncSleep';
import CardSelectionIndicator from './CardSelectionIndicator.vue';
+import CardExpansionPanel from './CardExpansionPanel.vue';
+import CardExpansionPanelArrow from './CardExpansionPanelArrow.vue';
export default defineComponent({
components: {
- ScriptsTree,
AppIcon,
CardSelectionIndicator,
- FlatButton,
+ CardExpansionPanel,
+ ExpandCollapseTransition,
+ CardExpansionPanelArrow,
},
props: {
categoryId: {
type: Number,
required: true,
},
+ totalCardsPerRow: {
+ type: Number,
+ required: true,
+ },
activeCategoryId: {
type: Number,
default: undefined,
@@ -94,6 +95,14 @@ export default defineComponent({
},
});
+ const cardWidth = computed(() => {
+ const totalTimesGapIsUsedInRow = props.totalCardsPerRow - 1;
+ const totalGapWidthInRow = `calc(${totalTimesGapIsUsedInRow} * 15px)`; // TODO: 15px is hardcoded, $card-gap variable should be used
+ const availableRowWidthForCards = `calc(100% - (${totalGapWidthInRow}))`;
+ const availableWidthPerCard = `calc((${availableRowWidthForCards}) / ${totalTimesGapIsUsedInRow})`;
+ return availableWidthPerCard;
+ });
+
const cardElement = shallowRef();
const cardTitle = computed(() => {
@@ -118,6 +127,7 @@ export default defineComponent({
cardTitle,
isExpanded,
cardElement,
+ cardWidth,
collapse,
};
},
@@ -131,11 +141,22 @@ export default defineComponent({
$card-inner-padding : 30px;
$arrow-size : 15px;
$expanded-margin-top : 30px;
-$card-horizontal-gap : $card-gap;
-.card {
- transition: all 0.2s ease-in-out;
+.expansion__arrow {
+ position: relative;
+ .expansion__arrow__inner {
+ position: absolute;
+ left: calc(50% - $arrow-size * 1.5);
+ top: calc(1.5 * $arrow-size);
+ border: solid $color-primary-darker;
+ border-width: 0 $arrow-size $arrow-size 0;
+ padding: $arrow-size;
+ transform: rotate(-135deg);
+ }
+}
+.card {
+ width: v-bind(cardWidth);
&__inner {
padding-top: $card-inner-padding;
padding-right: $card-inner-padding;
@@ -160,9 +181,6 @@ $card-horizontal-gap : $card-gap;
color: $color-on-secondary;
transform: scale(1.05);
}
- &:after {
- transition: all 0.3s ease-in-out;
- }
.card__inner__title {
display: flex;
flex-direction: column;
@@ -184,73 +202,12 @@ $card-horizontal-gap : $card-gap;
font-size: $font-size-absolute-normal;
}
}
- .card__expander {
- transition: all 0.2s ease-in-out;
- position: relative;
- background-color: $color-primary-darker;
- color: $color-on-primary;
-
- display: flex;
- align-items: center;
- flex-direction: column;
-
- .card__expander__content {
- display: flex;
- justify-content: center;
- word-break: break-word;
- max-width: 100%; // Prevents horizontal expansion of inner content (e.g., when a code block is shown)
- width: 100%; // Expands the container to fill available horizontal space, enabling alignment of child items.
- }
-
- .card__expander__close-button {
- font-size: $font-size-absolute-large;
- align-self: flex-end;
- margin-right: 0.25em;
- @include clickable;
- color: $color-primary-light;
- @include hover-or-touch {
- color: $color-primary;
- }
- }
- }
-
- &.is-collapsed {
- .card__inner {
- &:after {
- content: "";
- opacity: 0;
- }
- }
-
- .card__expander {
- max-height: 0;
- min-height: 0;
- overflow: hidden;
- opacity: 0;
- }
- }
&.is-expanded {
.card__inner {
height: auto;
background-color: $color-secondary;
color: $color-on-secondary;
- &:after { // arrow
- content: "";
- display: block;
- position: absolute;
- bottom: calc(-1 * #{$expanded-margin-top});
- left: calc(50% - #{$arrow-size});
- border-left: #{$arrow-size} solid transparent;
- border-right: #{$arrow-size} solid transparent;
- border-bottom: #{$arrow-size} solid $color-primary-darker;
- }
- }
-
- .card__expander {
- min-height: 200px;
- margin-top: $expanded-margin-top;
- opacity: 1;
}
@include hover-or-touch {
@@ -277,26 +234,26 @@ $card-horizontal-gap : $card-gap;
}
}
@mixin adaptive-card($cards-in-row) {
- &.card {
+ .card {
$total-times-gap-is-used-in-row: $cards-in-row - 1;
$total-gap-width-in-row: $total-times-gap-is-used-in-row * $card-horizontal-gap;
$available-row-width-for-cards: calc(100% - #{$total-gap-width-in-row});
$available-width-per-card: calc(#{$available-row-width-for-cards} / #{$cards-in-row});
width:$available-width-per-card;
- .card__expander {
- $all-cards-width: 100% * $cards-in-row;
- $additional-padding-width: $card-horizontal-gap * ($cards-in-row - 1);
- width: calc(#{$all-cards-width} + #{$additional-padding-width});
- }
- @for $nth-card from 2 through $cards-in-row { // From second card to rest
- &:nth-of-type(#{$cards-in-row}n+#{$nth-card}) {
- .card__expander {
- $card-left: -100% * ($nth-card - 1);
- $additional-space: $card-horizontal-gap * ($nth-card - 1);
- margin-left: calc(#{$card-left} - #{$additional-space});
- }
- }
- }
+ // .card__expander {
+ // $all-cards-width: 100% * $cards-in-row;
+ // $additional-padding-width: $card-horizontal-gap * ($cards-in-row - 1);
+ // width: calc(#{$all-cards-width} + #{$additional-padding-width});
+ // }
+ // @for $nth-card from 2 through $cards-in-row { // From second card to rest
+ // &:nth-of-type(#{$cards-in-row}n+#{$nth-card}) {
+ // .card__expander {
+ // $card-left: -100% * ($nth-card - 1);
+ // $additional-space: $card-horizontal-gap * ($nth-card - 1);
+ // margin-left: calc(#{$card-left} - #{$additional-space});
+ // }
+ // }
+ // }
// Ensure new line after last row
$card-after-last: $cards-in-row + 1;
&:nth-of-type(#{$cards-in-row}n+#{$card-after-last}) {
@@ -304,8 +261,4 @@ $card-horizontal-gap : $card-gap;
}
}
}
-
-.big-screen { @include adaptive-card(3); }
-.medium-screen { @include adaptive-card(2); }
-.small-screen { @include adaptive-card(1); }
diff --git a/src/presentation/components/Scripts/View/Cards/CardRow.vue b/src/presentation/components/Scripts/View/Cards/CardRow.vue
new file mode 100644
index 00000000..e69de29b