commit b2900017d2ba745a56a6519979f86d0f267d0602 Author: Docker VM Date: Sat Jul 6 18:27:29 2024 -0400 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57872d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..029451c --- /dev/null +++ b/composer.json @@ -0,0 +1,17 @@ +{ + "name": "dylanbanta/responsive-cards", + "description": "A Laravel component that responsively displays up to 3 cards in a row. The cards size is determined by character count.", + "type": "larave-component", + "license": "MIT", + "autoload": { + "psr-4": { + "Dylanbanta\\ResponsiveCards\\": "src/" + } + }, + "authors": [ + { + "name": "Dylan Banta" + } + ], + "require": {} +} diff --git a/src/ResponsiveCardsServiceProvider.php b/src/ResponsiveCardsServiceProvider.php new file mode 100644 index 0000000..aabc268 --- /dev/null +++ b/src/ResponsiveCardsServiceProvider.php @@ -0,0 +1,30 @@ +loadViewsFrom(__DIR__ . '/resources/views', 'responsive-cards'); + + // Publish assets + $this->publishes([ + __DIR__ . '/resources/css/cards.css' => public_path('vendor/responsive-cards/css/cards.css'), + __DIR__ . '/resources/js/cards.js' => public_path('vendor/responsive-cards/js/cards.js'), + ], 'public'); + + // Publish views + $this->publishes([ + __DIR__ . '/resources/views' => resource_path('views/vendor/responsive-cards'), + ]); + } + + public function register() + { + // + } +} diff --git a/src/composer.json b/src/composer.json new file mode 100644 index 0000000..61a4ea6 --- /dev/null +++ b/src/composer.json @@ -0,0 +1,38 @@ +{ + "name": "dylanbanta/responsive-cards", + "description": "A Laravel package for custom responsive cards", + "type": "library", + "license": "MIT", + "autoload": { + "psr-4": { + "Dylanbanta\\ResponsiveCards\\": "src/" + } + }, + "extra": { + "laravel": { + "providers": [ + "Dylanbanta\\ResponsiveCards\\ResponsiveCardsServiceProvider" + ], + "aliases": { + "ResponsiveCards": "Dylanbanta\\ResponsiveCards\\Facades\\ResponsiveCards" + } + } + }, + "require": { + "php": "^7.3|^8.0", + "illuminate/support": "^8.0|^9.0", + "tailwindcss/tailwindcss": "^2.0", + "tailwindcss/typography": "^0.4.0" + }, + "scripts": { + "post-autoload-dump": [ + "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", + "@php artisan package:discover --ansi" + ], + "post-update-cmd": [ + "@php artisan vendor:publish --tag=responsive-cards-config --ansi" + ] + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/src/resources/css/cards.css b/src/resources/css/cards.css new file mode 100644 index 0000000..1c9fea1 --- /dev/null +++ b/src/resources/css/cards.css @@ -0,0 +1,21 @@ + +.my-card { + padding: 1rem; + background-color: #f0f0f0; + border-radius: 0.5rem; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + transition: transform 0.2s ease-in-out; +} + +.my-card:hover { + transform: translateY(-5px); +} + +.my-card h2 { + margin-bottom: 0.5rem; + color: #333; +} + +.my-card p { + color: #666; +} \ No newline at end of file diff --git a/src/resources/js/cards.js b/src/resources/js/cards.js new file mode 100644 index 0000000..b1f40f1 --- /dev/null +++ b/src/resources/js/cards.js @@ -0,0 +1,86 @@ +document.addEventListener('DOMContentLoaded', function () { + console.log("DOM fully loaded and parsed."); + adjustCardWidths(); +}); + +function adjustCardWidths() { + const container = document.getElementById('cards-container'); + if (!container) { + console.error('cards-container not found'); + return; + } + console.log("cards-container found:", container); + + const cards = Array.from(container.querySelectorAll('.adjust-card')); + console.log("Found cards:", cards); + + let currentRowCards = []; + let currentRowWidth = 0; + const rowMaxWidth = 3; // Assuming a row can hold up to 3 'col-span-1' cards + + cards.forEach((card, index) => { + const textLength = card.textContent.length; + console.log("Card text length:", textLength); + + let colSpan = 1; // Default to smallest size + if (textLength > 300) { + colSpan = 3; + } else if (textLength > 150) { + colSpan = 2; + } + + console.log("Assigning colSpan:", colSpan + " for card:", card); + + // Remove existing col-span classes + card.classList.remove('lg:col-span-1', 'lg:col-span-2', 'lg:col-span-3'); + // Add the new col-span class + card.classList.add(`lg:col-span-${colSpan}`); + + // Check if adding this card would exceed the row max width + if (currentRowWidth + colSpan > rowMaxWidth) { + adjustRow(currentRowCards, currentRowWidth, rowMaxWidth); + currentRowWidth = colSpan; + currentRowCards = [card]; + } else { + currentRowWidth += colSpan; + currentRowCards.push(card); + } + + // Adjust the last row if it's the last card + if (index === cards.length - 1) { + adjustRow(currentRowCards, currentRowWidth, rowMaxWidth); + } + }); +} + +function adjustRow(rowCards, currentRowWidth, rowMaxWidth) { + if (rowCards.length === 1) { + // Single card in the row + const card = rowCards[0]; + card.classList.remove('lg:col-span-1', 'lg:col-span-2', 'lg:col-span-3'); + card.classList.add(`lg:col-span-${rowMaxWidth}`); + } else if (rowCards.length === 2) { + // Two cards in the row + const firstCard = rowCards[0]; + const secondCard = rowCards[1]; + const firstColSpan = firstCard.classList.contains('lg:col-span-2') ? 2 : 1; + const secondColSpan = secondCard.classList.contains('lg:col-span-2') ? 2 : 1; + if (currentRowWidth > rowMaxWidth) { + // Push second card to the next row and expand the first card + secondCard.classList.remove(`lg:col-span-${secondColSpan}`); + secondCard.classList.add('lg:col-span-1'); // reset to span 1 for next row processing + firstCard.classList.remove(`lg:col-span-${firstColSpan}`); + firstCard.classList.add(`lg:col-span-${rowMaxWidth}`); + } else { + // Expand the second card to fill the row + secondCard.classList.remove(`lg:col-span-${secondColSpan}`); + secondCard.classList.add(`lg:col-span-${rowMaxWidth - firstColSpan}`); + } + } else if (rowCards.length === 3) { + // Three cards in the row, expand the last card to fill the row + const lastCard = rowCards[2]; + const lastColSpan = lastCard.classList.contains('lg:col-span-2') ? 2 : 1; + lastCard.classList.remove(`lg:col-span-${lastColSpan}`); + lastCard.classList.add(`lg:col-span-${rowMaxWidth - (currentRowWidth - lastColSpan)}`); + } +} diff --git a/src/resources/views/card-templates/default.blade.php b/src/resources/views/card-templates/default.blade.php new file mode 100644 index 0000000..0e852f8 --- /dev/null +++ b/src/resources/views/card-templates/default.blade.php @@ -0,0 +1,4 @@ +
+

