Compare commits
76 Commits
edd91be047
...
1.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bb544e96c | ||
|
|
a104b43b24 | ||
|
|
8d5a63b262 | ||
| 14c885a60f | |||
| 422e89caee | |||
| d0df371a3c | |||
|
|
a1803a6f4a | ||
|
|
3fe1386415 | ||
| a306f0732c | |||
| 027ae4d130 | |||
|
|
2592137fa3 | ||
|
|
8279a81dc9 | ||
|
|
2faa9e740e | ||
|
|
a589977015 | ||
|
|
06e2fabe81 | ||
|
|
d107d68bcc | ||
|
|
472e69d3c0 | ||
| 1c61a4d202 | |||
| 40b0855ca5 | |||
| 124066da59 | |||
|
|
f3aceb69af | ||
|
|
a87d521a4f | ||
|
|
c5b71add07 | ||
|
|
881c9408b6 | ||
|
|
35f0fe3654 | ||
|
|
21b7b0a252 | ||
|
|
1c6f12c210 | ||
| 56f7c7d3a3 | |||
| c7ddb02ac1 | |||
| 63fbab34ce | |||
|
|
8fad5d7717 | ||
|
|
41a9c9d269 | ||
| dd1ec2c374 | |||
| 58589c56dd | |||
|
|
8dd2312aa0 | ||
|
|
5a56dfa051 | ||
| 3a5214ed45 | |||
| 72f0518f9d | |||
| ede464fb0d | |||
| 2082e0c7bc | |||
|
|
d1e4814593 | ||
|
|
530ea7da89 | ||
|
|
5903bafee5 | ||
| 8452841460 | |||
|
|
69b359d9a1 | ||
|
|
a626abe1c3 | ||
| 834d5e763e | |||
| dde27f9b31 | |||
| 0d5e68188d | |||
|
|
fc2d9c2bc9 | ||
| cb11d68fa7 | |||
|
|
07f431e2a3 | ||
| e85ffc66f8 | |||
|
|
cc8b5035fe | ||
|
|
83a640433a | ||
|
|
cee8ebecc5 | ||
|
|
f02f181058 | ||
|
|
4432acfea5 | ||
|
|
9d0149de75 | ||
|
|
e548dbb6c9 | ||
| 770d3bb012 | |||
|
|
3bf23daa7a | ||
|
|
6cbb4c8dad | ||
| b20ce6da06 | |||
| a68f35faf5 | |||
|
|
6262ce53aa | ||
|
|
6d50337e3b | ||
| c09b08a474 | |||
|
|
7f3f266d52 | ||
|
|
fd27ac9c69 | ||
|
|
5b0f69b7aa | ||
|
|
2d71dd0245 | ||
|
|
7a3dabc9aa | ||
|
|
aba685fb72 | ||
|
|
f80b0b1bf3 | ||
|
|
a0adeecb13 |
1
.gitignore
vendored
@@ -5,3 +5,4 @@ node_modules/
|
||||
.DS_Store
|
||||
.sourcemaps
|
||||
dist/
|
||||
package-lock.json
|
||||
27
README.md
@@ -1,27 +0,0 @@
|
||||
## Created with Capacitor Create App
|
||||
|
||||
This app was created using [`@capacitor/create-app`](https://github.com/ionic-team/create-capacitor-app),
|
||||
and comes with a very minimal shell for building an app.
|
||||
|
||||
### Running this example
|
||||
|
||||
To run the provided example, you can use `npm start` command.
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
### Background Color
|
||||
|
||||
In src/manifest.json, "#31d53d" refers to the green color which is visible in the background in the web version. This is not visible in the built version.
|
||||
|
||||
### Running iOS
|
||||
|
||||
https://capacitorjs.com/docs/ios#adding-the-ios-platform
|
||||
|
||||
npm install @capacitor/ios
|
||||
npx cap add ios
|
||||
npx cap open ios
|
||||
|
||||
To Rerun:
|
||||
npm run build && npx cap copy ios
|
||||
@@ -1,10 +1,13 @@
|
||||
{
|
||||
"appId": "so.blockcatcher.app",
|
||||
"appName": "Blockcatcher",
|
||||
"appId": "so.forum.app",
|
||||
"appName": "Forum",
|
||||
"webDir": "dist",
|
||||
"ios": {
|
||||
"allowsBackForwardNavigationGestures": true
|
||||
},
|
||||
"plugins": {
|
||||
"SplashScreen": {
|
||||
"launchAutoHide": false
|
||||
"launchAutoHide": true
|
||||
}
|
||||
}
|
||||
}
|
||||
158
doc.md
Normal file
@@ -0,0 +1,158 @@
|
||||
|
||||
Quill is a SwiftUI-style JavaScript framework. It makes use of components called Shadows, which are HTML Custom Elements.
|
||||
|
||||
### Getting Started:
|
||||
Take index.js and put it in your app. Typically as quill.js. Then import it in the head of the HTML.
|
||||
|
||||
### Basic Overview:
|
||||
|
||||
Quill uses components called Shadows. Each Shadow is a Custom HTML Element (https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements)
|
||||
```
|
||||
class Home extends Shadow {
|
||||
render() {
|
||||
}
|
||||
}
|
||||
|
||||
register(Home)
|
||||
```
|
||||
|
||||
Once created, it can be imported like
|
||||
```
|
||||
import "Home.js"
|
||||
```
|
||||
(Not how we are NOT importing the actual class object. If that happens, it will fail.)
|
||||
|
||||
Here is an example of Hello World:
|
||||
|
||||
```
|
||||
class Home extends Shadow {
|
||||
render() {
|
||||
p("Hello World")
|
||||
.x(50, vw)
|
||||
.y(50, vh)
|
||||
}
|
||||
}
|
||||
|
||||
register(Home)
|
||||
```
|
||||
|
||||
This will render a paragraph tag in the middle of the screen.
|
||||
|
||||
Here's what it will look like in HTML:
|
||||
|
||||
```
|
||||
<body>
|
||||
<home->
|
||||
<p style="position: absolute; top: 50vh; left: 50vw;">Hello World</p>
|
||||
</home->
|
||||
</body>
|
||||
```
|
||||
|
||||
Note: .x() and .y() are quill-specific functions that were created simply for nice syntax. However, this would also be valid:
|
||||
```
|
||||
p("Hello World")
|
||||
.top(50, vh)
|
||||
.left(50, vw)
|
||||
```
|
||||
|
||||
There are quill functions for every HTML style attribute. If they have units, they will follow the pattern directly above, where the first parameter is the amount and the second parameter is the unit.
|
||||
|
||||
### Real Basic Example:
|
||||
|
||||
First, you need your index.html. Here is one:
|
||||
|
||||
```
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="public">
|
||||
<head>
|
||||
<title>Parchment</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" href="/_/icons/quill.svg">
|
||||
<link rel="stylesheet" href="/_/code/shared.css">
|
||||
<script src="/_/code/quill.js"></script>
|
||||
<script type="module" src="75820185/index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
When starting, it is typical to make a "Home" shadow and import it in index.js. Here is an example:
|
||||
|
||||
index.js:
|
||||
```
|
||||
import "./Home.js"
|
||||
Home()
|
||||
```
|
||||
|
||||
Home.js:
|
||||
```
|
||||
import "../components/NavBar.js"
|
||||
import "./HomeContent.js"
|
||||
import "./Why.js"
|
||||
import "./Events.js"
|
||||
import "./Join.js"
|
||||
import "./SignIn.js"
|
||||
import "./Success.js"
|
||||
|
||||
class Home extends Shadow {
|
||||
render() {
|
||||
|
||||
ZStack(() => {
|
||||
|
||||
NavBar()
|
||||
|
||||
img("/_/icons/logo.svg", "2.5em")
|
||||
.onClick((done) => {
|
||||
if(!done) return
|
||||
window.navigateTo("/")
|
||||
})
|
||||
.position("absolute")
|
||||
.left(50, vw).top(4, em)
|
||||
.center()
|
||||
.transform(`translate(${window.isMobile() ? "-50%" : "-2em"}, -50%)`)
|
||||
|
||||
switch(window.location.pathname) {
|
||||
case "/":
|
||||
HomeContent()
|
||||
break;
|
||||
case "/why":
|
||||
Why()
|
||||
break;
|
||||
case "/events":
|
||||
Events()
|
||||
break;
|
||||
case "/join":
|
||||
Join()
|
||||
break;
|
||||
case "/success":
|
||||
Success()
|
||||
break;
|
||||
}
|
||||
|
||||
})
|
||||
.onNavigate(() => {
|
||||
this.rerender()
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
register(Home)
|
||||
|
||||
```
|
||||
|
||||
|
||||
Success.js:
|
||||
|
||||
```
|
||||
class Success extends Shadow {
|
||||
render() {
|
||||
p("Thanks for your purchase! You will receive a confirmation email shortly. <br><br> <b>Keep that email; it will be checked at the door.</b>")
|
||||
.x(50, vw).y(50, vh)
|
||||
.center()
|
||||
}
|
||||
}
|
||||
|
||||
register(Success)
|
||||
```
|
||||
@@ -18,6 +18,7 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
22352DD22F74F93C0052EF07 /* App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = App.entitlements; sourceTree = "<group>"; };
|
||||
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
|
||||
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
|
||||
504EC3041FED79650016851F /* App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = App.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -73,6 +74,7 @@
|
||||
504EC3061FED79650016851F /* App */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
22352DD22F74F93C0052EF07 /* App.entitlements */,
|
||||
50379B222058CBB4000EE86E /* capacitor.config.json */,
|
||||
504EC3071FED79650016851F /* AppDelegate.swift */,
|
||||
504EC30B1FED79650016851F /* Main.storyboard */,
|
||||
@@ -361,15 +363,16 @@
|
||||
baseConfigurationReference = FC68EB0AF532CFC21C3344DD /* Pods-App.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 53DK57C7ZF;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 1.0;
|
||||
MARKETING_VERSION = 1.0.6;
|
||||
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = so.hyperia.app;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = russell.sam.forum;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -382,14 +385,15 @@
|
||||
baseConfigurationReference = AF51FD2D460BCFE21FA515B2 /* Pods-App.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = App/App.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = 53DK57C7ZF;
|
||||
INFOPLIST_FILE = App/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = so.hyperia.app;
|
||||
MARKETING_VERSION = 1.0.6;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = russell.sam.forum;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
||||
78
ios/App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme
Normal file
@@ -0,0 +1,78 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1640"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
buildArchitectures = "Automatic">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||
BuildableName = "App.app"
|
||||
BlueprintName = "App"
|
||||
ReferencedContainer = "container:App.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||
BuildableName = "App.app"
|
||||
BlueprintName = "App"
|
||||
ReferencedContainer = "container:App.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "504EC3031FED79650016851F"
|
||||
BuildableName = "App.app"
|
||||
BlueprintName = "App"
|
||||
ReferencedContainer = "container:App.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
8
ios/App/App/App.entitlements
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -7,10 +7,38 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||||
self.enableInteractiveKeyboard()
|
||||
}
|
||||
// Override point for customization after application launch.
|
||||
return true
|
||||
}
|
||||
|
||||
func enableInteractiveKeyboard() {
|
||||
guard let window = UIApplication.shared.windows.first,
|
||||
let rootView = window.rootViewController?.view else {
|
||||
return
|
||||
}
|
||||
|
||||
// Find WKWebView recursively
|
||||
func findWebView(in view: UIView) -> WKWebView? {
|
||||
if let webView = view as? WKWebView {
|
||||
return webView
|
||||
}
|
||||
for subview in view.subviews {
|
||||
if let found = findWebView(in: subview) {
|
||||
return found
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if let webView = findWebView(in: rootView) {
|
||||
webView.scrollView.keyboardDismissMode = .interactive
|
||||
print("✅ Interactive keyboard enabled!")
|
||||
}
|
||||
}
|
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) {
|
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
|
||||
@@ -46,4 +74,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
||||
NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
|
||||
}
|
||||
|
||||
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
|
||||
NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 108 KiB |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "AppIcon-512@2x.png",
|
||||
"filename" : "Group 73 (6).png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "ios",
|
||||
"size" : "1024x1024"
|
||||
|
||||
BIN
ios/App/App/Assets.xcassets/AppIcon.appiconset/Group 73 (6).png
Normal file
|
After Width: | Height: | Size: 34 KiB |
@@ -1,23 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Group 74.png",
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732-2.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group 75.png",
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732-1.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Group 76.png",
|
||||
"idiom" : "universal",
|
||||
"filename" : "splash-2732x2732.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
BIN
ios/App/App/Assets.xcassets/Splash.imageset/Group 74.png
vendored
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
ios/App/App/Assets.xcassets/Splash.imageset/Group 75.png
vendored
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
ios/App/App/Assets.xcassets/Splash.imageset/Group 76.png
vendored
Normal file
|
After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 40 KiB |
|
Before Width: | Height: | Size: 40 KiB |
@@ -5,7 +5,7 @@
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>Hyperia</string>
|
||||
<string>Forum</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
@@ -22,6 +22,23 @@
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
||||
<string>Used to find keep local information relevant.</string>
|
||||
<key>NSLocationWhenInUseUsageDescription</key>
|
||||
<string>Used to find forums and communities near you</string>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Access your photos to set a profile picture and share with others</string>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
@@ -30,18 +47,15 @@
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UIRequiresFullScreen</key>
|
||||
<true/>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<true/>
|
||||
|
||||
@@ -12,8 +12,12 @@ def capacitor_pods
|
||||
pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
|
||||
pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
|
||||
pod 'CapacitorCamera', :path => '../../node_modules/@capacitor/camera'
|
||||
pod 'CapacitorFilesystem', :path => '../../node_modules/@capacitor/filesystem'
|
||||
pod 'CapacitorGeolocation', :path => '../../node_modules/@capacitor/geolocation'
|
||||
pod 'CapacitorGoogleMaps', :path => '../../node_modules/@capacitor/google-maps'
|
||||
pod 'CapacitorHaptics', :path => '../../node_modules/@capacitor/haptics'
|
||||
pod 'CapacitorPreferences', :path => '../../node_modules/@capacitor/preferences'
|
||||
pod 'CapacitorPushNotifications', :path => '../../node_modules/@capacitor/push-notifications'
|
||||
pod 'CapacitorSplashScreen', :path => '../../node_modules/@capacitor/splash-screen'
|
||||
end
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@ PODS:
|
||||
- CapacitorCamera (7.0.2):
|
||||
- Capacitor
|
||||
- CapacitorCordova (7.4.4)
|
||||
- CapacitorFilesystem (7.1.8):
|
||||
- Capacitor
|
||||
- IONFilesystemLib (~> 1.1.1)
|
||||
- CapacitorGeolocation (7.1.5):
|
||||
- Capacitor
|
||||
- IONGeolocationLib (= 1.0.1)
|
||||
@@ -11,6 +14,12 @@ PODS:
|
||||
- Capacitor
|
||||
- Google-Maps-iOS-Utils (~> 5.0)
|
||||
- GoogleMaps (~> 8.4)
|
||||
- CapacitorHaptics (7.0.3):
|
||||
- Capacitor
|
||||
- CapacitorPreferences (7.0.4):
|
||||
- Capacitor
|
||||
- CapacitorPushNotifications (7.0.6):
|
||||
- Capacitor
|
||||
- CapacitorSplashScreen (7.0.3):
|
||||
- Capacitor
|
||||
- Google-Maps-iOS-Utils (5.0.0):
|
||||
@@ -20,20 +29,26 @@ PODS:
|
||||
- GoogleMaps/Base (8.4.0)
|
||||
- GoogleMaps/Maps (8.4.0):
|
||||
- GoogleMaps/Base
|
||||
- IONFilesystemLib (1.1.2)
|
||||
- IONGeolocationLib (1.0.1)
|
||||
|
||||
DEPENDENCIES:
|
||||
- "Capacitor (from `../../node_modules/@capacitor/ios`)"
|
||||
- "CapacitorCamera (from `../../node_modules/@capacitor/camera`)"
|
||||
- "CapacitorCordova (from `../../node_modules/@capacitor/ios`)"
|
||||
- "CapacitorFilesystem (from `../../node_modules/@capacitor/filesystem`)"
|
||||
- "CapacitorGeolocation (from `../../node_modules/@capacitor/geolocation`)"
|
||||
- "CapacitorGoogleMaps (from `../../node_modules/@capacitor/google-maps`)"
|
||||
- "CapacitorHaptics (from `../../node_modules/@capacitor/haptics`)"
|
||||
- "CapacitorPreferences (from `../../node_modules/@capacitor/preferences`)"
|
||||
- "CapacitorPushNotifications (from `../../node_modules/@capacitor/push-notifications`)"
|
||||
- "CapacitorSplashScreen (from `../../node_modules/@capacitor/splash-screen`)"
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- Google-Maps-iOS-Utils
|
||||
- GoogleMaps
|
||||
- IONFilesystemLib
|
||||
- IONGeolocationLib
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
@@ -43,10 +58,18 @@ EXTERNAL SOURCES:
|
||||
:path: "../../node_modules/@capacitor/camera"
|
||||
CapacitorCordova:
|
||||
:path: "../../node_modules/@capacitor/ios"
|
||||
CapacitorFilesystem:
|
||||
:path: "../../node_modules/@capacitor/filesystem"
|
||||
CapacitorGeolocation:
|
||||
:path: "../../node_modules/@capacitor/geolocation"
|
||||
CapacitorGoogleMaps:
|
||||
:path: "../../node_modules/@capacitor/google-maps"
|
||||
CapacitorHaptics:
|
||||
:path: "../../node_modules/@capacitor/haptics"
|
||||
CapacitorPreferences:
|
||||
:path: "../../node_modules/@capacitor/preferences"
|
||||
CapacitorPushNotifications:
|
||||
:path: "../../node_modules/@capacitor/push-notifications"
|
||||
CapacitorSplashScreen:
|
||||
:path: "../../node_modules/@capacitor/splash-screen"
|
||||
|
||||
@@ -54,13 +77,18 @@ SPEC CHECKSUMS:
|
||||
Capacitor: 09d9ff8e9618e8c4b3cab2bbee34a17215dd2fef
|
||||
CapacitorCamera: 6e18d54c8ab30d7dc7b8cd93d96f9b4f57e9202a
|
||||
CapacitorCordova: bf648a636f3c153f652d312ae145fb508b6ffced
|
||||
CapacitorFilesystem: f54cd6b76be06fa7ceb219cf313d32e0d626ea87
|
||||
CapacitorGeolocation: b96474c3259dd4a294227ea8ec19140b1837cceb
|
||||
CapacitorGoogleMaps: 20b5445a532f80dbb120fa99941fd094bcc88af6
|
||||
CapacitorHaptics: d17da7dd984cae34111b3f097ccd3e21f9feec62
|
||||
CapacitorPreferences: d82a7e3b95fcab43a553268b803356522910d153
|
||||
CapacitorPushNotifications: c6158ba6f3777f281a675aa43e4011e9723e822b
|
||||
CapacitorSplashScreen: d06ae8804808e9f649a08e7bb7f283c77b688084
|
||||
Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321
|
||||
GoogleMaps: 8939898920281c649150e0af74aa291c60f2e77d
|
||||
IONFilesystemLib: 21a63377696b2d8fab5632ecfb7d2ac67bddb68a
|
||||
IONGeolocationLib: 20f9d0248a0b5264511fb57a37e25dd2badf797a
|
||||
|
||||
PODFILE CHECKSUM: 1f8c41a3cb5e4540693adb6a47064e328eec261d
|
||||
PODFILE CHECKSUM: 32ad5bbf56056f7ee8d159f9eae42fe03e911a61
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
|
||||
2275
package-lock.json
generated
14
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "capacitor-app",
|
||||
"version": "1.0.0",
|
||||
"name": "Forum",
|
||||
"version": "1.0.1",
|
||||
"description": "An Amazing Capacitor App",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
@@ -13,12 +13,16 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@capacitor/camera": "latest",
|
||||
"@capacitor/core": "latest",
|
||||
"@capacitor/camera": "^7.0.2",
|
||||
"@capacitor/core": "^7.4.4",
|
||||
"@capacitor/filesystem": "^7.1.8",
|
||||
"@capacitor/geolocation": "^7.1.5",
|
||||
"@capacitor/google-maps": "^7.2.0",
|
||||
"@capacitor/haptics": "^7.0.3",
|
||||
"@capacitor/ios": "^7.4.4",
|
||||
"@capacitor/splash-screen": "latest"
|
||||
"@capacitor/preferences": "^7.0.4",
|
||||
"@capacitor/push-notifications": "^7.0.6",
|
||||
"@capacitor/splash-screen": "^7.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@capacitor/cli": "latest",
|
||||
|
||||
64
readme.md
Normal file
@@ -0,0 +1,64 @@
|
||||
## Run in Browser
|
||||
|
||||
```npm run start```
|
||||
|
||||
### Browser: Dev Frontend and Dev Backend (localhost)
|
||||
This option should be at the top level of capacitor.config.json
|
||||
"server": {
|
||||
"url": "http://sam.local:5173",
|
||||
"cleartext": true
|
||||
},
|
||||
|
||||
### Browser: Prod Frontend and Prod Backend
|
||||
Run:
|
||||
vite build
|
||||
npx serve dist
|
||||
|
||||
If you need to login again:
|
||||
run localStorage.clear() in the browser dev tools console and then refresh the page.
|
||||
|
||||
## Run On Device
|
||||
https://capacitorjs.com/docs/ios#adding-the-ios-platform
|
||||
|
||||
One-Time Install:
|
||||
npm install @capacitor/ios
|
||||
npx cap add ios
|
||||
|
||||
To Open XCode:
|
||||
npx cap open ios
|
||||
|
||||
Run this command to rebuild for iOS
|
||||
npm run build && npx cap copy ios
|
||||
|
||||
If getting black screen:
|
||||
npx cap sync iOS
|
||||
|
||||
### iOS: Dev Frontend and Dev Backend (localhost)
|
||||
This option should be at the top level of capacitor.config.json
|
||||
"server": {
|
||||
"url": "http://sam.local:5173",
|
||||
"cleartext": true
|
||||
},
|
||||
|
||||
### iOS: Dev Frontend with Prod Backend (frm.so)
|
||||
Add "https://frm.so" to VITE_API_URL in .env.development
|
||||
|
||||
### iOS: Prod Frontend and Prod Backend (frm.so)
|
||||
Remove the "server" object from capacitor.config.
|
||||
|
||||
### Various Commands
|
||||
npx cap config - this will list the full configuration currently being used
|
||||
|
||||
### Architecture
|
||||
|
||||
In Development, API routes are routed using the vite.config.js.
|
||||
|
||||
### Notes
|
||||
|
||||
Background Color:
|
||||
In src/manifest.json, "#31d53d" refers to the green color which is visible in the background in the web version. This is not visible in the built version.
|
||||
|
||||
Test Push Notifications:
|
||||
https://icloud.developer.apple.com/dashboard/notifications/teams/53DK57C7ZF/app/russell.sam.forum/notifications/create?notificationId=8bb87cf2-9590-4a63-b7e1-e4c7f2a2c879&environment=DEVELOPMENT¬ificationType=push
|
||||
|
||||
Note: Even if built in "production" mode, the tokens will still be considered "development" by Apple until the app is actually deployed
|
||||
1
src/.env.development
Normal file
@@ -0,0 +1 @@
|
||||
VITE_API_URL=http://localhost:10002
|
||||
1
src/.env.production
Normal file
@@ -0,0 +1 @@
|
||||
VITE_API_URL=https://frm.so
|
||||
1186
src/_/code/quill.js
114
src/_/code/shared.css
Normal file
@@ -0,0 +1,114 @@
|
||||
:root {
|
||||
--main: #FFE9C8;
|
||||
--accent: #570b0b;
|
||||
--lightaccent: #760f0f;
|
||||
--darkaccent: #dfc9ac;
|
||||
--text: #340000;
|
||||
--yellow: #f1f3c3;
|
||||
--bone: #fff2e7;
|
||||
--gold: #FEBA7D;
|
||||
--divider: #bb7c36;
|
||||
--green: #0857265c;
|
||||
--red: #ff0000;
|
||||
--quillred: #DE3F3F;
|
||||
--darkred: #6b2c1d;
|
||||
--brown: #812A18;
|
||||
|
||||
--sidebar: #698b6f;
|
||||
--divider: #523636;
|
||||
--lightDivider: #52363681;
|
||||
--darkbrown: #3f0808;
|
||||
--darkgrey: #5c4646;
|
||||
|
||||
--headertext: #433c36e2;
|
||||
--searchbackground: #ffeed8;
|
||||
--loginButton: var(--main);
|
||||
--loginBackground: #d96b6b;
|
||||
|
||||
--home-src: /_/icons/home.svg;
|
||||
--home-selected-src: /_/icons/homelightselected.svg;
|
||||
--people-src: /_/icons/people.svg;
|
||||
--people-selected-src: /_/icons/peoplelightselected.svg;
|
||||
--settings-src: /_/icons/settings.svg;
|
||||
--settings-selected-src: /_/icons/settingslightselected.svg;
|
||||
--events-src: /_/icons/events.svg;
|
||||
--events-selected-src: /_/icons/eventslightselected.svg;
|
||||
--jobs-src: /_/icons/jobs.svg;
|
||||
--jobs-selected-src: /_/icons/jobslightselected.svg;
|
||||
|
||||
--column-src: /_/icons/column2.svg;
|
||||
--nodes-src: /_/icons/nodes.svg;
|
||||
--forum-src: /_/icons/forum.svg;
|
||||
--trash-src: /_/icons/trash.svg;
|
||||
|
||||
--pin-src: /_/icons/pin.svg;
|
||||
--time-src: /_/icons/time.svg;
|
||||
|
||||
--top-inset: env(safe-area-inset-top, 0px);
|
||||
--bottom-inset: env(safe-area-inset-bottom, 0px);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--main: #2A150E;
|
||||
--lightaccent: #69413a;
|
||||
--accent: #3D2622;
|
||||
--darkaccent: #240609;
|
||||
--text: #FADFB6;
|
||||
|
||||
--sidebar: #240609;
|
||||
--divider: #523636;
|
||||
--lightDivider: #52363680;
|
||||
--darktext: #62473E;
|
||||
--headertext: #ffd8bb;
|
||||
--darkred: #6b2c1d;
|
||||
--searchbackground: #260F0C;
|
||||
--loginButton: var(--darkaccent);
|
||||
--loginBackground: var(--accent);
|
||||
|
||||
|
||||
--home-src: /_/icons/homelight.svg;
|
||||
--home-selected-src: /_/icons/homelightselected.svg;
|
||||
--people-src: /_/icons/peoplelight.svg;
|
||||
--people-selected-src: /_/icons/peoplelightselected.svg;
|
||||
--settings-src: /_/icons/settingslight.svg;
|
||||
--settings-selected-src: /_/icons/settingslightselected.svg;
|
||||
--events-src: /_/icons/eventslight.svg;
|
||||
--events-selected-src: /_/icons/eventslightselected.svg;
|
||||
--jobs-src: /_/icons/jobslight.svg;
|
||||
--jobs-selected-src: /_/icons/jobslightselected.svg;
|
||||
|
||||
--column-src: /_/icons/column2.svg;
|
||||
--nodes-src: /_/icons/nodes.svg;
|
||||
--forum-src: /_/icons/forum.svg;
|
||||
--trash-src: /_/icons/trash.svg;
|
||||
|
||||
--pin-src: /_/icons/pinlight.svg;
|
||||
--time-src: /_/icons/timelight.svg;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
outline: none;
|
||||
caret-color: var(--text); /* hide real caret */
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
font-family: Arial;
|
||||
color: #5C504D;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-family: Arial;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--main);
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
:root {
|
||||
--main: #AEBDFF;
|
||||
--accent: #60320c;
|
||||
--text: #340000;
|
||||
--yellow: #f1f3c3;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 99 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100px" height="100px"><path d="M 17 21 A 1.0001 1.0001 0 0 0 16 22 L 16 32 A 1.0001 1.0001 0 0 0 17 33 L 83 33 A 1.0001 1.0001 0 0 0 84 32 L 84 22 A 1.0001 1.0001 0 0 0 83 21 L 17 21 z M 18 23 L 82 23 L 82 31 L 18 31 L 18 29 L 73.5 29 A 0.50005 0.50005 0 1 0 73.5 28 L 18 28 L 18 23 z M 76.5 28 A 0.50005 0.50005 0 1 0 76.5 29 L 78.5 29 A 0.50005 0.50005 0 1 0 78.5 28 L 76.5 28 z M 17 44 A 1.0001 1.0001 0 0 0 16 45 L 16 55 A 1.0001 1.0001 0 0 0 17 56 L 83 56 A 1.0001 1.0001 0 0 0 84 55 L 84 45 A 1.0001 1.0001 0 0 0 83 44 L 17 44 z M 18 46 L 82 46 L 82 54 L 18 54 L 18 46 z M 22.5 51 A 0.50005 0.50005 0 1 0 22.5 52 L 67.5 52 A 0.50005 0.50005 0 1 0 67.5 51 L 22.5 51 z M 70.5 51 A 0.50005 0.50005 0 1 0 70.5 52 L 73.5 52 A 0.50005 0.50005 0 1 0 73.5 51 L 70.5 51 z M 76.5 51 A 0.50005 0.50005 0 1 0 76.5 52 L 78.5 52 A 0.50005 0.50005 0 1 0 78.5 51 L 76.5 51 z M 17 67 A 1.0001 1.0001 0 0 0 16 68 L 16 78 A 1.0001 1.0001 0 0 0 17 79 L 83 79 A 1.0001 1.0001 0 0 0 84 78 L 84 68 A 1.0001 1.0001 0 0 0 83 67 L 17 67 z M 18 69 L 82 69 L 82 74 L 26.5 74 A 0.50005 0.50005 0 1 0 26.5 75 L 82 75 L 82 77 L 18 77 L 18 69 z M 21.5 74 A 0.50005 0.50005 0 1 0 21.5 75 L 23.5 75 A 0.50005 0.50005 0 1 0 23.5 74 L 21.5 74 z"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg height="800px" width="800px" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 511.697 511.697" xml:space="preserve">
|
||||
<g transform="translate(0 1)">
|
||||
<g>
|
||||
<path style="fill:#FFE100;" d="M505.189,119.472L505.189,119.472c-7.81-7.81-13.885-9.546-21.695-1.736l-45.125,45.993
|
||||
c-6.075,6.075-14.753,6.075-20.827,0.868l-63.349-59.01c-4.339-4.339-10.414-6.942-16.488-6.942h-94.59l-79.837,75.498
|
||||
c-7.81,7.81-9.546,21.695-1.736,30.373c8.678,9.546,22.563,8.678,31.241,0l59.01-62.481h43.39L147.656,306.916H62.612
|
||||
c-13.885,0-26.902,10.414-27.769,24.298c-0.868,15.62,11.281,27.77,26.034,27.77H165.88c10.414,0,19.959-4.339,27.77-12.149
|
||||
l57.275-61.614l61.614,65.085L296.05,456.177c-2.603,12.149,2.603,25.166,13.885,30.373c15.62,6.942,32.108-1.736,36.447-17.356
|
||||
l25.166-135.376c0.868-6.075-0.868-11.281-5.207-15.62l-71.159-72.027l69.424-69.424l45.993,45.993
|
||||
c7.81,7.81,21.695,7.81,29.505,0l19.959-19.959l45.125-52.068C513.867,142.035,513.867,128.15,505.189,119.472"/>
|
||||
<path style="fill:#FFE100;" d="M462.667,118.605l-0.868-0.868c-7.81-7.81-1.736-7.81-10.414,0l-34.712,45.993
|
||||
c-6.075,6.075-14.753,6.075-20.827,0.868l-73.763-59.01c-4.339-4.339-4.339-6.942-10.414-6.942h-68.556l-79.837,75.498
|
||||
c-7.81,7.81-9.546,21.695-1.736,30.373c8.678,9.546,4.339,8.678,12.149,0l60.746-62.481h34.712L121.623,306.916h-59.01
|
||||
c-13.885,0-26.902,10.414-27.769,24.298c-0.868,15.62,11.281,27.77,26.034,27.77h95.458l69.424-72.895l60.746,64.217
|
||||
l-16.488,105.871c-2.603,12.149,2.603,25.166,13.885,30.373c15.62,6.942,16.488-1.736,19.959-17.356l20.827-144.922
|
||||
l-55.539-78.102l63.349-69.424l40.786,45.993c7.81,7.81,18.224-3.471,26.034-11.281l8.678-8.678l54.671-54.671
|
||||
C470.477,140.299,470.477,126.415,462.667,118.605"/>
|
||||
</g>
|
||||
<g>
|
||||
<path style="fill:#FFA800;" d="M323.819,324.272l-20.827,144.922c-2.603,11.281-3.471,19.092-10.414,19.959
|
||||
c12.149,0.868,23.431-7.81,26.034-19.959l27.77-144.922l-77.234-77.234L323.819,324.272z"/>
|
||||
<path style="fill:#FFA800;" d="M487.833,118.605l-0.868-0.868c-7.81-7.81-19.092-7.81-27.77-1.736
|
||||
c0.868,0.868,0.868,0.868,1.736,1.736l0.868,0.868c7.81,7.81,7.81,20.827,0,29.505l-54.671,54.671l-8.678,8.678
|
||||
c-4.339,4.339-8.678,9.546-13.885,12.149c7.81,6.942,20.827,6.942,28.637-0.868l19.959-19.959l54.671-54.671
|
||||
C495.643,140.299,495.643,127.282,487.833,118.605"/>
|
||||
</g>
|
||||
<g>
|
||||
<path style="fill:#FFFFFF;" d="M163.277,207.12c-0.868-0.868-1.736-1.736-2.603-2.603c-7.81-8.678-6.942-21.695,1.736-30.373
|
||||
l80.705-75.498H217.08l-79.837,75.498c-7.81,7.81-9.546,21.695-1.736,30.373S155.467,213.194,163.277,207.12"/>
|
||||
<path style="fill:#FFFFFF;" d="M34.843,331.215c0.868-13.885,13.017-24.298,26.902-24.298H35.711
|
||||
c-13.885,0-26.902,10.414-27.769,24.298c0,15.62,12.149,27.77,26.902,27.77h26.034C46.124,358.984,33.975,346.835,34.843,331.215"
|
||||
/>
|
||||
</g>
|
||||
<path style="fill:#FFE100;" d="M425.351,63.933c0-24.298-19.092-43.39-43.39-43.39c-0.868,0-26.034,19.092-26.034,43.39
|
||||
c0,0.868,1.736,43.39,26.034,43.39C406.26,107.323,425.351,88.232,425.351,63.933"/>
|
||||
<g>
|
||||
<path style="fill:#FFA800;" d="M399.318,20.543c-2.603,0-6.075,0-8.678,0.868c19.959,4.339,34.712,21.695,34.712,42.522
|
||||
s-14.753,38.183-34.712,42.522c2.603,0.868,6.075,0.868,8.678,0.868c24.298,0,43.39-19.092,43.39-43.39
|
||||
S423.616,20.543,399.318,20.543"/>
|
||||
<path style="fill:#FFA800;" d="M356.795,71.743c0,0.868,0,0.868,0,1.736C356.795,72.611,356.795,71.743,356.795,71.743"/>
|
||||
</g>
|
||||
<path d="M295.182,497.832c-5.207,0-9.546-0.868-14.753-3.471c-14.753-6.942-23.431-23.431-19.092-40.786l15.62-100.664
|
||||
l-52.068-54.671l-62.481,66.82c-1.736,1.736-3.471,2.603-6.075,2.603H34.843c-9.546,0-18.224-4.339-25.166-10.414
|
||||
c-6.942-6.942-10.414-16.488-9.546-26.034c0.868-18.224,16.488-32.976,36.447-32.976h81.573l32.108-35.58
|
||||
c3.471-3.471,8.678-3.471,12.149-0.868c3.471,3.471,3.471,8.678,0.868,12.149l-34.712,39.051c-2.603,1.736-4.339,2.603-6.942,2.603
|
||||
H36.579c-10.414,0-19.092,6.942-19.092,16.488c0,5.207,1.736,9.546,4.339,13.017c3.471,3.471,7.81,5.207,13.017,5.207h118.02
|
||||
l65.953-70.292c1.736-1.736,4.339-2.603,6.075-2.603c2.603,0,4.339,0.868,6.075,2.603l61.614,64.217
|
||||
c1.736,1.736,2.603,4.339,2.603,6.942l-16.488,105.871c-1.736,9.546,1.736,18.224,9.546,21.695c5.207,2.603,10.414,1.736,14.753,0
|
||||
c4.339-2.603,7.81-6.942,9.546-11.281l26.034-139.715l-74.63-74.631c-2.603-2.603-3.471-4.339-3.471-6.942
|
||||
c0-2.603,0.868-4.339,2.603-6.075l69.424-69.424c3.471-3.471,8.678-3.471,12.149,0l45.993,45.993
|
||||
c4.339,4.339,12.149,4.339,17.356,0l74.63-74.631c4.339-4.339,4.339-12.149,0-16.488l-0.868-0.868
|
||||
c-5.207-5.207-13.017-5.207-17.356,0l-45.125,45.993c-8.678,8.678-23.431,9.546-32.976,0.868l-63.349-59.01
|
||||
c-2.603-2.603-6.942-4.339-10.414-4.339h-91.986l-77.234,73.763c-5.207,5.207-5.207,13.017-0.868,18.224
|
||||
c2.603,2.603,6.075,4.339,9.546,4.339l0,0c3.471,0,6.942-1.736,8.678-4.339l59.01-62.481c1.736-1.736,4.339-2.603,6.075-2.603
|
||||
h43.39c3.471,0,6.942,1.736,7.81,5.207s0.868,6.942-1.736,9.546l-69.424,78.102c-3.471,3.471-8.678,4.339-12.149,0.868
|
||||
c-3.471-3.471-3.471-8.678-0.868-12.149l56.407-63.349h-19.959l-56.407,59.878c-5.207,6.075-13.017,9.546-21.695,9.546l0,0
|
||||
c-8.678,0-16.488-3.471-21.695-9.546c-10.414-11.281-9.546-30.373,1.736-42.522l79.837-76.366c1.736-3.471,3.471-4.339,6.075-4.339
|
||||
h94.59c8.678,0,16.488,3.471,22.563,8.678l63.349,59.01c2.603,2.603,6.075,2.603,8.678,0l45.125-45.993
|
||||
c11.281-11.281,30.373-11.281,42.522,0l0.868,0.868c11.281,11.281,11.281,30.373,0,41.654l-74.63,74.631
|
||||
c-11.281,11.281-30.373,11.281-41.654,0l-39.919-39.919l-57.275,57.275l72.027,72.027c1.736,1.736,2.603,5.207,2.603,7.81
|
||||
L329.026,470.93c-2.603,10.414-9.546,19.092-18.224,23.431C305.595,496.964,300.389,497.832,295.182,497.832z"/>
|
||||
<path d="M187.575,241.832c0-5.207-3.471-8.678-8.678-8.678s-8.678,3.471-8.678,8.678s3.471,8.678,8.678,8.678
|
||||
S187.575,247.038,187.575,241.832"/>
|
||||
<path d="M399.318,116.001c-28.637,0-52.068-23.431-52.068-52.068s23.431-52.068,52.068-52.068
|
||||
c28.637,0,52.068,23.431,52.068,52.068S427.955,116.001,399.318,116.001z M399.318,29.221c-19.092,0-34.712,15.62-34.712,34.712
|
||||
s15.62,34.712,34.712,34.712c19.092,0,34.712-15.62,34.712-34.712S418.409,29.221,399.318,29.221z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 12 KiB |
@@ -1,12 +0,0 @@
|
||||
html,
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
}
|
||||
118
src/index.html
@@ -2,28 +2,114 @@
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Blockcatcher</title>
|
||||
<title>Forum</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
content="viewport-fit=auto, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
|
||||
/>
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="msapplication-tap-highlight" content="no" />
|
||||
|
||||
<script
|
||||
type="module"
|
||||
src="https://unpkg.com/@ionic/pwa-elements@latest/dist/ionicpwaelements/ionicpwaelements.esm.js"
|
||||
></script>
|
||||
<script
|
||||
nomodule
|
||||
src="https://unpkg.com/@ionic/pwa-elements@latest/dist/ionicpwaelements/ionicpwaelements.js"
|
||||
></script>
|
||||
|
||||
<link rel="icon" type="image/x-icon" href="./_/icons/runner.svg" />
|
||||
<link rel="manifest" href="./manifest.json" />
|
||||
<link rel="stylesheet" href="./_/code/styles.css" />
|
||||
<script src="./_/code/quill.js"></script>
|
||||
<script type="module" src="./index.js"></script>
|
||||
<link rel="stylesheet" href="./_/code/shared.css" />
|
||||
<script type="module">
|
||||
await import('./util.js')
|
||||
|
||||
function appendScript(src, isModule = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const s = document.createElement('script')
|
||||
s.src = src
|
||||
s.crossOrigin = "anonymous"
|
||||
if (isModule) s.type = 'module'
|
||||
s.onload = resolve
|
||||
s.onerror = reject
|
||||
document.head.appendChild(s)
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
await appendScript(window.util.HOST + '/_/code/quill.js')
|
||||
await appendScript(window.util.HOST + '/83947261/index.js', true)
|
||||
} catch (e) {
|
||||
document.body.innerHTML = `
|
||||
<style>
|
||||
#ptr-screen {
|
||||
position: fixed; inset: 0;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center;
|
||||
font-family: sans-serif; text-align: center;
|
||||
padding: 2rem; touch-action: none;
|
||||
transition: transform 0.2s ease;
|
||||
color: var(--text);
|
||||
}
|
||||
#ptr-icon {
|
||||
font-size: 2rem; margin-bottom: 1rem;
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
opacity: 0.4;
|
||||
}
|
||||
#ptr-label {
|
||||
font-size: 0.9rem; opacity: 0.5;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
#ptr-indicator {
|
||||
color: var(--text);
|
||||
position: fixed; top: 5vh; left: 0; right: 0;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
padding-top: env(safe-area-inset-top);
|
||||
height: 0; overflow: hidden;
|
||||
transition: height 0.1s ease;
|
||||
font-size: 0.8rem; opacity: 0.6; gap: 0.4rem;
|
||||
}
|
||||
@keyframes spin { to { transform: rotate(360deg) } }
|
||||
.spinning { animation: spin 0.6s linear infinite }
|
||||
</style>
|
||||
<div id="ptr-indicator">
|
||||
<span id="ptr-arrow">↓</span>
|
||||
<span id="ptr-hint">Pull to retry</span>
|
||||
</div>
|
||||
<div id="ptr-screen">
|
||||
<div id="ptr-icon">⚠️</div>
|
||||
<p style="margin:0;font-size:1.1rem;font-weight:600">No connection</p>
|
||||
<p id="ptr-label">Could not reach the server.<br>Pull down to try again.</p>
|
||||
</div>
|
||||
`
|
||||
|
||||
const THRESHOLD = 90
|
||||
let startY = 0, dragging = false
|
||||
|
||||
document.addEventListener('touchstart', e => {
|
||||
startY = e.touches[0].clientY
|
||||
dragging = true
|
||||
})
|
||||
|
||||
document.addEventListener('touchmove', e => {
|
||||
if (!dragging) return
|
||||
const dy = Math.max(0, e.touches[0].clientY - startY)
|
||||
const pull = Math.min(dy, THRESHOLD * 1.5)
|
||||
const progress = Math.min(pull / THRESHOLD, 1)
|
||||
|
||||
document.getElementById('ptr-screen').style.transform = `translateY(${pull * 0.4}px)`
|
||||
document.getElementById('ptr-indicator').style.height = (pull * 0.6) + 'px'
|
||||
document.getElementById('ptr-arrow').style.transform = `rotate(${progress * 180}deg)`
|
||||
document.getElementById('ptr-hint').textContent = progress >= 1 ? 'Release to retry' : 'Pull to retry'
|
||||
document.getElementById('ptr-icon').style.opacity = 0.4 + progress * 0.6
|
||||
})
|
||||
|
||||
document.addEventListener('touchend', e => {
|
||||
if (!dragging) return
|
||||
dragging = false
|
||||
const dy = e.changedTouches[0].clientY - startY
|
||||
if (dy >= THRESHOLD) {
|
||||
document.getElementById('ptr-arrow').textContent = '↻'
|
||||
document.getElementById('ptr-arrow').classList.add('spinning')
|
||||
document.getElementById('ptr-hint').textContent = 'Retrying…'
|
||||
setTimeout(() => location.reload(), 400)
|
||||
} else {
|
||||
document.getElementById('ptr-screen').style.transform = ''
|
||||
document.getElementById('ptr-indicator').style.height = '0'
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<meta name="theme-color" content="#31d53d" />
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
import "./js/Home.js"
|
||||
Home()
|
||||
document.body.style.backgroundColor = "var(--main)"
|
||||
197
src/js/Home.js
@@ -1,197 +0,0 @@
|
||||
class Home extends Shadow {
|
||||
|
||||
tracking = false
|
||||
logs = []
|
||||
timer = null
|
||||
|
||||
async startTracking() {
|
||||
if (!navigator.geolocation) {
|
||||
alert("Geolocation is not supported by your browser.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.tracking = true
|
||||
|
||||
navigator.geolocation.requestPermission?.() || Promise.resolve('granted');
|
||||
|
||||
const permission = await new Promise((resolve) => {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
() => resolve('granted'),
|
||||
() => resolve('denied')
|
||||
);
|
||||
});
|
||||
|
||||
if (permission === 'denied') {
|
||||
alert("Location permission required");
|
||||
this.tracking = false
|
||||
return;
|
||||
}
|
||||
|
||||
const timer = setInterval(async () => {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
async (pos) => {
|
||||
const { latitude, longitude } = pos.coords;
|
||||
const now = new Date();
|
||||
const log = `${now.toISOString()} — (${latitude}, ${longitude})`;
|
||||
const timestamp = this.formatCentralTime(now);
|
||||
|
||||
this.logs = [log, ...this.logs]
|
||||
|
||||
this.updateLogs()
|
||||
await this.sendLocation(latitude, longitude, timestamp);
|
||||
},
|
||||
(err) => console.error("Location error:", err),
|
||||
{ enableHighAccuracy: true }
|
||||
);
|
||||
}, 1000);
|
||||
|
||||
this.timer = timer
|
||||
}
|
||||
|
||||
stopTracking() {
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
this.tracking = false;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
ZStack(() => {
|
||||
// Title bar
|
||||
HStack(() => {
|
||||
img("./_/icons/runner.svg", "2em", "2em")
|
||||
p("San Marcos, TX")
|
||||
.fontSize(1.2, em)
|
||||
img("./_/icons/hamburger.svg", "2em", "2em")
|
||||
})
|
||||
.gap(15, vw)
|
||||
.position("fixed")
|
||||
.top(0)
|
||||
.left(0)
|
||||
.width(100, vw)
|
||||
.paddingTop(2, em)
|
||||
.paddingBottom(2, em)
|
||||
.borderBottom("0.1rem solid var(--text)")
|
||||
.backgroundColor("var(--yellow)")
|
||||
.fontWeight("bold")
|
||||
.display("flex")
|
||||
.alignItems("center")
|
||||
.justifyContent("center")
|
||||
.zIndex(10)
|
||||
|
||||
VStack(() => {
|
||||
button(() => {
|
||||
if(this.tracking) {
|
||||
Rectangle("48%", "48%")
|
||||
.fill("#264B61")
|
||||
.stroke("0.2em", "black")
|
||||
} else {
|
||||
Triangle("58%", "58%")
|
||||
.fill("#9F292B")
|
||||
.stroke("0.2em", "black")
|
||||
}
|
||||
})
|
||||
.attr({"id": "playButton"})
|
||||
.width(120, px)
|
||||
.height(120, px)
|
||||
.x(50, vw).y(50, vh)
|
||||
.center()
|
||||
.borderRadius(50, "%")
|
||||
.backgroundColor(this.tracking ? "#CD593E" : "#A6EABD")
|
||||
.border("0.2em solid black")
|
||||
.cursor("pointer")
|
||||
.display("flex")
|
||||
.alignItems("center")
|
||||
.justifyContent("center")
|
||||
.onTap(() => {
|
||||
console.log("tapped")
|
||||
if (this.tracking) {
|
||||
this.stopTracking();
|
||||
this.rerender()
|
||||
} else {
|
||||
this.startTracking();
|
||||
this.rerender()
|
||||
}
|
||||
})
|
||||
|
||||
VStack(() => {
|
||||
this.logs.map(log =>
|
||||
div(log)
|
||||
.paddingHorizontal("8px")
|
||||
.paddingVertical("12px")
|
||||
.backgroundColor("rgba(255,255,255,0.9)")
|
||||
.borderRadius(6, px)
|
||||
.marginBottom(6, px)
|
||||
.fontSize(0.9, rem)
|
||||
.color("#222")
|
||||
.fontFamily("monospace")
|
||||
)
|
||||
})
|
||||
.attr({"id": "logList"})
|
||||
.flex(1)
|
||||
.overflowY("auto")
|
||||
.paddingHorizontal(16, px)
|
||||
})
|
||||
.marginTop(7, em)
|
||||
})
|
||||
.overflowX("hidden")
|
||||
.width(100, vw)
|
||||
.height(100, vh)
|
||||
.display("block")
|
||||
.margin(0)
|
||||
.color("var(--text)")
|
||||
.fontFamily("Arial")
|
||||
}
|
||||
|
||||
showTracking() {
|
||||
this.$("#playButton").rerender()
|
||||
this.$("#playButton").style.backgroundColor = this.tracking ? "#CD593E" : "#A6EABD"
|
||||
}
|
||||
|
||||
updateLogs() {
|
||||
let list = this.$("#logList")
|
||||
list.rerender()
|
||||
list.attr({"id": "logList"})
|
||||
}
|
||||
|
||||
formatCentralTime(date) {
|
||||
return new Intl.DateTimeFormat('en-US', {
|
||||
timeZone: 'America/Chicago',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
year: '2-digit',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: true
|
||||
})
|
||||
.format(date)
|
||||
.replace(/,/, '') // "04/05/25, 2:30:00 PM" → "04/05/25 2:30:00 PM"
|
||||
.replace(/\//g, '.') // → "04.05.25 2:30:00 PM"
|
||||
.toLowerCase()
|
||||
.replace(' pm', 'pm')
|
||||
.replace(' am', 'am');
|
||||
}
|
||||
|
||||
async sendLocation(lat, lon, timestamp) {
|
||||
try {
|
||||
const resp = await fetch('http://localhost:3008/api/location', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
name: "Freddy Krueger",
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
timestamp
|
||||
})
|
||||
});
|
||||
if (!resp.ok) throw new Error(resp.status);
|
||||
console.log('Location sent');
|
||||
} catch (e) {
|
||||
console.error('Failed to send location:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
register(Home)
|
||||
@@ -4,9 +4,9 @@
|
||||
"start_url": "index.html",
|
||||
"display": "standalone",
|
||||
"icons": [{
|
||||
"src": "_/imgs/logo.png",
|
||||
"src": "_/icons/logo.svg",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
"type": "image/svg"
|
||||
}],
|
||||
"background_color": "#31d53d",
|
||||
"theme_color": "#31d53d"
|
||||
|
||||
53
src/util.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import { PushNotifications } from '@capacitor/push-notifications';
|
||||
import { Preferences } from '@capacitor/preferences';
|
||||
import { Filesystem, Directory } from '@capacitor/filesystem';
|
||||
import { Haptics, ImpactStyle } from '@capacitor/haptics';
|
||||
import { Camera, CameraResultType, CameraSource } from '@capacitor/camera';
|
||||
import { Geolocation } from '@capacitor/geolocation';
|
||||
import { SplashScreen } from '@capacitor/splash-screen';
|
||||
|
||||
window.capacitor = {
|
||||
Preferences,
|
||||
PushNotifications,
|
||||
Filesystem,
|
||||
Directory,
|
||||
Haptics,
|
||||
ImpactStyle,
|
||||
Camera,
|
||||
CameraResultType,
|
||||
CameraSource,
|
||||
Geolocation,
|
||||
SplashScreen,
|
||||
}
|
||||
|
||||
const env = import.meta.env
|
||||
|
||||
window.util = class util {
|
||||
|
||||
static HOST = env.VITE_API_URL
|
||||
static PushNotifications = PushNotifications
|
||||
static Preferences = Preferences
|
||||
|
||||
static async authFetch(url, options = {}) {
|
||||
const { value: token } = await Preferences.get({ key: 'auth_token' });
|
||||
|
||||
return fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
...options.headers,
|
||||
'Authorization': `Bearer ${token}`,
|
||||
'X-Client': 'mobile'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static async removeAuthToken() {
|
||||
await Preferences.remove({ key: 'auth_token'})
|
||||
}
|
||||
|
||||
static cssVariable(value) {
|
||||
return getComputedStyle(document.documentElement)
|
||||
.getPropertyValue("--" + value)
|
||||
.trim();
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,45 @@ export default defineConfig({
|
||||
outDir: '../dist',
|
||||
minify: false,
|
||||
emptyOutDir: true,
|
||||
sourcemap: true,
|
||||
target: 'esnext' // modern version of browsers, allows top-level await
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
"/ws": {
|
||||
target: "http://localhost:10002",
|
||||
changeOrigin: true,
|
||||
ws: true
|
||||
},
|
||||
"/profile/upload-image": {
|
||||
target: "http://localhost:10002",
|
||||
changeOrigin: true
|
||||
},
|
||||
"/api": {
|
||||
target: "http://localhost:10002",
|
||||
changeOrigin: true
|
||||
},
|
||||
"/db": {
|
||||
target: "http://localhost:10002",
|
||||
changeOrigin: true
|
||||
},
|
||||
"/apps": {
|
||||
target: "http://localhost:10002",
|
||||
changeOrigin: true
|
||||
},
|
||||
"/auth": {
|
||||
target: "http://localhost:10002",
|
||||
changeOrigin: true
|
||||
},
|
||||
"/@server": {
|
||||
target: "http://localhost:10002",
|
||||
changeOrigin: true
|
||||
}
|
||||
},
|
||||
host: true,
|
||||
allowedHosts: ['sam.local'],
|
||||
},
|
||||
esbuild: {
|
||||
keepNames: true
|
||||
}
|
||||
});
|
||||
|
||||