Skip to content

Commit a2865a6

Browse files
authored
[FEATURE] Introduce composer text role (#604)
Making it possible to link to packagist and display more information about the package. Warn if package not found. ![image](https://github.com/TYPO3-Documentation/render-guides/assets/48202465/40f47ec2-678f-403e-b461-b080513138aa) ![image](https://github.com/TYPO3-Documentation/render-guides/assets/48202465/02dbbab6-0986-4e87-a889-dd70e8bd29b5) ![image](https://github.com/TYPO3-Documentation/render-guides/assets/48202465/b82524f0-a596-4edc-b0b4-9e3a3cf8d6f9) If JavaScript is not active they are simple links to packagist from where users can get all other information.
1 parent e8dadfa commit a2865a6

File tree

55 files changed

+1197
-24
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+1197
-24
lines changed
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
(() => {
2+
const SELECTOR_MODAL = '#generalModal';
3+
const SELECTOR_COPY_BUTTON = '.copy-button';
4+
const SELECTOR_ALERT_SUCCESS = '#general-alert-success';
5+
6+
function handleCopyButtons(generalModal) {
7+
const alertSuccessDiv = generalModal.querySelector(SELECTOR_ALERT_SUCCESS);
8+
const copyButtons = generalModal.querySelectorAll(SELECTOR_COPY_BUTTON);
9+
if (!navigator.clipboard || !navigator.clipboard.writeText) {
10+
console.info('"navigator.clipboard.writeText" is not available. Update to a modern browser to copy code to the system\'s clipboard');
11+
copyButtons.forEach(button => button.disabled = true);
12+
} else {
13+
copyButtons.forEach(button => {
14+
button.addEventListener('click', function() {
15+
const targetId = this.getAttribute('data-target');
16+
const targetElement = generalModal.querySelector(`#${targetId}`);
17+
if (!targetElement) {
18+
console.warn('Cannot copy link as no input is available!');
19+
return;
20+
}
21+
alertSuccessDiv.classList.remove('d-none');
22+
alertSuccessDiv.innerHTML = `Snippet <code>${htmlEscape(targetElement.value)}</code> was copied to your clipboard.`;
23+
navigator.clipboard.writeText(targetElement.value);
24+
});
25+
});
26+
}
27+
}
28+
29+
function htmlEscape(text) {
30+
const div = document.createElement('div');
31+
div.textContent = text;
32+
return div.innerHTML;
33+
}
34+
35+
const generalModal = document.querySelector(SELECTOR_MODAL);
36+
generalModal.addEventListener('show.bs.modal', function (event) {
37+
const item = event.relatedTarget;
38+
if (!item.dataset.composername) {
39+
return;
40+
}
41+
const generalModalLabel = generalModal.querySelector('#generalModalLabel');
42+
const content = generalModal.querySelector('#generalModalContent');
43+
generalModalLabel.innerText = item.dataset.composername;
44+
handleCopyButtons(generalModal);
45+
content.innerHTML = `
46+
<p>${item.dataset.description}</p>
47+
<p>Install the package using Composer: </p>
48+
<div class="input-group">
49+
<textarea class="form-control code" id="composer-command" readonly>${item.dataset.composercommand}</textarea>
50+
<button type="button" class="btn btn-outline-secondary copy-button" data-target="composer-command"><i class="far fa-clone"></i></button>
51+
</div>
52+
`;
53+
const generalModalCustomButtons = generalModal.querySelector('#generalModalCustomButtons');
54+
55+
// Add more buttons to the modal footer
56+
generalModalCustomButtons.innerHTML = `
57+
<a href="${item.href}" class="btn btn-default"><i class="fa-solid fa-arrow-right"></i>&nbsp;Packagist</a>
58+
`;
59+
if(item.dataset.documentation) {
60+
const url = new URL(item.dataset.documentation);
61+
const isExternal = url.hostname !== 'docs.typo3.org';
62+
generalModalCustomButtons.innerHTML += `
63+
<a href="${item.dataset.documentation}" class="btn btn-default">
64+
<i class="fa-solid fa-book"></i>&nbsp;Documentation ${isExternal ? '(external)' : ''}
65+
</a>
66+
`;
67+
}
68+
if(item.dataset.homepage) {
69+
const url = new URL(item.dataset.homepage);
70+
const isTER = url.hostname === 'extensions.typo3.org';
71+
if (isTER) {
72+
generalModalCustomButtons.innerHTML += `
73+
<a href="${item.dataset.homepage}" class="btn btn-default">
74+
<i class="fa-brands fa-typo3"></i>&nbsp;TER
75+
</a>
76+
`;
77+
}
78+
}
79+
handleCopyButtons(generalModal);
80+
});
81+
})();
Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11

2-
/**
3-
* Keyboard Shortcuts, text role :kbd:
4-
*/
5-
kbd {
6-
@include inline-box;
7-
}
2+
article {
3+
/**
4+
* Keyboard Shortcuts, text role :kbd:
5+
*/
6+
kbd {
7+
@include inline-box;
8+
}
9+
10+
/**
11+
* GUI-Label
12+
*/
13+
.guilabel {
14+
font-size: 75%;
15+
@include inline-box($info);
16+
}
817

9-
/**
10-
* GUI-Label
11-
*/
12-
.guilabel {
13-
font-size: 75%;
14-
@include inline-box($info);
18+
a.composer-link {
19+
text-decoration: underline dotted;
20+
}
1521
}

packages/typo3-docs-theme/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
}
1111
},
1212
"require": {
13+
"ext-curl": "*",
1314
"brotkrueml/twig-codehighlight": "^0.1.1",
1415
"phpdocumentor/guides-graphs": "^1.0",
1516
"phpdocumentor/guides-theme-bootstrap": "^1.0",

packages/typo3-docs-theme/resources/config/typo3-docs-theme.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@
2828
use T3Docs\Typo3DocsTheme\EventListeners\IgnoreLocalizationsFolders;
2929
use T3Docs\Typo3DocsTheme\EventListeners\TestingModeActivator;
3030
use T3Docs\Typo3DocsTheme\Inventory\Typo3InventoryRepository;
31+
use T3Docs\Typo3DocsTheme\Packagist\PackagistService;
3132
use T3Docs\Typo3DocsTheme\Inventory\Typo3VersionService;
3233
use T3Docs\Typo3DocsTheme\Parser\ExtendedInterlinkParser;
3334
use T3Docs\Typo3DocsTheme\Parser\Productions\FieldList\EditOnGitHubFieldListItemRule;
3435
use T3Docs\Typo3DocsTheme\Parser\Productions\FieldList\TemplateFieldListItemRule;
3536
use T3Docs\Typo3DocsTheme\Renderer\DecoratingPlantumlRenderer;
37+
use T3Docs\Typo3DocsTheme\TextRoles\ComposerTextRole;
3638
use T3Docs\Typo3DocsTheme\TextRoles\FluidTextTextRole;
3739
use T3Docs\Typo3DocsTheme\TextRoles\HtmlTextTextRole;
3840
use T3Docs\Typo3DocsTheme\TextRoles\InputTextTextRole;
@@ -74,6 +76,8 @@
7476
->set(InventoryRepository::class, Typo3InventoryRepository::class)
7577
->arg('$inventoryConfigs', param('phpdoc.guides.inventories'))
7678
->set(InterlinkParser::class, ExtendedInterlinkParser::class)
79+
->set(ComposerTextRole::class)
80+
->tag('phpdoc.guides.parser.rst.text_role')
7781
->set(FluidTextTextRole::class)
7882
->tag('phpdoc.guides.parser.rst.text_role')
7983
->set(HtmlTextTextRole::class)
@@ -134,6 +138,7 @@
134138
->tag('twig.extension')
135139
->autowire()
136140

141+
->set(PackagistService::class)
137142
->set(Typo3VersionService::class)
138143

139144
// Register Event Listeners

packages/typo3-docs-theme/resources/public/css/theme.css

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24698,10 +24698,15 @@ article *:hover > a.headerlink:after, article *:hover > a.permalink:after, artic
2469824698
margin: 0;
2469924699
}
2470024700

24701-
/**
24702-
* Keyboard Shortcuts, text role :kbd:
24703-
*/
24704-
kbd {
24701+
article {
24702+
/**
24703+
* Keyboard Shortcuts, text role :kbd:
24704+
*/
24705+
/**
24706+
* GUI-Label
24707+
*/
24708+
}
24709+
article kbd {
2470524710
display: inline-block;
2470624711
padding: 0.25em 0.5em;
2470724712
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), inset 0 0 0 2px #ffffff;
@@ -24710,11 +24715,7 @@ kbd {
2471024715
border-radius: 0.375rem;
2471124716
border: 1px solid #f2f2f2;
2471224717
}
24713-
24714-
/**
24715-
* GUI-Label
24716-
*/
24717-
.guilabel {
24718+
article .guilabel {
2471824719
font-size: 75%;
2471924720
display: inline-block;
2472024721
padding: 0.25em 0.5em;
@@ -24724,6 +24725,9 @@ kbd {
2472424725
border-radius: 0.375rem;
2472524726
border: 1px solid #319fc0;
2472624727
}
24728+
article a.composer-link {
24729+
text-decoration: underline dotted;
24730+
}
2472724731

2472824732
/**
2472924733
* Bignums
@@ -24922,11 +24926,11 @@ ul[class*=horizbuttons-][class*=-attention-] > li:hover, ul[class*=horizbuttons-
2492224926
background-color: #f2f2f2;
2492324927
outline: 2px solid #333333;
2492424928
}
24925-
ul[class*=horizbuttons-][class*=-note-] > li, ul[class*=horizbuttons-][class*=-tip-] > li, ul[class*=horizbuttons-][class*=-default-] > li {
24929+
ul[class*=horizbuttons-][class*=-note-] > li, ul[class*=horizbuttons-][class*=-tip-] > li, ul[class*=horizbuttons-][class*=-default-] > li, ul[class*=horizbuttons-][class*=-light-] > li {
2492624930
color: #000000;
2492724931
background-color: #f2f2f2;
2492824932
}
24929-
ul[class*=horizbuttons-][class*=-note-] > li:hover, ul[class*=horizbuttons-][class*=-tip-] > li:hover, ul[class*=horizbuttons-][class*=-default-] > li:hover {
24933+
ul[class*=horizbuttons-][class*=-note-] > li:hover, ul[class*=horizbuttons-][class*=-tip-] > li:hover, ul[class*=horizbuttons-][class*=-default-] > li:hover, ul[class*=horizbuttons-][class*=-light-] > li:hover {
2493024934
color: #333333;
2493124935
background-color: #f2f2f2;
2493224936
outline: 2px solid #333333;

packages/typo3-docs-theme/resources/public/js/theme.min.js

Lines changed: 18 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<a class="composer-link"
2+
href="{{ node.package.packagistLink }}"
3+
title="Packagist information"
4+
data-bs-toggle="modal"
5+
data-bs-target="#generalModal"
6+
data-description="{{ node.package.description }}"
7+
data-composername="{{ node.composerName }}"
8+
data-composercommand="{{ node.package.composerCommand }}"
9+
data-homepage="{{ node.package.homepage }}"
10+
data-documentation="{{ node.package.documentation }}"
11+
data-issues="{{ node.package.issues }}"
12+
data-source="{{ node.package.source }}"
13+
>
14+
{{ node.composerName }}
15+
</a>

packages/typo3-docs-theme/resources/template/structure/layout.html.twig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
</main>
5858

5959
{% include "structure/layoutParts/linkReferenceModal.html.twig" %}
60+
{% include "structure/layoutParts/generalModal.html.twig" %}
6061
</div>
6162

6263
{% include "structure/layoutParts/footer.html.twig" %}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{%- set interlinkShortcode = getSettings('interlink_shortcode') -%}
2+
<div class="modal fade" id="generalModal" tabindex="-1" aria-labelledby="linkReferenceModalLabel"
3+
aria-hidden="true" data-current-filename="{{ getCurrentFilename() }}"
4+
>
5+
<div class="modal-dialog">
6+
<div class="modal-content">
7+
<div class="modal-header">
8+
<h5 class="modal-title" id="generalModalLabel"></h5>
9+
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
10+
</div>
11+
<div class="modal-body">
12+
<div class="alert alert-success d-none" id="general-alert-success" role="alert"></div>
13+
<div id="generalModalContent">
14+
</div>
15+
</div>
16+
<div class="modal-footer justify-content-between">
17+
<div id="generalModalCustomButtons"></div>
18+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal"><i class="fa-regular fa-circle-xmark"></i>&nbsp;Close</button>
19+
</div>
20+
</div>
21+
</div>
22+
</div>

packages/typo3-docs-theme/src/DependencyInjection/Typo3DocsThemeExtension.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
1515
use Symfony\Component\DependencyInjection\Reference;
1616
use T3Docs\Typo3DocsTheme\Nodes\Inline\CodeInlineNode;
17+
use T3Docs\Typo3DocsTheme\Nodes\Inline\ComposerInlineNode;
1718
use T3Docs\Typo3DocsTheme\Nodes\YoutubeNode;
1819
use T3Docs\Typo3DocsTheme\Settings\Typo3DocsInputSettings;
1920
use T3Docs\Typo3DocsTheme\Settings\Typo3DocsThemeSettings;
@@ -99,6 +100,7 @@ public function prepend(ContainerBuilder $container): void
99100

100101
'templates' => [
101102
template(CodeInlineNode::class, 'inline/textroles/code.html.twig'),
103+
template(ComposerInlineNode::class, 'inline/textroles/composer.html.twig'),
102104
],
103105
]);
104106
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace T3Docs\Typo3DocsTheme\Nodes\Inline;
4+
5+
use phpDocumentor\Guides\Nodes\Inline\InlineNode;
6+
use T3Docs\Typo3DocsTheme\Packagist\ComposerPackage;
7+
8+
final class ComposerInlineNode extends InlineNode
9+
{
10+
public const TYPE = 'code';
11+
12+
public function __construct(
13+
private string $composerName,
14+
private ComposerPackage $package,
15+
) {
16+
parent::__construct(self::TYPE, $composerName);
17+
}
18+
19+
public function getComposerName(): string
20+
{
21+
return $this->composerName;
22+
}
23+
24+
public function getPackage(): ComposerPackage
25+
{
26+
return $this->package;
27+
}
28+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace T3Docs\Typo3DocsTheme\Packagist;
4+
5+
class ComposerPackage
6+
{
7+
public function __construct(
8+
private readonly string $composerName,
9+
private readonly string $composerCommand,
10+
private readonly string $packagistStatus,
11+
private readonly string $packagistLink = '',
12+
private readonly string $description = '',
13+
private readonly string $homepage = '',
14+
private readonly string $documentation = '',
15+
private readonly string $issues = '',
16+
private readonly string $source = '',
17+
private readonly bool $development = false,
18+
) {}
19+
20+
public function getComposerName(): string
21+
{
22+
return $this->composerName;
23+
}
24+
25+
public function getComposerCommand(): string
26+
{
27+
return $this->composerCommand;
28+
}
29+
30+
public function getPackagistLink(): string
31+
{
32+
return $this->packagistLink;
33+
}
34+
35+
public function getDescription(): string
36+
{
37+
return $this->description;
38+
}
39+
40+
public function getHomepage(): string
41+
{
42+
return $this->homepage;
43+
}
44+
45+
public function getDocumentation(): string
46+
{
47+
return $this->documentation;
48+
}
49+
50+
public function getIssues(): string
51+
{
52+
return $this->issues;
53+
}
54+
55+
public function getSource(): string
56+
{
57+
return $this->source;
58+
}
59+
60+
public function getPackagistStatus(): string
61+
{
62+
return $this->packagistStatus;
63+
}
64+
65+
public function isDevelopment(): bool
66+
{
67+
return $this->development;
68+
}
69+
}

0 commit comments

Comments
 (0)