Skip to content

Commit b27639e

Browse files
Add More Slide Masters (#17)
Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: ErikBernskiold <1166728+ErikBernskiold@users.noreply.github.com>
1 parent 6b2b537 commit b27639e

File tree

13 files changed

+868
-13
lines changed

13 files changed

+868
-13
lines changed

src/LaravelPptServiceProvider.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,27 @@
66
use BernskioldMedia\LaravelPpt\Commands\CreateNewSlideDeckCommand;
77
use BernskioldMedia\LaravelPpt\Commands\GenerateSamplePresentationCommand;
88
use BernskioldMedia\LaravelPpt\Registries\SlideMasters;
9+
use BernskioldMedia\LaravelPpt\SlideMasters\Agenda;
910
use BernskioldMedia\LaravelPpt\SlideMasters\Blank;
1011
use BernskioldMedia\LaravelPpt\SlideMasters\BlankWithTitle;
1112
use BernskioldMedia\LaravelPpt\SlideMasters\BlankWithTitleSubtitle;
1213
use BernskioldMedia\LaravelPpt\SlideMasters\BulletPoints;
1314
use BernskioldMedia\LaravelPpt\SlideMasters\Chart;
1415
use BernskioldMedia\LaravelPpt\SlideMasters\ChartSquare;
1516
use BernskioldMedia\LaravelPpt\SlideMasters\ChartText;
17+
use BernskioldMedia\LaravelPpt\SlideMasters\ChartTextTitle;
1618
use BernskioldMedia\LaravelPpt\SlideMasters\ChartTitle;
1719
use BernskioldMedia\LaravelPpt\SlideMasters\ChartTitles;
1820
use BernskioldMedia\LaravelPpt\SlideMasters\FourUp;
21+
use BernskioldMedia\LaravelPpt\SlideMasters\Quote;
1922
use BernskioldMedia\LaravelPpt\SlideMasters\SixUp;
23+
use BernskioldMedia\LaravelPpt\SlideMasters\Table;
2024
use BernskioldMedia\LaravelPpt\SlideMasters\Text;
25+
use BernskioldMedia\LaravelPpt\SlideMasters\ThreeColumn;
26+
use BernskioldMedia\LaravelPpt\SlideMasters\ThreeUp;
2127
use BernskioldMedia\LaravelPpt\SlideMasters\Title;
2228
use BernskioldMedia\LaravelPpt\SlideMasters\TitleSubtitle;
29+
use BernskioldMedia\LaravelPpt\SlideMasters\TwoColumn;
2330
use BernskioldMedia\LaravelPpt\SlideMasters\TwoUp;
2431
use Spatie\LaravelPackageTools\Package;
2532
use Spatie\LaravelPackageTools\PackageServiceProvider;
@@ -42,20 +49,27 @@ public function packageBooted(): void
4249
{
4350
// Register package's built-in slide masters
4451
SlideMasters::register([
52+
Agenda::class,
4553
Blank::class,
4654
BlankWithTitle::class,
4755
BlankWithTitleSubtitle::class,
4856
BulletPoints::class,
4957
Chart::class,
5058
ChartSquare::class,
59+
ChartTextTitle::class,
5160
ChartText::class,
5261
ChartTitle::class,
5362
ChartTitles::class,
5463
FourUp::class,
64+
Quote::class,
5565
SixUp::class,
66+
Table::class,
5667
Text::class,
68+
ThreeColumn::class,
69+
ThreeUp::class,
5770
Title::class,
5871
TitleSubtitle::class,
72+
TwoColumn::class,
5973
TwoUp::class,
6074
]);
6175
}

src/SlideMasters/Agenda.php

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
namespace BernskioldMedia\LaravelPpt\SlideMasters;
4+
5+
use BernskioldMedia\LaravelPpt\Components\TextBox;
6+
use BernskioldMedia\LaravelPpt\Concerns\Slides\WithSlideTitle;
7+
use BernskioldMedia\LaravelPpt\Contracts\DynamicallyCreatable;
8+
use BernskioldMedia\LaravelPpt\Presentation\BaseSlide;
9+
use PhpOffice\PhpPresentation\Style\Bullet;
10+
use PhpOffice\PhpPresentation\Style\Color;
11+
12+
/**
13+
* @method static static make(string $title = '', array $items = [])
14+
*/
15+
class Agenda extends BaseSlide implements DynamicallyCreatable
16+
{
17+
use WithSlideTitle;
18+
19+
public function __construct(
20+
string $title = '',
21+
protected array $items = [],
22+
) {
23+
$this->slideTitle = $title;
24+
}
25+
26+
public function item(string $text): self
27+
{
28+
$this->items[] = $text;
29+
30+
return $this;
31+
}
32+
33+
protected function render(): void
34+
{
35+
// Render the title rotated 90 degrees on the left side
36+
if (! empty($this->slideTitle)) {
37+
TextBox::make($this, $this->slideTitle)
38+
->bold()
39+
->rotate(-90)
40+
->width($this->presentation->height - 2 * $this->verticalPadding)
41+
->height(200)
42+
->x(-230)
43+
->centerVertically()
44+
->size(100)
45+
->uppercase()
46+
->render();
47+
}
48+
49+
if (empty($this->items)) {
50+
return;
51+
}
52+
53+
// Content area starts from the left with padding
54+
$yOffset = 75;
55+
$xOffset = $this->horizontalPadding + 150; // Extra padding for rotated title
56+
$contentWidth = $this->presentation->width - $xOffset - $this->horizontalPadding;
57+
58+
$box = null;
59+
60+
foreach ($this->items as $item) {
61+
if (! $box) {
62+
$box = TextBox::make($this, $item)
63+
->paragraphStyle('tocPoint')
64+
->size(24)
65+
->height($this->presentation->height - $yOffset - 75)
66+
->width($contentWidth)
67+
->position($xOffset, $yOffset)
68+
->alignLeft()
69+
->alignTop()
70+
->render()
71+
->shape;
72+
} else {
73+
$box->createParagraph()
74+
->createTextRun($item)
75+
->getFont()
76+
->setSize(24)
77+
->setColor(new Color($this->textColor))
78+
->setBold(false)
79+
->setName($this->presentation->branding->baseFont())
80+
->setCharacterSpacing(0);
81+
}
82+
83+
$box->getActiveParagraph()
84+
->getBulletStyle()
85+
->setBulletType(Bullet::TYPE_NUMERIC)
86+
->setBulletColor(new Color($this->textColor));
87+
88+
$box->getActiveParagraph()
89+
->setSpacingAfter(25)
90+
->getAlignment()
91+
->setIndent(-40)
92+
->setMarginLeft(60);
93+
}
94+
}
95+
96+
public static function dataSchema(): array
97+
{
98+
return [
99+
'type' => 'object',
100+
'properties' => [
101+
'title' => [
102+
'type' => 'string',
103+
'description' => 'The slide title (e.g., "Agenda" or "Table of Contents")',
104+
],
105+
'items' => [
106+
'type' => 'array',
107+
'description' => 'Array of agenda items',
108+
'items' => [
109+
'type' => 'string',
110+
],
111+
],
112+
],
113+
'required' => ['title', 'items'],
114+
];
115+
}
116+
117+
public static function description(): string
118+
{
119+
return 'A slide with a title and numbered agenda/table of contents items';
120+
}
121+
122+
public static function exampleData(): array
123+
{
124+
return [
125+
'title' => 'Agenda',
126+
'items' => [
127+
'Introduction and Welcome',
128+
'Company Overview',
129+
'Product Demonstration',
130+
'Q&A Session',
131+
'Next Steps',
132+
],
133+
];
134+
}
135+
}

src/SlideMasters/BulletPoints.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ protected function render(): void
3434
{
3535
$titleBox = $this->renderTitle();
3636

37-
$yOffset = $titleBox->height + 75;
37+
$yOffset = $titleBox->height + 100;
3838
$box = null;
3939

4040
foreach ($this->bulletPoints as $bulletPoint) {
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?php
2+
3+
namespace BernskioldMedia\LaravelPpt\SlideMasters;
4+
5+
use BernskioldMedia\LaravelPpt\Components\ChartComponent;
6+
use BernskioldMedia\LaravelPpt\Components\ChartShape;
7+
use BernskioldMedia\LaravelPpt\Components\TextBox;
8+
use BernskioldMedia\LaravelPpt\Concerns\Slides\WithSlideTitle;
9+
use BernskioldMedia\LaravelPpt\Contracts\DynamicallyCreatable;
10+
use BernskioldMedia\LaravelPpt\Presentation\BaseSlide;
11+
12+
/**
13+
* @method static static make(string $title = '', string $text = '', ChartComponent $chart = null)
14+
*/
15+
class ChartTextTitle extends BaseSlide implements DynamicallyCreatable
16+
{
17+
use WithSlideTitle;
18+
19+
public function __construct(
20+
string $title = '',
21+
protected string $text = '',
22+
protected ?ChartComponent $chart = null,
23+
) {
24+
$this->slideTitle = $title;
25+
}
26+
27+
protected function render(): void
28+
{
29+
// Render title and calculate offset
30+
if (! empty($this->slideTitle)) {
31+
$titleBox = $this->renderTitle();
32+
$yOffset = $titleBox->height + 75;
33+
} else {
34+
$yOffset = $this->verticalPadding;
35+
}
36+
37+
// Calculate available dimensions
38+
$availableWidth = $this->presentation->width - (2 * $this->horizontalPadding);
39+
$availableHeight = $this->presentation->height - $yOffset - $this->verticalPadding;
40+
41+
// Calculate text and chart widths (approximately 40/60 split with gap)
42+
$gap = 40;
43+
$textWidth = (int) ($availableWidth * 0.4);
44+
$chartWidth = $availableWidth - $textWidth - $gap;
45+
$chartXPosition = $this->horizontalPadding + $textWidth + $gap;
46+
47+
// Render chart on the right
48+
if ($this->chart) {
49+
ChartShape::make($this, $this->chart->slide($this)->get())
50+
->height($availableHeight)
51+
->width($chartWidth)
52+
->backgroundColor($this->chartBackgroundColor)
53+
->position($chartXPosition, $yOffset)
54+
->render();
55+
}
56+
57+
// Render text on the left
58+
if (! empty($this->text)) {
59+
TextBox::make($this, $this->text)
60+
->paragraphStyle('body')
61+
->alignLeft()
62+
->alignMiddle()
63+
->position($this->horizontalPadding, $yOffset)
64+
->height($availableHeight)
65+
->width($textWidth)
66+
->render();
67+
}
68+
}
69+
70+
public static function dataSchema(): array
71+
{
72+
return [
73+
'type' => 'object',
74+
'properties' => [
75+
'title' => [
76+
'type' => 'string',
77+
'description' => 'The slide title',
78+
],
79+
'text' => [
80+
'type' => 'string',
81+
'description' => 'The text content for the left side',
82+
],
83+
'chartType' => [
84+
'type' => 'string',
85+
'enum' => ['Bar', 'StackedBar', 'PercentageStackedBar', 'Column', 'StackedColumn', 'PercentageStackedColumn', 'Line', 'Radar', 'Scatter'],
86+
'description' => 'Type of chart to render',
87+
],
88+
'chartData' => [
89+
'type' => 'object',
90+
'description' => 'Chart data with series',
91+
'properties' => [
92+
'series' => [
93+
'type' => 'array',
94+
'items' => [
95+
'type' => 'object',
96+
'properties' => [
97+
'label' => ['type' => 'string'],
98+
'data' => ['type' => 'object'],
99+
],
100+
'required' => ['label', 'data'],
101+
],
102+
],
103+
],
104+
'required' => ['series'],
105+
],
106+
],
107+
'required' => ['title', 'text', 'chartType', 'chartData'],
108+
];
109+
}
110+
111+
public static function description(): string
112+
{
113+
return 'A slide with a title at the top, text on the left, and a chart on the right';
114+
}
115+
116+
public static function exampleData(): array
117+
{
118+
return [
119+
'title' => 'This is a chart that we want to describe',
120+
'text' => 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec odio. Quisque volutpat mattis eros. Nullam malesuada erat ut turpis. Suspendisse urna nibh, viverra non, semper suscipit, posuere a, pede.',
121+
'chartType' => 'Column',
122+
'chartData' => [
123+
'series' => [
124+
[
125+
'label' => 'Series 1',
126+
'data' => ['Category 1' => 4, 'Category 2' => 2, 'Category 3' => 3, 'Category 4' => 5],
127+
],
128+
[
129+
'label' => 'Series 2',
130+
'data' => ['Category 1' => 2, 'Category 2' => 5, 'Category 3' => 2, 'Category 4' => 3],
131+
],
132+
[
133+
'label' => 'Series 3',
134+
'data' => ['Category 1' => 2, 'Category 2' => 2, 'Category 3' => 3, 'Category 4' => 5],
135+
],
136+
],
137+
],
138+
];
139+
}
140+
}

0 commit comments

Comments
 (0)