Initial
25
.dockerignore
Normal file
@@ -0,0 +1,25 @@
|
||||
**/.dockerignore
|
||||
**/.env
|
||||
**/.git
|
||||
**/.gitignore
|
||||
**/.project
|
||||
**/.settings
|
||||
**/.toolstarget
|
||||
**/.vs
|
||||
**/.vscode
|
||||
**/.idea
|
||||
**/*.*proj.user
|
||||
**/*.dbmdl
|
||||
**/*.jfm
|
||||
**/azds.yaml
|
||||
**/bin
|
||||
**/charts
|
||||
**/docker-compose*
|
||||
**/Dockerfile*
|
||||
**/node_modules
|
||||
**/npm-debug.log
|
||||
**/obj
|
||||
**/secrets.dev.yaml
|
||||
**/values.dev.yaml
|
||||
LICENSE
|
||||
README.md
|
||||
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
13
.idea/.idea.nukeitter-web.dir/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Rider ignored files
|
||||
/projectSettingsUpdater.xml
|
||||
/modules.xml
|
||||
/contentModel.xml
|
||||
/.idea.nukeitter-web.iml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
4
.idea/.idea.nukeitter-web.dir/.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
||||
8
.idea/.idea.nukeitter-web.dir/.idea/indexLayout.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/.idea.nukeitter-web.dir/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
13
.idea/.idea.nukitter-web/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Rider ignored files
|
||||
/projectSettingsUpdater.xml
|
||||
/modules.xml
|
||||
/contentModel.xml
|
||||
/.idea.nukitter-web.iml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
4
.idea/.idea.nukitter-web/.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
||||
8
.idea/.idea.nukitter-web/.idea/indexLayout.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="UserContentModel">
|
||||
<attachedFolders />
|
||||
<explicitIncludes />
|
||||
<explicitExcludes />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/.idea.nukitter-web/.idea/jsLibraryMappings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<file url="PROJECT" libraries="{daisyui}" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/.idea.nukitter-web/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
14
App.razor
Normal file
@@ -0,0 +1,14 @@
|
||||
<CascadingAuthenticationState>
|
||||
<Router AppAssembly="@typeof(App).Assembly">
|
||||
<Found Context="routeData">
|
||||
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
|
||||
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
|
||||
</Found>
|
||||
<NotFound>
|
||||
<PageTitle>Not found</PageTitle>
|
||||
<LayoutView Layout="@typeof(MainLayout)">
|
||||
<p role="alert">Sorry, there's nothing at this address.</p>
|
||||
</LayoutView>
|
||||
</NotFound>
|
||||
</Router>
|
||||
</CascadingAuthenticationState>
|
||||
16
Controllers/UserController.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Twitter;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Nukitter.Web.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
public class UserController : ControllerBase {
|
||||
[HttpGet("twitter")]
|
||||
public async Task TwitterSignIn() {
|
||||
await HttpContext.ChallengeAsync(TwitterDefaults.AuthenticationScheme, new AuthenticationProperties {
|
||||
RedirectUri = "https://nukeitter.dev.fergl.ie:5001/profile"
|
||||
});
|
||||
}
|
||||
}
|
||||
20
Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
EXPOSE 443
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
|
||||
WORKDIR /src
|
||||
COPY ["nukitter-web.csproj", "./"]
|
||||
RUN dotnet restore "nukitter-web.csproj"
|
||||
COPY . .
|
||||
WORKDIR "/src/"
|
||||
RUN dotnet build "nukitter-web.csproj" -c Release -o /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "nukitter-web.csproj" -c Release -o /app/publish
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
COPY --from=publish /app/publish .
|
||||
ENTRYPOINT ["dotnet", "nukitter-web.dll"]
|
||||
18
Pages/Counter.razor
Normal file
@@ -0,0 +1,18 @@
|
||||
@page "/counter"
|
||||
|
||||
<PageTitle>Counter</PageTitle>
|
||||
|
||||
<h1>Counter</h1>
|
||||
|
||||
<p role="status">Current count: @currentCount</p>
|
||||
|
||||
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
|
||||
|
||||
@code {
|
||||
private int currentCount = 0;
|
||||
|
||||
private void IncrementCount() {
|
||||
currentCount++;
|
||||
}
|
||||
|
||||
}
|
||||
41
Pages/Error.cshtml
Normal file
@@ -0,0 +1,41 @@
|
||||
@page
|
||||
@model Nukitter.Web.Pages.ErrorModel
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
|
||||
<title>Error</title>
|
||||
<link href="~/css/bootstrap/bootstrap.min.css" rel="stylesheet"/>
|
||||
<link href="~/css/site.css" rel="stylesheet" asp-append-version="true"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="main">
|
||||
<div class="content px-4">
|
||||
<h1 class="text-danger">Error.</h1>
|
||||
<h2 class="text-danger">An error occurred while processing your request.</h2>
|
||||
|
||||
@if (Model.ShowRequestId) {
|
||||
<p>
|
||||
<strong>Request ID:</strong> <code>@Model.RequestId</code>
|
||||
</p>
|
||||
}
|
||||
|
||||
<h3>Development Mode</h3>
|
||||
<p>
|
||||
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
|
||||
</p>
|
||||
<p>
|
||||
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
|
||||
It can result in displaying sensitive information from exceptions to end users.
|
||||
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
|
||||
and restarting the app.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
23
Pages/Error.cshtml.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace Nukitter.Web.Pages;
|
||||
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
[IgnoreAntiforgeryToken]
|
||||
public class ErrorModel : PageModel {
|
||||
public string? RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
private readonly ILogger<ErrorModel> _logger;
|
||||
|
||||
public ErrorModel(ILogger<ErrorModel> logger) {
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void OnGet() {
|
||||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
|
||||
}
|
||||
}
|
||||
37
Pages/Index.razor
Normal file
@@ -0,0 +1,37 @@
|
||||
@page "/"
|
||||
|
||||
<PageTitle>Twit Nuke</PageTitle>
|
||||
|
||||
<div
|
||||
class="container mx-auto flex flex-col md:flex-row items-center my-12 md:my-24">
|
||||
<!--Left Col-->
|
||||
<div
|
||||
class="flex flex-col w-full lg:w-1/2 justify-center items-start pt-12 pb-24 px-6 group">
|
||||
<p class="uppercase tracking-loose">Nukeitter</p>
|
||||
<div class="group flex justify-center items-center">
|
||||
<h1 class="font-bold text-3xl my-4 flx flex-row">
|
||||
Delete your Tweets on a schedule... or just once.
|
||||
</h1>
|
||||
</div>
|
||||
<p class="leading-normal mb-4">
|
||||
You never know who's gonna read that radioactive Tweet you forgot you sent
|
||||
in 2017
|
||||
</p>
|
||||
<a
|
||||
href="/setup"
|
||||
class="btn btn-outline btn-info gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.59 14.37a6 6 0 01-5.84 7.38v-4.8m5.84-2.58a14.98 14.98 0 006.16-12.12A14.98 14.98 0 009.631 8.41m5.96 5.96a14.926 14.926 0 01-5.841 2.58m-.119-8.54a6 6 0 00-7.381 5.84h4.8m2.581-5.84a14.927 14.927 0 00-2.58 5.84m2.699 2.7c-.103.021-.207.041-.311.06a15.09 15.09 0 01-2.448-2.448 14.9 14.9 0 01.06-.312m-2.24 2.39a4.493 4.493 0 00-1.757 4.306 4.493 4.493 0 004.306-1.758M16.5 9a1.5 1.5 0 11-3 0 1.5 1.5 0 013 0z"/>
|
||||
</svg>
|
||||
|
||||
Let's go
|
||||
</a>
|
||||
</div>
|
||||
<!--Right Col-->
|
||||
<div class="w-full lg:w-1/2 lg:py-6 text-center">
|
||||
<img
|
||||
src="/img/logo.svg"
|
||||
alt="Radioactive"
|
||||
class="fill-current text-gray-900 w-3/5 mx-auto"/>
|
||||
</div>
|
||||
</div>
|
||||
31
Pages/Profile.razor
Normal file
@@ -0,0 +1,31 @@
|
||||
@page "/profile"
|
||||
@using System.Security.Claims
|
||||
@inject NavigationManager _navigationManager
|
||||
|
||||
<PageTitle>Twit Nuke</PageTitle>
|
||||
|
||||
<div
|
||||
class="container mx-auto flex flex-col md:flex-row items-center my-12 md:my-24">
|
||||
<h1>This is your profile</h1>
|
||||
<div>@claim</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
[CascadingParameter]
|
||||
public Task<AuthenticationState> authenticationState { get; set; }
|
||||
|
||||
public Claim claim;
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
var authState = await authenticationState;
|
||||
var user = authState.User;
|
||||
|
||||
if (user.Identity.IsAuthenticated) {
|
||||
claim = user.FindFirst(c => c.Type == ClaimTypes.NameIdentifier);
|
||||
}
|
||||
else {
|
||||
_navigationManager.NavigateTo("/");
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Pages/Setup.razor
Normal file
@@ -0,0 +1,42 @@
|
||||
@page "/setup"
|
||||
@inject NavigationManager _navigationManager
|
||||
|
||||
<PageTitle>Twit Nuke</PageTitle>
|
||||
|
||||
<div
|
||||
class="container mx-auto flex flex-col md:flex-row items-center my-12 md:my-24">
|
||||
<!--Left Col-->
|
||||
<div
|
||||
class="flex flex-col w-full lg:w-1/2 justify-center items-start pt-12 pb-24 px-6 group">
|
||||
<div class="group flex justify-center items-center">
|
||||
<h1 class="font-bold text-3xl my-4 flx flex-row">
|
||||
Let's get started
|
||||
</h1>
|
||||
</div>
|
||||
<p class="leading-normal mb-4">
|
||||
We need access to your Twitter account, promise we won't do anything icky!!
|
||||
</p>
|
||||
<button
|
||||
@onclick="TwitterSignin"
|
||||
href="/setup"
|
||||
class="btn btn-outline btn-info gap-2">
|
||||
<i class="fa-brands fa-twitter"></i>
|
||||
Login to Twitter
|
||||
</button>
|
||||
</div>
|
||||
<!--Right Col-->
|
||||
<div class="w-full lg:w-1/2 lg:py-6 text-center">
|
||||
<img
|
||||
src="/img/logo.svg"
|
||||
alt="Radioactive"
|
||||
class="fill-current text-gray-900 w-3/5 mx-auto"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
private void TwitterSignin() {
|
||||
_navigationManager.NavigateTo("user/twitter", true);
|
||||
}
|
||||
|
||||
}
|
||||
35
Pages/_Host.cshtml
Normal file
@@ -0,0 +1,35 @@
|
||||
@page "/"
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@namespace Nukitter.Web.Pages
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
@addTagHelper *, Heroicons.AspNetCore.Mvc.TagHelpers
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<base href="~/"/>
|
||||
<link href="https://cdn.jsdelivr.net/npm/daisyui@2.47.0/dist/full.css" rel="stylesheet" type="text/css"/>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css" integrity="sha512-MV7K8+y+gLIBoVD59lQIYicR65iaqukzvf/nwasF0nqhPay5w/9lJmVM2hMDcnK1OnMGCdVK+iQrJ7lzPJQd1w==" crossorigin="anonymous" referrerpolicy="no-referrer"/>
|
||||
<link rel="icon" type="image/png" href="favicon.ico"/>
|
||||
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered"/>
|
||||
</head>
|
||||
<body>
|
||||
<component type="typeof(App)" render-mode="ServerPrerendered"/>
|
||||
|
||||
<div id="blazor-error-ui">
|
||||
<environment include="Staging,Production">
|
||||
An error has occurred. This application may no longer respond until reloaded.
|
||||
</environment>
|
||||
<environment include="Development">
|
||||
An unhandled exception has occurred. See browser dev tools for details.
|
||||
</environment>
|
||||
<a href="" class="reload">Reload</a>
|
||||
<a class="dismiss">🗙</a>
|
||||
</div>
|
||||
|
||||
<script src="_framework/blazor.server.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
47
Program.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Net;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
builder.WebHost.ConfigureKestrel(options => {
|
||||
options.Listen(IPAddress.Any, 5001, listenOptions => {
|
||||
var certPem = File.ReadAllText("/etc/letsencrypt/live/dev.fergl.ie/fullchain.pem");
|
||||
var keyPem = File.ReadAllText("/etc/letsencrypt/live/dev.fergl.ie/privkey.pem");
|
||||
var x509 = X509Certificate2.CreateFromPem(certPem, keyPem);
|
||||
listenOptions.UseHttps(x509);
|
||||
});
|
||||
});
|
||||
builder.Services.AddRazorPages();
|
||||
builder.Services.AddServerSideBlazor();
|
||||
|
||||
builder.Services.AddAuthentication(options => {
|
||||
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddCookie()
|
||||
.AddTwitter(twitterOptions => {
|
||||
twitterOptions.ConsumerKey = builder.Configuration["Auth:Twitter:ConsumerKey"];
|
||||
twitterOptions.ConsumerSecret = builder.Configuration["Auth:Twitter:ConsumerSecret"];
|
||||
twitterOptions.RetrieveUserDetails = true;
|
||||
});
|
||||
builder.Services.AddControllers();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
if (!app.Environment.IsDevelopment()) {
|
||||
app.UseExceptionHandler("/Error");
|
||||
app.UseHsts();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseStaticFiles();
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.MapBlazorHub();
|
||||
app.MapFallbackToPage("/_Host");
|
||||
app.MapControllerRoute(
|
||||
name: "default",
|
||||
pattern: "{controller=Home}/{action=Index}/{id?}");
|
||||
|
||||
app.Run();
|
||||
37
Properties/launchSettings.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:33728",
|
||||
"sslPort": 44341
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:5001",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Shared/MainLayout.razor
Normal file
@@ -0,0 +1,15 @@
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
<PageTitle>nukitter-web</PageTitle>
|
||||
|
||||
<div class="page">
|
||||
<div class="sidebar">
|
||||
<NavMenu/>
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<article class="content px-4">
|
||||
@Body
|
||||
</article>
|
||||
</main>
|
||||
</div>
|
||||
70
Shared/MainLayout.razor.css
Normal file
@@ -0,0 +1,70 @@
|
||||
.page {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #d6d5d5;
|
||||
justify-content: flex-end;
|
||||
height: 3.5rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.top-row ::deep a, .top-row .btn-link {
|
||||
white-space: nowrap;
|
||||
margin-left: 1.5rem;
|
||||
}
|
||||
|
||||
.top-row a:first-child {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@media (max-width: 640.98px) {
|
||||
.top-row:not(.auth) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.top-row.auth {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.top-row a, .top-row .btn-link {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.page {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
height: 100vh;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.top-row {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.top-row, article {
|
||||
padding-left: 2rem !important;
|
||||
padding-right: 1.5rem !important;
|
||||
}
|
||||
}
|
||||
14
Shared/NavMenu.razor
Normal file
@@ -0,0 +1,14 @@
|
||||
<div class="navbar bg-base-100">
|
||||
<div class="flex-none">
|
||||
<img
|
||||
src="/img/logo.svg"
|
||||
alt="Radioactive"
|
||||
class="fill-current text-gray-900 w-8 h-8 mx-auto"/>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<a class="btn btn-ghost normal-case text-xl">NukeTwitter</a>
|
||||
</div>
|
||||
<div class="flex-none">
|
||||
<span>Stuff on the right</span>
|
||||
</div>
|
||||
</div>
|
||||
68
Shared/NavMenu.razor.css
Normal file
@@ -0,0 +1,68 @@
|
||||
.navbar-toggler {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.top-row {
|
||||
height: 3.5rem;
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.oi {
|
||||
width: 2rem;
|
||||
font-size: 1.1rem;
|
||||
vertical-align: text-top;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
font-size: 0.9rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.nav-item:first-of-type {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.nav-item:last-of-type {
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.nav-item ::deep a {
|
||||
color: #d7d7d7;
|
||||
border-radius: 4px;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 3rem;
|
||||
}
|
||||
|
||||
.nav-item ::deep a.active {
|
||||
background-color: rgba(255,255,255,0.25);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-item ::deep a:hover {
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
color: white;
|
||||
}
|
||||
|
||||
@media (min-width: 641px) {
|
||||
.navbar-toggler {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapse {
|
||||
/* Never collapse the sidebar for wide screens */
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-scrollable {
|
||||
/* Allow sidebar to scroll for tall menus */
|
||||
height: calc(100vh - 3.5rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
17
Shared/SurveyPrompt.razor
Normal file
@@ -0,0 +1,17 @@
|
||||
<div class="alert alert-secondary mt-4">
|
||||
<span class="oi oi-pencil me-2" aria-hidden="true"></span>
|
||||
<strong>@Title</strong>
|
||||
|
||||
<span class="text-nowrap">
|
||||
Please take our
|
||||
<a target="_blank" class="font-weight-bold link-dark" href="https://go.microsoft.com/fwlink/?linkid=2186158">brief survey</a>
|
||||
</span>
|
||||
and tell us what you think.
|
||||
</div>
|
||||
|
||||
@code {
|
||||
// Demonstrates how a parent component can supply parameters
|
||||
[Parameter]
|
||||
public string? Title { get; set; }
|
||||
|
||||
}
|
||||
10
_Imports.razor
Normal file
@@ -0,0 +1,10 @@
|
||||
@using System.Net.Http
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Forms
|
||||
@using Microsoft.AspNetCore.Components.Routing
|
||||
@using Microsoft.AspNetCore.Components.Web
|
||||
@using Microsoft.AspNetCore.Components.Web.Virtualization
|
||||
@using Microsoft.JSInterop
|
||||
@using Nukitter.Web
|
||||
@using Nukitter.Web.Shared
|
||||
9
appsettings.Development.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"DetailedErrors": true,
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
15
appsettings.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Auth": {
|
||||
"Twitter": {
|
||||
"ConsumerKey": "wRE6ajw7rraqDax8iOhZCHvml",
|
||||
"ConsumerSecret": "l4Jn42ON1BrN8N4L28unQJYcjcRpbWuMIfcwzZZx3Dg8ZipyoD"
|
||||
}
|
||||
}
|
||||
}
|
||||
19
nukeitter-web.csproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<RootNamespace>Nukitter.Web</RootNamespace>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Data" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Twitter" Version="7.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
BIN
wwwroot/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
wwwroot/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
wwwroot/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
wwwroot/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 774 B |
BIN
wwwroot/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
wwwroot/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
wwwroot/img/logo.png
Normal file
|
After Width: | Height: | Size: 62 KiB |
65
wwwroot/img/logo.svg
Normal file
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg height="800px"
|
||||
width="800px"
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 297.502 297.502"
|
||||
xml:space="preserve">
|
||||
<g>
|
||||
<g id="XMLID_20_">
|
||||
<g>
|
||||
<path style="fill:#0071D4;"
|
||||
d="M260.1,84.461c17.17,29.75,21.74,64.39,12.85,97.57c-8.89,33.17-30.17,60.9-59.91,78.07
|
||||
c-29.74,17.17-64.39,21.73-97.57,12.84c-33.17-8.88-60.89-30.16-78.07-59.9c-17.17-29.75-21.73-64.39-12.84-97.57
|
||||
c8.89-33.17,30.16-60.9,59.91-78.07c19.81-11.44,41.79-17.28,64.07-17.28c11.17,0,22.42,1.47,33.49,4.44
|
||||
C215.2,33.441,242.93,54.721,260.1,84.461z M266.42,148.931c0.01-2.64-1.03-5.17-2.9-7.04c-1.86-1.87-4.39-2.92-7.03-2.92h-70.62
|
||||
c-0.86-3.25-2.15-6.41-3.88-9.41c-1.73-2.99-3.83-5.69-6.21-8.07l35.31-61.16c1.32-2.28,1.67-5,0.99-7.54
|
||||
c-0.69-2.55-2.36-4.72-4.65-6.03c-36.28-20.84-81.31-20.8-117.57,0.13l-0.22,0.14c-4.74,2.75-6.35,8.81-3.62,13.55l35.37,61.25
|
||||
c-4.61,4.68-7.96,10.48-9.71,16.99c-0.01,0.05-0.02,0.1-0.04,0.15H41.01c-2.63,0-5.16,1.05-7.02,2.92
|
||||
c-1.87,1.86-2.91,4.39-2.91,7.02c0.01,20.52,5.47,40.81,15.78,58.67s25.15,32.73,42.92,43c1.52,0.88,3.24,1.33,4.97,1.33
|
||||
c0.86,0,1.72-0.11,2.56-0.34c2.55-0.68,4.72-2.34,6.04-4.62l35.31-61.18c0.06,0.02,0.11,0.04,0.16,0.05
|
||||
c3.31,0.89,6.66,1.32,10,1.32c3.23,0,6.44-0.42,9.56-1.23l35.37,61.25c1.31,2.29,3.47,3.96,6.02,4.64
|
||||
c0.85,0.23,1.71,0.34,2.57,0.34c1.73,0,3.44-0.46,4.96-1.34l0.28-0.16C243.78,229.751,266.32,190.771,266.42,148.931z"/>
|
||||
<path d="M277.3,74.531c19.83,34.34,25.09,74.34,14.83,112.64s-34.82,70.31-69.16,90.13c-22.87,13.2-48.26,19.95-73.98,19.95
|
||||
c-12.89,0-25.87-1.7-38.66-5.12c-38.29-10.26-70.3-34.83-90.13-69.16c-19.82-34.34-25.09-74.34-14.83-112.64
|
||||
c10.27-38.3,34.83-70.31,69.16-90.13c34.34-19.82,74.34-25.09,112.64-14.83S257.48,40.201,277.3,74.531z M272.95,182.031
|
||||
c8.89-33.18,4.32-67.82-12.85-97.57c-17.17-29.74-44.9-51.02-78.07-59.9c-11.07-2.97-22.32-4.44-33.49-4.44
|
||||
c-22.28,0-44.26,5.84-64.07,17.28c-29.75,17.17-51.02,44.9-59.91,78.07c-8.89,33.18-4.33,67.82,12.84,97.57
|
||||
c17.18,29.74,44.9,51.02,78.07,59.9c33.18,8.89,67.83,4.33,97.57-12.84C242.78,242.931,264.06,215.201,272.95,182.031z"/>
|
||||
<path d="M263.52,141.891c1.87,1.87,2.91,4.4,2.9,7.04c-0.1,41.84-22.64,80.82-58.84,101.71l-0.28,0.16
|
||||
c-1.52,0.88-3.23,1.34-4.96,1.34c-0.86,0-1.72-0.11-2.57-0.34c-2.55-0.68-4.71-2.35-6.02-4.64l-35.37-61.25
|
||||
c-3.12,0.81-6.33,1.23-9.56,1.23c-3.34,0-6.69-0.43-10-1.32c-0.05-0.01-0.1-0.03-0.16-0.05l-35.31,61.18
|
||||
c-1.32,2.28-3.49,3.94-6.04,4.62c-0.84,0.23-1.7,0.34-2.56,0.34c-1.73,0-3.45-0.45-4.97-1.33c-17.77-10.27-32.61-25.14-42.92-43
|
||||
s-15.77-38.15-15.78-58.67c0-2.63,1.04-5.16,2.91-7.02c1.86-1.87,4.39-2.92,7.02-2.92h70.63c0.02-0.05,0.03-0.1,0.04-0.15
|
||||
c1.75-6.51,5.1-12.31,9.71-16.99l-35.37-61.25c-2.73-4.74-1.12-10.8,3.62-13.55l0.22-0.14c36.26-20.93,81.29-20.97,117.57-0.13
|
||||
c2.29,1.31,3.96,3.48,4.65,6.03c0.68,2.54,0.33,5.26-0.99,7.54l-35.31,61.16c2.38,2.38,4.48,5.08,6.21,8.07
|
||||
c1.73,3,3.02,6.16,3.88,9.41h70.62C259.13,138.971,261.66,140.021,263.52,141.891z M246.03,158.841h-60.25
|
||||
c-1.82,6.66-5.31,12.57-10.11,17.28l30.07,52.1C228.37,211.971,243.11,186.591,246.03,158.841z M158.53,111.641l30.13-52.18
|
||||
c-25.49-11.34-54.83-11.27-80.23,0.2l30.07,52.1C144.99,109.951,151.86,109.881,158.53,111.641z M166.64,153.541
|
||||
c1.28-4.78,0.62-9.76-1.85-14.05c-2.47-4.28-6.47-7.35-11.24-8.63c-1.6-0.42-3.22-0.63-4.83-0.63c-3.21,0-6.37,0.84-9.23,2.48
|
||||
c-4.28,2.48-7.34,6.47-8.62,11.25s-0.63,9.76,1.85,14.05c2.47,4.28,6.46,7.35,11.24,8.63c4.78,1.27,9.77,0.62,14.05-1.85
|
||||
C162.29,162.311,165.36,158.321,166.64,153.541z M91.37,227.971l30.13-52.19c-2.29-2.32-4.31-4.94-5.98-7.84
|
||||
c-1.68-2.9-2.94-5.96-3.8-9.1H51.46c1.41,13.6,5.7,26.85,12.6,38.81C70.96,209.601,80.3,219.941,91.37,227.971z"/>
|
||||
<path style="fill:#FFD63F;"
|
||||
d="M185.78,158.841h60.25c-2.92,27.75-17.66,53.13-40.29,69.38l-30.07-52.1
|
||||
C180.47,171.411,183.96,165.501,185.78,158.841z"/>
|
||||
<path style="fill:#FFD63F;"
|
||||
d="M188.66,59.461l-30.13,52.18c-6.67-1.76-13.54-1.69-20.03,0.12l-30.07-52.1
|
||||
C133.83,48.191,163.17,48.121,188.66,59.461z"/>
|
||||
<path style="fill:#FFD63F;"
|
||||
d="M164.79,139.491c2.47,4.29,3.13,9.27,1.85,14.05c-1.28,4.78-4.35,8.77-8.63,11.25
|
||||
c-4.28,2.47-9.27,3.12-14.05,1.85c-4.78-1.28-8.77-4.35-11.24-8.63c-2.48-4.29-3.13-9.27-1.85-14.05s4.34-8.77,8.62-11.25
|
||||
c2.86-1.64,6.02-2.48,9.23-2.48c1.61,0,3.23,0.21,4.83,0.63C158.32,132.141,162.32,135.211,164.79,139.491z"/>
|
||||
<path style="fill:#FFD63F;"
|
||||
d="M121.5,175.781l-30.13,52.19c-11.07-8.03-20.41-18.37-27.31-30.32
|
||||
c-6.9-11.96-11.19-25.21-12.6-38.81h60.26c0.86,3.14,2.12,6.2,3.8,9.1C117.19,170.841,119.21,173.461,121.5,175.781z"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
1
wwwroot/site.webmanifest
Normal file
@@ -0,0 +1 @@
|
||||
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
||||