diff --git a/client/src/app.tsx b/client/src/app.tsx index 127a391..667362a 100644 --- a/client/src/app.tsx +++ b/client/src/app.tsx @@ -325,8 +325,8 @@ function Card({ interface InkProps { alpha?: THREE.Texture; color: THREE.Color; - emissive: THREE.Color; - specular: THREE.Color; + emissive?: THREE.Color; + specular?: THREE.Color; side?: THREE.Side; normal?: THREE.Texture; shininess?: number; @@ -532,11 +532,9 @@ function LegendCard({ rotation, ...props }: GroupProps) { {createPortal(, scene.current)} - - {mask && } + />} { const size = Number(r.headers.get('Content-Length')); if (size < 5_000) console.error(`Invalid static image on token #${i}`); expect(size).toBeGreaterThan(5_000); - expect(r.headers.get('Content-Type')).toBe('image/webp'); expect(r.status).toBe(200); return r.text() }) @@ -74,7 +73,6 @@ describe(`${canister}`, () => { const size = Number(r.headers.get('Content-Length')); if (size < 5_000) console.error(`Invalid animated image on token #${i}`); expect(size).toBeGreaterThan(5_000); - expect(r.headers.get('Content-Type')).toBe('image/webp'); expect(r.status).toBe(200); return r.text() }) diff --git a/src/Assets/Assets.test.mo b/src/Assets/Assets.test.mo index 9ddc100..65cfb98 100644 --- a/src/Assets/Assets.test.mo +++ b/src/Assets/Assets.test.mo @@ -28,6 +28,7 @@ let params : Types.Params = { createAsset("asset3", ["preview", "tag0", "tag1", "tag3"]), ]; colors = []; + stockColors = []; _Admins = Admins.Admins({ admins = [admin] }); }; let a = Assets.Assets(params); diff --git a/src/Assets/lib.mo b/src/Assets/lib.mo index 3ea5070..6b202fe 100644 --- a/src/Assets/lib.mo +++ b/src/Assets/lib.mo @@ -120,6 +120,9 @@ module { // TODO: Use token traits instead. private var colors : [Types.Color] = state.colors; + // Colors for legends card stock. + private var stockColors : [Types.Color] = state.stockColors; + public func restore (backup : Types.State) : () { for (asset in backup.assets.vals()) { _putAsset(asset); @@ -131,6 +134,7 @@ module { return { assets = assets.toArray(); colors; + stockColors; }; }; @@ -162,6 +166,11 @@ module { colors; }; + // Get all stock colors. + public func getStockColors () : [Types.Color] { + stockColors; + }; + //////////////// // Admin API // @@ -306,6 +315,15 @@ module { colors := newColors; }; + // Configure stock colors. + public func configureStockColors ( + caller : Principal, + newColors : [Types.Color], + ) : () { + assert state._Admins._isAdmin(caller); + stockColors := newColors; + }; + }; }; \ No newline at end of file diff --git a/src/Assets/types.mo b/src/Assets/types.mo index 0579e92..7ccbeab 100644 --- a/src/Assets/types.mo +++ b/src/Assets/types.mo @@ -12,19 +12,14 @@ module Assets { public type State = { assets : [Record]; colors : [Color]; + stockColors : [Color]; }; public type Dependencies = { _Admins : Admins.Admins; }; - // TODO: This after upgrading DFX - // public type Params = State and Dependencies; - public type Params = { - assets : [Record]; - colors : [Color]; - _Admins : Admins.Admins; - }; + public type Params = State and Dependencies; public type Asset = { contentType : Text; @@ -49,6 +44,8 @@ module Assets { back : Tag; border : Tag; ink : Tag; + mask : Tag; + stock : Tag; nri : { back : Float; border : Float; @@ -68,7 +65,7 @@ module Assets { emissive : Text; background : Text; }; - stock : { + stockColors: { base : Text; specular : Text; emissive : Text; diff --git a/src/Http/lib.mo b/src/Http/lib.mo index f7bc01a..4721200 100644 --- a/src/Http/lib.mo +++ b/src/Http/lib.mo @@ -166,7 +166,7 @@ module { index : Nat, ) : AssetTypes.LegendManifest { let tokenId = Ext.TokenIdentifier.encode(state.cid, Nat32.fromNat(index)); - let { back; border; ink; mask; normal; } = state._Tokens.nfts(?index)[0]; + let { back; border; ink; mask; normal; stock; } = state._Tokens.nfts(?index)[0]; let nriBack = switch (Array.find<(Text, Float)>(nri, func ((a, b)) { a == "back-" # back })) { case (?(_, i)) i; case _ 0.0; @@ -183,6 +183,8 @@ module { back; border; ink; + mask; + stock; nri = { back = nriBack; border = nriBorder; @@ -236,12 +238,15 @@ module { }; map; }; - stock = do { + stockColors = do { var map = { base = "#000000"; specular = "#000000"; emissive = "#000000"; }; + for (color in state._Assets.getStockColors().vals()) { + if (color.name == stock) map := color; + }; map; }; views = { @@ -282,6 +287,8 @@ module { "\t\"back\" : \"" # manifest.back # "\",\n" # "\t\"border\" : \"" # manifest.border # "\",\n" # "\t\"ink\" : \"" # manifest.ink # "\",\n" # + "\t\"mask\" : \"" # manifest.mask # "\",\n" # + "\t\"stock\" : \"" # manifest.stock # "\",\n" # "\t\"nri\" : {\n" # "\t\t\"back\" : " # Float.toText(manifest.nri.back) # ",\n" # "\t\t\"border\" : " # Float.toText(manifest.nri.border) # ",\n" # @@ -318,9 +325,9 @@ module { "\t\t\"background\" : \"" # manifest.colors.background # "\"\n" # "\t},\n" # "\t\"stock\": {\n" # - "\t\t\"base\" : \"" # manifest.stock.base # "\",\n" # - "\t\t\"specular\" : \"" # manifest.stock.specular # "\",\n" # - "\t\t\"emissive\" : \"" # manifest.stock.emissive # "\"\n" # + "\t\t\"base\" : \"" # manifest.stockColors.base # "\",\n" # + "\t\t\"specular\" : \"" # manifest.stockColors.specular # "\",\n" # + "\t\t\"emissive\" : \"" # manifest.stockColors.emissive # "\"\n" # "\t},\n" # "\t\"views\": {\n" # "\t\t\"flat\" : \"" # manifest.views.flat # "\",\n" # @@ -457,7 +464,8 @@ module { let legend = state._Tokens._getMetadata(i); renderAssetWithTags([ "preview", "side-by-side", "back-" # legend.back, - "border-" # legend.border, "ink-" # legend.ink + "border-" # legend.border, "ink-" # legend.ink, + "mask-" # legend.mask, "stock-" # legend.stock ]); }; }; @@ -484,7 +492,8 @@ module { let legend = state._Tokens._getMetadata(i); renderAssetWithTags([ "preview", "animated", "back-" # legend.back, - "border-" # legend.border, "ink-" # legend.ink + "border-" # legend.border, "ink-" # legend.ink, + "mask-" # legend.mask, "stock-" # legend.stock ]); }; }; @@ -543,7 +552,8 @@ module { if (Text.contains(request.url, #text("type=animated"))) { return renderAssetWithTags([ "preview", "animated", "back-" # legend.back, - "border-" # legend.border, "ink-" # legend.ink + "border-" # legend.border, "ink-" # legend.ink, + "mask-" # legend.mask, "stock-" # legend.stock ]); }; if (not Text.contains(request.url, #text("type=thumbnail"))) { @@ -551,7 +561,8 @@ module { }; renderAssetWithTags([ "preview", "side-by-side", "back-" # legend.back, - "border-" # legend.border, "ink-" # legend.ink + "border-" # legend.border, "ink-" # legend.ink, + "mask-" # legend.mask, "stock-" # legend.stock ]); }; @@ -565,7 +576,8 @@ module { let legend = state._Tokens._getMetadata(i); renderAssetWithTags([ "preview", "side-by-side", "back-" # legend.back, - "border-" # legend.border, "ink-" # legend.ink + "border-" # legend.border, "ink-" # legend.ink, + "mask-" # legend.mask, "stock-" # legend.stock ]); }; case _ http404(?"No token at that index."); @@ -618,12 +630,14 @@ module { } else if (Text.map(tokens[1], Prim.charToLower) == "webm") { return renderAssetWithTags([ "preview", "animated", "back-" # legend.back, - "border-" # legend.border, "ink-" # legend.ink + "border-" # legend.border, "ink-" # legend.ink, + "mask-" # legend.mask, "stock-" # legend.stock ]); } else if (Text.map(tokens[1], Prim.charToLower) == "webp") { return renderAssetWithTags([ "preview", "side-by-side", "back-" # legend.back, - "border-" # legend.border, "ink-" # legend.ink + "border-" # legend.border, "ink-" # legend.ink, + "mask-" # legend.mask, "stock-" # legend.stock ]); } else if (Text.map(tokens[1], Prim.charToLower) == "json") { return { diff --git a/src/main.mo b/src/main.mo index 1fa1aa3..d040bcf 100644 --- a/src/main.mo +++ b/src/main.mo @@ -67,6 +67,7 @@ shared ({ caller = creator }) actor class LegendsNFT( private stable var stableAssets : [AssetTypes.Record] = []; private stable var stableColors : [AssetTypes.Color] = []; + private stable var stableStockColors : [AssetTypes.Color] = []; // Admins @@ -111,9 +112,10 @@ shared ({ caller = creator }) actor class LegendsNFT( system func preupgrade() { // Preserve assets - let { colors; assets } = _Assets.backup(); + let { colors; assets; stockColors; } = _Assets.backup(); stableAssets := assets; stableColors := colors; + stableStockColors := stockColors; // Preserve admins stableAdmins := _Admins.toStable(); @@ -187,18 +189,18 @@ shared ({ caller = creator }) actor class LegendsNFT( ////////////// - system func heartbeat() : async () { - if (not s_heartbeatOn) return; + // system func heartbeat() : async () { + // if (not s_heartbeatOn) return; - // Limit heartbeats - let now = Time.now(); - if (now - s_heartbeatLastBeat < s_heartbeatIntervalSeconds * 1_000_000_000) return; - s_heartbeatLastBeat := now; + // // Limit heartbeats + // let now = Time.now(); + // if (now - s_heartbeatLastBeat < s_heartbeatIntervalSeconds * 1_000_000_000) return; + // s_heartbeatLastBeat := now; - // Run jobs - await _Entrepot.cronDisbursements(); - await _Entrepot.cronSettlements(); - }; + // // Run jobs + // await _Entrepot.cronDisbursements(); + // await _Entrepot.cronSettlements(); + // }; public shared ({ caller }) func heartbeatSetInterval ( i : Nat @@ -367,6 +369,7 @@ shared ({ caller = creator }) actor class LegendsNFT( _Admins; assets = stableAssets; colors = stableColors; + stockColors = stableStockColors; }); public shared ({ caller }) func upload ( @@ -436,6 +439,13 @@ shared ({ caller = creator }) actor class LegendsNFT( _Assets.configureColors(caller, colors); }; + public shared ({ caller }) func configureStockColors ( + colors : [AssetTypes.Color], + ) : async () { + _captureMetrics(); + _Assets.configureStockColors(caller, colors); + }; + ///////////// // Tokens // diff --git a/zsh/configure.zsh b/zsh/configure.zsh index 1f17d64..0c1eadd 100755 --- a/zsh/configure.zsh +++ b/zsh/configure.zsh @@ -35,9 +35,11 @@ payload="$payload})" dfx canister --network $network call $canister configureMetadata $payload + # Initialize CAP dfx canister --network $network call $canister init + # Configure colors colors="./config/colors/$confname.csv" [ ! -f $colors ] && { echo "$colors file not found"; exit 99; } @@ -57,41 +59,22 @@ payload="$payload})" dfx canister --network $network call $canister configureColors $payload -# Configure price - -config="./config/canisters/$confname.json" -[ ! -f $config ] && { echo "$config file not found"; exit 99; } -read -r -d$'\1' price_private price_public <<< $(jq -r '.private_sale_price_e8s, .public_sale_price_e8s' $config) - -# dfx canister --network $network call $canister configurePublicSalePrice "( $price_private : nat64, $price_public : nat64 )" - -# Configure NRI -if [[ $canister != "0-the-fool" ]] -then - echo "No NRI data yet" - exit -fi +# Configure stocks +colors="./config/stocks/$confname.csv" +[ ! -f $colors ] && { echo "$colors file not found"; exit 99; } +OLDIFS=$IFS +IFS=',' +payload="(vec {" +{ + read # skip headers + while read name base specular emissive + do + if [[ $name == "" ]] continue # skip empty lines + payload="$payload record { name = \"$name\"; base = \"$base\"; specular = \"$specular\"; emissive = \"$emissive\"; background = \"#000000\"; };" + done +} < $colors +IFS=$OLDIFS +payload="$payload})" -dfx canister --network $network call $canister configureNri\ - "(vec {\ - record {\"back-fate\"; 0.0000};\ - record {\"back-bordered-saxon\"; 0.5283};\ - record {\"back-worn-saxon\"; 0.9434};\ - record {\"back-saxon\"; 1.0000};\ - record {\"border-thin\"; 0.0000};\ - record {\"border-bare\"; 0.0000};\ - record {\"border-round\"; 0.4615};\ - record {\"border-staggered\"; 0.4615};\ - record {\"border-thicc\"; 0.9231};\ - record {\"border-greek\"; 0.9231};\ - record {\"border-worn-saxon\"; 0.7692};\ - record {\"border-saxon\"; 1.0000};\ - record {\"ink-copper\"; 0.0000};\ - record {\"ink-silver\"; 0.3333};\ - record {\"ink-gold\"; 0.5833};\ - record {\"ink-canopy\"; 0.8056};\ - record {\"ink-rose\"; 0.8611};\ - record {\"ink-spice\"; 0.9444};\ - record {\"ink-midnight\"; 1.0000};\ - })" \ No newline at end of file +dfx canister --network $network call $canister configureStockColors "$payload"