Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 34 additions & 45 deletions app/Icons/Lucide.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,18 @@

namespace App\Icons;

use Native\Mobile\Icon\AndroidSymbol;
use Native\Mobile\Icon\Icon;

/**
* The Lucide icons the web draws.
*
* Most are Lucide's own drawings. Their SVGs, from lucide-react 1.57.0, are in
* resources/icons, and the NativePHP build turns each one into a template image
* on iOS and a VectorDrawable on Android, so both platforms draw the web's
* strokes, tinted like any other icon. `$filled` is the on state of a star, a
* bookmark or a pin, which the web draws as the same shape with `fill-current`.
* Their SVGs, from lucide-react 1.57.0, are in resources/icons, and the
* NativePHP build turns each one into a template image on iOS and a
* VectorDrawable on Android, so both platforms draw the web's strokes, tinted
* like any other icon. `$filled` is the on state of a star, a bookmark or a
* pin, which the web draws as the same shape with `fill-current`.
*
* The rest still map to the closest SF Symbol and outlined Material icon. To
* draw one of them as the web does, add its SVG to resources/icons and name it
* in custom().
* A new case needs its SVG in resources/icons and a line in custom().
*/
enum Lucide
{
Expand All @@ -39,11 +36,12 @@ enum Lucide
case ArrowUp;
case Pin;
case ListOrdered;
/** lucide-react 1.57 draws Building2 as building-complex, so that is the drawing in building-2.svg. */
case Building2;
case MapPin;
case CalendarDays;
case Clock3;
/** The web draws GitHub's own mark, which neither system has, so this is the code glyph. */
/** Lucide has no brand marks, so this is GitHub's own, as the web draws it. */
case Github;
case Quote;
case Check;
Expand Down Expand Up @@ -109,7 +107,11 @@ enum Lucide
case Phone;
case PhoneOff;
case MicOff;
case Share;
case Share2;
case BadgeCheck;
case Gamepad;
case TabletSmartphone;

/**
* The icon the web's inbox draws for a kind of notification.
Expand Down Expand Up @@ -154,11 +156,11 @@ public static function forBadge(string $icon): self
}

/**
* The `custom:<name>` icon drawn from resources/icons/<name>.svg, or null for a system glyph.
* The `custom:<name>` icon drawn from resources/icons/<name>.svg.
*/
public function custom(bool $filled = false): ?string
public function custom(bool $filled = false): string
{
$name = match ($this) {
return Icon::custom(match ($this) {
self::GitCommitVertical => 'git-commit-vertical',
self::Bell => 'bell',
self::MessagesSquare => 'messages-square',
Expand All @@ -169,8 +171,18 @@ public function custom(bool $filled = false): ?string
self::Star => $filled ? 'star-filled' : 'star',
self::Bookmark => $filled ? 'bookmark-filled' : 'bookmark',
self::Trash2 => 'trash-2',
self::CornerDownRight => 'corner-down-right',
self::ChevronRight => 'chevron-right',
self::ChevronLeft => 'chevron-left',
self::ChevronDown => 'chevron-down',
self::ArrowUpRight => 'arrow-up-right',
self::ArrowUp => 'arrow-up',
self::ChevronsUp => 'chevrons-up',
self::ListOrdered => 'list-ordered',
self::Building2 => 'building-2',
self::MapPin => 'map-pin',
self::CalendarDays => 'calendar-days',
self::Github => 'github',
self::Quote => 'quote',
self::Check => 'check',
self::X => 'x',
Expand Down Expand Up @@ -234,44 +246,21 @@ public function custom(bool $filled = false): ?string
self::Phone => 'phone',
self::PhoneOff => 'phone-off',
self::MicOff => 'mic-off',
self::Share => 'share',
self::Share2 => 'share-2',
default => null,
};

return $name === null ? null : Icon::custom($name);
self::BadgeCheck => 'badge-check',
self::Gamepad => 'gamepad',
self::TabletSmartphone => 'tablet-smartphone',
});
}

public function ios(bool $filled = false): Ios|string
public function ios(bool $filled = false): string
{
return $this->custom($filled) ?? match ($this) {
self::CornerDownRight => Ios::ArrowTurnDownRight,
self::ChevronRight => Ios::ChevronRight,
self::ChevronLeft => Ios::ChevronLeft,
self::ChevronDown => Ios::ChevronDown,
self::ArrowUpRight => Ios::ArrowUpRight,
self::ListOrdered => Ios::ListNumber,
self::Building2 => Ios::Building2,
self::MapPin => Ios::Mappin,
self::CalendarDays => Ios::Calendar,
self::Github => Ios::ChevronLeftForwardslashChevronRight,
default => Ios::Circle,
};
return $this->custom($filled);
}

public function android(bool $filled = false): AndroidSymbol|string
public function android(bool $filled = false): string
{
return $this->custom($filled) ?? match ($this) {
self::CornerDownRight => AndroidOutlined::SubdirectoryArrowRight,
self::ChevronRight => AndroidOutlined::ChevronRight,
self::ChevronLeft => AndroidOutlined::ChevronLeft,
self::ChevronDown => AndroidOutlined::ExpandMore,
self::ArrowUpRight => AndroidOutlined::ArrowOutward,
self::ListOrdered => AndroidOutlined::FormatListNumbered,
self::Building2 => AndroidOutlined::Business,
self::MapPin => AndroidOutlined::LocationOn,
self::CalendarDays => AndroidOutlined::CalendarToday,
self::Github => AndroidOutlined::Code,
default => AndroidOutlined::Circle,
};
return $this->custom($filled);
}
}
4 changes: 1 addition & 3 deletions app/NativeComponents/Log.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
use App\Devnull\ShownTabs;
use App\Devnull\Stash;
use App\Devnull\Timeline;
use App\Icons\Android;
use App\Icons\Ios;
use App\Icons\Lucide;
use App\Models\PendingWrite;
use App\NativeComponents\Concerns\DrawsSkeletonFirst;
Expand Down Expand Up @@ -341,7 +339,7 @@ public function navigationOptions(): ?NavBarOptions
)
->action(
NavAction::make('compose')
->icon(ios: Ios::SquareAndPencil, android: Android::Edit)
->icon(ios: Lucide::SquarePen->ios(), android: Lucide::SquarePen->android())
->a11yLabel('New commit')
->press('composeInSheet'),
);
Expand Down
33 changes: 21 additions & 12 deletions app/NativeComponents/Profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
use App\Devnull\SiteLink;
use App\Devnull\Stash;
use App\Devnull\Timeline;
use App\Icons\AndroidOutlined;
use App\Icons\Ios;
use App\Icons\Lucide;
use App\NativeComponents\Concerns\DrawsSkeletonFirst;
use App\NativeComponents\Concerns\ExpandsThreads;
Expand Down Expand Up @@ -183,18 +181,29 @@ public function navigationOptions(): ?NavBarOptions
{
if ($this->isMe()) {
return NavBarOptions::make()
->action($this->shareAction()->a11yLabel('Share profile'))
->action(
NavAction::make('scheduled')
->icon(ios: Lucide::CalendarDays->ios(), android: Lucide::CalendarDays->android())
->a11yLabel('Scheduled commits')
->press('openScheduledCommits'),
)
->action(
NavAction::make('starred')
->icon(ios: Lucide::Star->ios(), android: Lucide::Star->android())
->a11yLabel('Starred')
->press('openStarred'),
)
->action(
NavAction::make('account')
->icon(ios: Lucide::Settings2->ios(), android: Lucide::Settings2->android())
->a11yLabel('Account')
->press('openAccount'),
NavAction::make('more')
->icon(ios: Lucide::Ellipsis->ios(), android: Lucide::Ellipsis->android())
->a11yLabel('More options')
->items([
$this->shareAction()->label('Share profile'),
NavAction::make('account')
->label('Account')
->icon(ios: Lucide::Settings2->ios(), android: Lucide::Settings2->android())
->press('openAccount'),
]),
);
}

Expand All @@ -207,14 +216,14 @@ public function navigationOptions(): ?NavBarOptions
}

