Skip to content

Commit ba7acd1

Browse files
Add error view mode and optional Font Awesome auto-include (#5)
2 parents 87f2ece + 65657ae commit ba7acd1

File tree

6 files changed

+228
-67
lines changed

6 files changed

+228
-67
lines changed

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## v1.3.0 (TBD)
4+
5+
- Added error view mode to display issues (like missing config file) with distinct red/orange styling
6+
- Added optional Font Awesome auto-include from CDN via bundle configuration
7+
38
## v1.2.0 (2025-11-07)
49

510
- Added `icon_type` parameter for widgets: `fa` (Font Awesome, default) or `text` (for emoji/plain text)

README.md

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,80 @@ widgets:
9797
9898
### Widget Properties
9999
100-
| Property | Type | Required | Description |
101-
|----------|:--------:|:--------:|--------------------------------------------------------------------------------|
102-
| `icon`* | `string` | | Optional Font Awesome icon class (e.g., `fa-bug`). |
103-
| `text`* | `string` | | Optional widget label to display (e.g., `Mailpit`). |
104-
| `url` | `string` | required | Link URL to redirect to once widget is clicked. |
105-
| `target` | `string` | | Link target (e.g., `_blank`). Default: no target |
106-
| `title` | `string` | | Tooltip text. If not given, `url` is shown. |
107-
| `expand` | `bool` | | Set to `true` to make widget expand and fill available space. Default `false`. |
100+
| Property | Type | Required | Description |
101+
|-------------|:--------:|:--------:|--------------------------------------------------------------------------------|
102+
| `icon`* | `string` | | Optional icon to display. Can be Font Awesome class or emoji/text. |
103+
| `icon_type` | `string` | | Icon type: `fa` (Font Awesome, default) or `text` (emoji/plain text). |
104+
| `text`* | `string` | | Optional widget label to display alongside icon. |
105+
| `url` | `string` | required | Link URL to redirect to once widget is clicked. |
106+
| `target` | `string` | | Link target (e.g., `_blank`). Default: no target |
107+
| `title` | `string` | | Tooltip text. If not given, `url` is shown. |
108+
| `expand` | `bool` | | Set to `true` to make widget expand and fill available space. Default `false`.|
108109

109110
*) Either `icon` or `text` must be provided or exception will be thrown.
110111

112+
### Font Awesome Icons
113+
114+
DiscoDevBar supports Font Awesome icons for widgets. You have two options for including Font Awesome:
115+
116+
#### Option 1: Automatic Inclusion (Recommended for Quick Setup)
117+
118+
Enable automatic Font Awesome inclusion from CDN in your `.disco-devbar.yaml` configuration file:
119+
120+
```yaml
121+
font_awesome:
122+
enabled: true # Enable auto-include from CDN (default: false)
123+
version: '6.5.1' # Font Awesome version to use (optional, default: 6.5.1)
124+
125+
widgets:
126+
left:
127+
- icon: "fa-flag-checkered"
128+
text: "1.0"
129+
url: "https://github.com/user/repo"
130+
```
131+
132+
**Benefits:**
133+
134+
- Works out of the box - no additional setup needed
135+
- Icons display immediately
136+
- Configuration kept in one place with your widgets
137+
138+
**Note:** Only enable this if your application doesn't already include Font Awesome. If you have Font Awesome in
139+
your project, use Option 2 instead to avoid version conflicts.
140+
141+
#### Option 2: Manual Setup (Recommended if Font Awesome Already Installed)
142+
143+
If your application already includes Font Awesome (via NPM, CDN, or other means), simply use Font Awesome icon
144+
classes in your widget configuration. DiscoDevBar will use your existing Font Awesome installation.
145+
146+
**Example:**
147+
148+
```yaml
149+
widgets:
150+
left:
151+
- icon: "fa-database"
152+
icon_type: "fa" # Use Font Awesome (default)
153+
url: "http://localhost:8080"
154+
```
155+
156+
If you don't have Font Awesome installed, you can include it manually in your base template:
157+
158+
```twig
159+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
160+
```
161+
162+
#### Using Text/Emoji Instead
163+
164+
If you prefer not to use Font Awesome, you can use emoji or plain text:
165+
166+
```yaml
167+
widgets:
168+
left:
169+
- icon: "🚀"
170+
icon_type: "text" # Use plain text/emoji
171+
url: "/admin"
172+
```
173+
111174
## Usage
112175