{{ $entry['title'] }}

+

{{ $entry['message'] }}

+
\ No newline at end of file diff --git a/src/resources/views/card-test.blade.php b/src/resources/views/card-test.blade.php new file mode 100755 index 0000000..35197cd --- /dev/null +++ b/src/resources/views/card-test.blade.php @@ -0,0 +1,25 @@ +@extends('layouts.card-layout') + +@section('content') + @php + $data = [ + ['title' => 'Card 1', 'message' => str_repeat('Short content. ', 1)], + ['title' => 'Card 2', 'message' => str_repeat('Short content. ', 1)], + ['title' => 'Card 3', 'message' => str_repeat('Short content. ', 1)], + ['title' => 'Card 4', 'message' => str_repeat('Short content. ', 1)], + ['title' => 'Card 5', 'message' => str_repeat('Medium content. ', 10)], + ['title' => 'Card 6', 'message' => str_repeat('Medium content. ', 10)], + ['title' => 'Card 7', 'message' => str_repeat('Short content. ', 1)], + ['title' => 'Card 8', 'message' => str_repeat('Short content. (Forced long) ', 1)], + ['title' => 'Card 9', 'message' => str_repeat('Long content. ', 25)], + ['title' => 'Card 10', 'message' => str_repeat('Short content. ', 1)], + ['title' => 'Card 11', 'message' => str_repeat('Short content. (Forced medium) ', 1)], + ['title' => 'Card 12', 'message' => str_repeat('Long content. ', 25)], + ['title' => 'Card 13', 'message' => str_repeat('Medium content. (Forced long) ', 10)], + ['title' => 'Card 14', 'message' => str_repeat('Medium content. (Forced long) ', 10)], + ]; + @endphp + + +@endsection + diff --git a/src/resources/views/components/cards.blade.php b/src/resources/views/components/cards.blade.php new file mode 100755 index 0000000..e1554f4 --- /dev/null +++ b/src/resources/views/components/cards.blade.php @@ -0,0 +1,12 @@ +@props(['cardsData', 'cardTemplate']) + +
+
+

+
+ @foreach ($cardsData as $entry) + @include($cardTemplate, ['entry' => $entry]) + @endforeach +
+
+
\ No newline at end of file diff --git a/src/resources/views/layouts/card-layout.blade.php b/src/resources/views/layouts/card-layout.blade.php new file mode 100644 index 0000000..5667fba --- /dev/null +++ b/src/resources/views/layouts/card-layout.blade.php @@ -0,0 +1,22 @@ + + + + + + @yield('title', 'Card Test') + @vite(['resources/css/app.css', 'resources/css/cards.css', 'resources/js/cards.js']) + @livewireStyles + + + + + + + + +
+ @yield('content') +
+ @livewireScripts + + diff --git a/src/vite.config.js b/src/vite.config.js new file mode 100644 index 0000000..bfdf71e --- /dev/null +++ b/src/vite.config.js @@ -0,0 +1,14 @@ +import { defineConfig } from 'vite'; +import laravel from 'laravel-vite-plugin'; + +export default defineConfig({ + plugins: [ + laravel({ + input: [ + 'vendor/dylanbanta/responsive-cards/src/resources/css/cards.css', + 'vendor/dylanbanta/responsive-cards/src/resources/js/cards.js' + ], + refresh: true, + }), + ], +}); diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..11d55b8 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,13 @@ +module.exports = { + content: [ + './vendor/dylanbanta/responsive-cards/src/resources/views/**/*.blade.php', + './vendor/dylanbanta/responsive-cards/src/resources/js/**/*.js', + './vendor/dylanbanta/responsive-cards/src/resources/css/**/*.css', + ], + theme: { + extend: {}, + }, + plugins: [ + require('@tailwindcss/typography'), + ], +};