/**
* Share profile, with the phone's own share icon: first in the nav bar on
* your own profile, first in the ⋯ on someone else's. It's always there, as
* the link needs nothing but the username.
* Share profile, under the share shape each phone uses (Lucide's share on
* iOS, share-2 on Android), first in the ⋯ of every profile. It's always
* there, as the link needs nothing but the username.
*/
private function shareAction(): NavAction
{
return NavAction::make('share')
->icon(ios: Ios::SquareAndArrowUp, android: AndroidOutlined::Share)
->icon(ios: Lucide::Share->ios(), android: Lucide::Share2->android())
->press('shareProfile');
}

Expand Down Expand Up @@ -569,7 +578,7 @@ public function editOnGitHub(): void
}

/**
* Your scheduled commits, beneath this tab, from the calendar beside Edit on GitHub.
* Your scheduled commits, beneath this tab, from the calendar in your profile's nav bar.
*/
public function openScheduledCommits(): void
{
Expand Down
1 change: 1 addition & 0 deletions resources/icons/arrow-up-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/badge-check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/building-2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/calendar-days.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/chevron-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/chevron-left.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/chevron-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/corner-down-right.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/gamepad.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/list-ordered.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/map-pin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/share.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/icons/tablet-smartphone.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</native:stack>

<native:row class="gap-2 items-center">
<native:button ref="share" variant="secondary" size="sm" :ios-icon="\App\Icons\Lucide::Share2->ios()" :android-icon="\App\Icons\Lucide::Share2->android()" @press="share" a11y-label="Share {{ $user->handle() }}" />
<native:button ref="share" variant="secondary" size="sm" :ios-icon="\App\Icons\Lucide::Share->ios()" :android-icon="\App\Icons\Lucide::Share2->android()" @press="share" a11y-label="Share {{ $user->handle() }}" />
@if ($organization->isFollowing)
<native:button ref="follow" variant="secondary" size="sm" @press="toggleFollow" a11y-hint="Unfollows {{ $user->handle() }}">Unfollow</native:button>
@else
Expand Down
11 changes: 4 additions & 7 deletions resources/views/native/partials/profile-header.blade.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{{--
The profile's header, which the pager draws above its tabs (see profile.blade.php): the avatar ringed in their
lane, Follow (or, on your own, Scheduled commits and Edit on GitHub), who they are, what GitHub says about them,
their counts and, in pastéis mode, the pastéis they've been given, then their activity, streaks and achievements.
lane, Follow (or, on your own, Edit on GitHub), who they are, what GitHub says about them, their counts and, in
pastéis mode, the pastéis they've been given, then their activity, streaks and achievements.
It scrolls up with the tab you're on until the tabs pin under the nav bar.
--}}
<native:column class="w-full bg-theme-surface">
Expand Down Expand Up @@ -33,11 +33,8 @@
@if ($sketched)
{{-- Follow waits for devnull to say whether you already do. --}}
@elseif ($isMe)
{{-- Your scheduled commits, which only you see, beside Edit on GitHub. --}}
<native:row class="gap-2 items-center">
<native:button ref="profile-scheduled" variant="secondary" size="sm" :ios-icon="\App\Icons\Lucide::CalendarDays->ios()" :android-icon="\App\Icons\Lucide::CalendarDays->android()" @press="openScheduledCommits" a11y-label="Scheduled commits" />
<native:button ref="edit-on-github" variant="secondary" size="sm" :ios-icon-trailing="\App\Icons\Lucide::ArrowUpRight->ios()" :android-icon-trailing="\App\Icons\Lucide::ArrowUpRight->android()" @press="editOnGitHub">Edit on GitHub</native:button>
</native:row>
{{-- Edit on GitHub, where the web puts Follow. Your scheduled commits are in the nav bar. --}}
<native:button ref="edit-on-github" variant="secondary" size="sm" :ios-icon-trailing="\App\Icons\Lucide::ArrowUpRight->ios()" :android-icon-trailing="\App\Icons\Lucide::ArrowUpRight->android()" @press="editOnGitHub">Edit on GitHub</native:button>
@else
{{-- The web's Remote, beside Follow, when you can push to them. --}}
<native:row class="gap-2 items-center">
Expand Down
4 changes: 2 additions & 2 deletions resources/views/native/partials/score-card.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<native:text font="semibold" class="flex-1 text-[13px] font-semibold tracking-tight text-theme-nata" :max-lines="1">Nata Nu/&#x2060;<native:text text="/" class="text-outline text-theme-nata" />&#x2060;ers</native:text>
@if ($card->signed)
<native:row ref="score-signed-{{ $commit->id }}" class="gap-1 items-center">
<native:icon :ios="\App\Icons\Ios::CheckmarkSeal" :android="\App\Icons\Android::Verified" :size="13" class="text-theme-ink-muted" />
<native:icon :ios="\App\Icons\Lucide::BadgeCheck->ios()" :android="\App\Icons\Lucide::BadgeCheck->android()" :size="13" class="text-theme-ink-muted" />
<native:text class="text-xs text-theme-ink-muted" :max-lines="1">Signed by their device</native:text>
</native:row>
@endif
Expand All @@ -35,7 +35,7 @@
</native:column>
@if ($playable)
<native:row class="px-3 py-[6] gap-1 items-center rounded-full bg-theme-nata">
<native:icon :ios="\App\Icons\Ios::GamecontrollerFill" :android="\App\Icons\Android::SportsEsports" :size="14" class="text-theme-on-nata" />
<native:icon :ios="\App\Icons\Lucide::Gamepad->ios()" :android="\App\Icons\Lucide::Gamepad->android()" :size="16" class="text-theme-on-nata" />
<native:text font="semibold" class="text-[13px] font-semibold text-theme-on-nata" :max-lines="1">Beat {{ $score }}</native:text>
</native:row>
@endif
Expand Down
3 changes: 1 addition & 2 deletions resources/views/native/this-device.blade.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@use('App\Devnull\Lane')
@use('App\Icons\Ios')
@use('App\Icons\Android')
@use('App\Icons\Lucide')

{{--
Expand Down Expand Up @@ -309,7 +308,7 @@
</native:column>

<native:column class="w-full px-4 pt-4">
<native:button ref="devices" variant="secondary" size="lg" :ios-icon="Ios::Iphone" :android-icon="Android::Smartphone" @press="openDevices" class="w-full">Your devices on dev-null.sh</native:button>
<native:button ref="devices" variant="secondary" size="lg" :ios-icon="Lucide::TabletSmartphone->ios()" :android-icon="Lucide::TabletSmartphone->android()" @press="openDevices" class="w-full">Your devices on dev-null.sh</native:button>
</native:column>
</native:column>

Expand Down
12 changes: 12 additions & 0 deletions tests/Feature/CustomIconsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ function referencedCustomIcons(): array
expect($missing)->toBe([]);
});

it('draws no system icon but the Apple logo, which Sign in with Apple has to show', function () {
$systemIcons = collect([...File::allFiles(app_path()), ...File::allFiles(resource_path('views'))])
->reject(fn (SplFileInfo $file): bool => str_starts_with($file->getPathname(), app_path('Icons')))
->flatMap(function (SplFileInfo $file): array {
preg_match_all('/\b(?:Ios|Android|AndroidOutlined)::(?!AppleLogo\b)\w+/', (string) file_get_contents($file->getPathname()), $matches);

return array_map(fn (string $icon): string => $file->getFilename().': '.$icon, $matches[0]);
});

expect($systemIcons->all())->toBe([]);
});

it('converts each SVG in resources/icons for both platforms', function (string $path) {
// The build runs the same conversion and stops at the first SVG it can't draw.
$icon = SvgParser::parse((string) file_get_contents($path), 'resources/icons/'.basename($path));
Expand Down
Loading
Loading