113176
Include the devbar template in your base layout:

Resources/public/devbar.css

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@
1616
font-size: 15px;
1717
}
1818

19+
/* DiscoDevBar error state - more red/orange to indicate problem */
20+
.disco-devbar-error {
21+
background: repeating-linear-gradient(
22+
45deg,
23+
#d32f2f,
24+
#d32f2f 10px,
25+
#ff5722 10px,
26+
#ff5722 20px
27+
);
28+
}
29+
1930
.disco-devbar-content {
2031
max-width: 1100px;
2132
margin: 0 auto;
@@ -117,6 +128,13 @@
117128
margin-right: 4px;
118129
}
119130

131+
/* Plain text in devbar (non-link) */
132+
.disco-devbar-text {
133+
color: white;
134+
font-weight: normal;
135+
padding: 6px 8px;
136+
}
137+
120138
/* Adjust top navigation when DiscoDevBar is present (public pages only) */
121139
body:has(.disco-devbar):not(:has(.wrapper)) .top-nav {
122140
top: 40px;

Resources/views/devbar.html.twig

Lines changed: 67 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,56 +2,76 @@
22
{# This template displays DiscoDevBar with links to various tools and information #}
33
{# Show with `{% if app.environment == 'dev' %}` condition #}
44

5-
<div class="disco-devbar">
5+
{% set banner_data = debug_banner_data() %}
6+
7+
{# Auto-include Font Awesome if enabled in configuration #}
8+
{% if banner_data.fontAwesomeEnabled %}
9+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/{{ banner_data.fontAwesomeVersion }}/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
10+
{% endif %}
11+
12+
<div class="disco-devbar{% if banner_data.hasError %} disco-devbar-error{% endif %}">
613
<div class="disco-devbar-content">
7-
{% set banner_data = debug_banner_data() %}
8-
<div class="disco-devbar-container-left {% if banner_data.leftExpand %}disco-devbar-container-expand{% endif %}">
9-
{% for widget in banner_data.left %}
10-
{% if not loop.first %}
11-
<span class="disco-devbar-separator">&middot;</span>
12-
{% endif %}
13-
<span class="disco-devbar-widget {% if widget.expand %}disco-devbar-widget-expand{% endif %}">
14-
<a href="{{ widget.url }}"
15-
class="disco-devbar-link"
16-
{% if widget.target %}target="{{ widget.target }}"{% endif %}
17-
{% if widget.title %}title="{{ widget.title }}"{% endif %}>
18-
<span class="disco-devbar-link-content">
19-
{% if widget.icon %}
20-
{% if widget.iconType.value == 'fa' %}
21-
<i class="fa-solid {{ widget.icon }}"></i>
22-
{% else %}
23-
{{ widget.icon }}
24-
{% endif %}
25-
{% endif %}
26-
{% if widget.text %}{{ widget.text }}{% endif %}
27-
</span>
14+
{% if banner_data.hasError %}
15+
<div class="disco-devbar-container-left">
16+
<span class="disco-devbar-widget">
17+
<a href="https://github.com/MarcinOrlowski/php-symfony-discodevbar" class="disco-devbar-link" target="_blank" title="Visit DiscoDevBar on GitHub">
18+
<span class="disco-devbar-link-content">Disco DevBar</span>
2819
</a>
2920
</span>
30-
{% endfor %}
31-
</div>
32-
<div class="disco-devbar-container-right {% if banner_data.rightExpand %}disco-devbar-container-expand{% endif %}">
33-
{% for widget in banner_data.right %}
34-
{% if not loop.first %}
35-
<span class="disco-devbar-separator">&middot;</span>
36-
{% endif %}
37-
<span class="disco-devbar-widget {% if widget.expand %}disco-devbar-widget-expand{% endif %}">
38-
<a href="{{ widget.url }}"
39-
class="disco-devbar-link"
40-
{% if widget.target %}target="{{ widget.target }}"{% endif %}
41-
{% if widget.title %}title="{{ widget.title }}"{% endif %}>
42-
<span class="disco-devbar-link-content">
43-
{% if widget.icon %}
44-
{% if widget.iconType.value == 'fa' %}
45-
<i class="fa-solid {{ widget.icon }}"></i>
46-
{% else %}
47-
{{ widget.icon }}
48-
{% endif %}
49-
{% endif %}
50-
{% if widget.text %}{{ widget.text }}{% endif %}
51-
</span>
52-
</a>
21+
<span class="disco-devbar-separator">&middot;</span>
22+
<span class="disco-devbar-widget">
23+
<span class="disco-devbar-text">v{{ banner_data.version ?? 'N/A' }} * {{ banner_data.errorMessage }}</span>
5324
</span>
54-
{% endfor %}
55-
</div>
25+
</div>
26+
{% else %}
27+
<div class="disco-devbar-container-left {% if banner_data.leftExpand %}disco-devbar-container-expand{% endif %}">
28+
{% for widget in banner_data.left %}
29+
{% if not loop.first %}
30+
<span class="disco-devbar-separator">&middot;</span>
31+
{% endif %}
32+
<span class="disco-devbar-widget {% if widget.expand %}disco-devbar-widget-expand{% endif %}">
33+
<a href="{{ widget.url }}"
34+
class="disco-devbar-link"
35+
{% if widget.target %}target="{{ widget.target }}"{% endif %}
36+
{% if widget.title %}title="{{ widget.title }}"{% endif %}>
37+
<span class="disco-devbar-link-content">
38+
{% if widget.icon %}
39+
{% if widget.iconType.value == 'fa' %}
40+
<i class="fa-solid {{ widget.icon }}"></i>
41+
{% else %}
42+
{{ widget.icon }}
43+
{% endif %}
44+
{% endif %}
45+
{% if widget.text %}{{ widget.text }}{% endif %}
46+
</span>
47+
</a>
48+
</span>
49+
{% endfor %}
50+
</div>
51+
<div class="disco-devbar-container-right {% if banner_data.rightExpand %}disco-devbar-container-expand{% endif %}">
52+
{% for widget in banner_data.right %}
53+
{% if not loop.first %}
54+
<span class="disco-devbar-separator">&middot;</span>
55+
{% endif %}
56+
<span class="disco-devbar-widget {% if widget.expand %}disco-devbar-widget-expand{% endif %}">
57+
<a href="{{ widget.url }}"
58+
class="disco-devbar-link"
59+
{% if widget.target %}target="{{ widget.target }}"{% endif %}
60+
{% if widget.title %}title="{{ widget.title }}"{% endif %}>
61+
<span class="disco-devbar-link-content">
62+
{% if widget.icon %}
63+
{% if widget.iconType.value == 'fa' %}
64+
<i class="fa-solid {{ widget.icon }}"></i>
65+
{% else %}
66+
{{ widget.icon }}
67+
{% endif %}
68+
{% endif %}
69+
{% if widget.text %}{{ widget.text }}{% endif %}
70+
</span>
71+
</a>
72+
</span>
73+
{% endfor %}
74+
</div>
75+
{% endif %}
5676
</div>
5777
</div>

src/Dto/DiscoDevBarData.php

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,24 @@ class DiscoDevBarData
2525
/**
2626
* @param array<Widget> $left
2727
* @param array<Widget> $right
28-
* @param bool $leftExpand Whether left container should expand
29-
* @param bool $rightExpand Whether right container should expand
28+
* @param bool $leftExpand Whether left container should expand
29+
* @param bool $rightExpand Whether right container should expand
30+
* @param bool $hasError Whether to show error/alternative view
31+
* @param string $errorMessage Error message to display (when hasError is true)
32+
* @param string|null $version Bundle version (null shows as N/A)
33+
* @param bool $fontAwesomeEnabled Whether to auto-include Font Awesome
34+
* @param string $fontAwesomeVersion Font Awesome version to use
3035
*/
3136
public function __construct(
3237
public readonly array $left,
3338
public readonly array $right,
3439
public readonly bool $leftExpand,
35-
public readonly bool $rightExpand
40+
public readonly bool $rightExpand,
41+
public readonly bool $hasError = false,
42+
public readonly string $errorMessage = '',
43+
public readonly ?string $version = null,
44+
public readonly bool $fontAwesomeEnabled = false,
45+
public readonly string $fontAwesomeVersion = '6.5.1'
3646
) {
3747
}
3848
}

src/Service/DiscoDevBarService.php

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
namespace MarcinOrlowski\DiscoDevBar\Service;
2222

23+
use Composer\InstalledVersions;
2324
use MarcinOrlowski\DiscoDevBar\Dto\DiscoDevBarData;
2425
use MarcinOrlowski\DiscoDevBar\Dto\Widget;
2526
use Symfony\Component\Yaml\Yaml;
@@ -35,6 +36,11 @@ class DiscoDevBarService
3536
'.debug-banner.yaml', // Legacy, kept for backward compatibility
3637
];
3738

39+
/**
40+
* Default Font Awesome version
41+
*/
42+
private const DEFAULT_FONT_AWESOME_VERSION = '6.5.1';
43+
3844
public function __construct(
3945
private readonly string $projectDir
4046
) {
@@ -43,14 +49,21 @@ public function __construct(
4349
public function getDiscoDevBarData(): DiscoDevBarData
4450
{
4551
$configPath = $this->findConfigFile();
52+
$version = $this->getVersion();
4653

47-
// Default: empty widgets
54+
// Default: show error message when no config found
4855
if ($configPath === null) {
56+
$errorMessage = 'Config file not found: ' . self::CONFIG_FILES[0];
4957
return new DiscoDevBarData(
50-
left: [],
51-
right: [],
52-
leftExpand: false,
53-
rightExpand: false
58+
left: [],
59+
right: [],
60+
leftExpand: false,
61+
rightExpand: false,
62+
hasError: true,
63+
errorMessage: $errorMessage,
64+
version: $version,
65+
fontAwesomeEnabled: false,
66+
fontAwesomeVersion: self::DEFAULT_FONT_AWESOME_VERSION
5467
);
5568
}
5669

@@ -61,6 +74,20 @@ public function getDiscoDevBarData(): DiscoDevBarData
6174
$config = [];
6275
}
6376

77+
// Extract Font Awesome configuration from YAML
78+
$fontAwesomeConfig = $config['font_awesome'] ?? [];
79+
$fontAwesomeEnabled = false;
80+
$fontAwesomeVersion = self::DEFAULT_FONT_AWESOME_VERSION;
81+
82+
if (\is_array($fontAwesomeConfig)) {
83+
$fontAwesomeEnabled = $fontAwesomeConfig['enabled'] ?? false;
84+
// Use user's version if provided and not null, otherwise use default
85+
$userVersion = $fontAwesomeConfig['version'] ?? null;
86+
if ($userVersion !== null && \is_string($userVersion)) {
87+
$fontAwesomeVersion = $userVersion;
88+
}
89+
}
90+
6491
$widgets = $config['widgets'] ?? [];
6592
if (!\is_array($widgets)) {
6693
$widgets = [];
@@ -73,10 +100,15 @@ public function getDiscoDevBarData(): DiscoDevBarData
73100
$rightWidgets = $this->loadWidgets(\is_array($right) ? $right : []);
74101

75102
return new DiscoDevBarData(
76-
left: $leftWidgets,
77-
right: $rightWidgets,
78-
leftExpand: $this->hasExpandingWidget($leftWidgets),
79-
rightExpand: $this->hasExpandingWidget($rightWidgets)
103+
left: $leftWidgets,
104+
right: $rightWidgets,
105+
leftExpand: $this->hasExpandingWidget($leftWidgets),
106+
rightExpand: $this->hasExpandingWidget($rightWidgets),
107+
hasError: false,
108+
errorMessage: '',
109+
version: $version,
110+
fontAwesomeEnabled: \is_bool($fontAwesomeEnabled) ? $fontAwesomeEnabled : false,
111+
fontAwesomeVersion: $fontAwesomeVersion
80112
);
81113
}
82114

@@ -131,4 +163,17 @@ function ($widgetData): Widget {
131163
$widgetsData
132164
);
133165
}
166+
167+
/**
168+
* Get bundle version from Composer
169+
*/
170+
private function getVersion(): string
171+
{
172+
try {
173+
$version = InstalledVersions::getVersion('marcin-orlowski/symfony-discodevbar');
174+
return $version ?? 'dev';
175+
} catch (\Exception $e) {
176+
return 'dev';
177+
}
178+
}
134179
}

0 commit comments

Comments
 (0)